Get ride of `Release` on build path output

How do I make CMake force MSVC to place the binary produced by the build in the “build” directory?

I ask because for all platforms (Linux, macOS & WebAssembly) the final binary is located in build , but only on Windows it’s in build\Release\myproject.exe.

So I would like to know how to remove the “Release” from the equation.

Thank you.

I’m not at my Windows computer but does this work?

set_property(TARGET myproject PROPERTY RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})

From the docs it should work.
https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.html

1 Like

Just a quick warning about doing this: the reason it gets put into a “Release” subdirectory, is because MSVC has multiple build configurations. At bare minimum, you also have a Debug configuration. If you force the output binary into the main build directory, then the debug and release configurations will overwrite each other when you switch between configurations.

MSVC, Ninja Multi-Config, and XCode, are multi-config generators, and the rest are single configuration:
https://cmake.org/cmake/help/latest/prop_gbl/GENERATOR_IS_MULTI_CONFIG.html

This is done because MSVC, & XCode have multiple configurations by default. This difference is annoying, and I wish that the CMake team would make all generators work the same way (i.e., make them all multi-config). For now, though, this is how it works.

Right one might instead do

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR})

and so on. Still have to have your comments in mind.

I wish that the CMake team would make all generators work the same way (i.e., make them all multi-config).

I am trying to discern why you feel that the default should be multi-config? Currently, I use Ninja single config on both Linux [to generate makefile] as well as Windows (on Visual Studio IDE) [to generate .sln and .vcxproj files] and this allows me to query and correctly use CMAKE_BUILD_TYPE to conditionally set flow in my CML.txt based on whether it is a Debug build or a Release build. From my understanding, CMAKE_BUILD_TYPE is valid only in single config model.

I made a query in trying to understand this better over at /r/cmake

https://www.reddit.com/r/cmake/comments/17qdvdj/usage_of_cmake_build_type_vs_generator_expression/

If you have time, could you please elaborate here why Multi config is better (?) than Single Config? While I understand natively Visual Studio IDE is MultiConfig, I a currently able to still use Visual Studio IDE and cmake using Ninja single config generator. How would the workflow be better if everything were multiconfig?

Multi-config allows you to build both debug and release (and other configs) side by side without needing to reconfigure.

The closest you can get with single configuration generators, is to manually create separate debug and release build directories, and run the configuration step twice; once in each. This works, but is more tedious. It’s also slower, because every time reconfiguration needs to be done, it has to be done for every configuration (at least, the configurations that you are building regularly).

Making everything single-config would be better than what we have now. However, I do think that it’s easier to switch from single-config to multi rather than the other way round.

1 Like

MSVC is the compiler; Visual Studio is the generator.

The install trees get muddied as usually only Debug (typically) has different artifact names than other configurations.

Not sure what you mean by this.

The best argument for single-config, is that it’s easier to understand if/else statements rather than generator expressions. So much so, that I wish that the multi-config generators could process the if/else statements related to debug/release/etc.

Debug libraries tend to be named libfood.dll while all other configs tend to use libfoo.dll. One can set a suffix for every config, but this is rarely done. On install, these will either overlap or embed the config into a directory name somewhere else.

I agree that there’s a lot that is simpler.

Given that the content of the branches can be arbitrary, that sounds…difficult. I’m sure the case you’re thinking of are fine, but I don’t know how to restrict things to what is sensible.

Ah, okay.

Yes, I think that would be difficult. The easiest way to get the results 100% correct would be brute force: execute the cmake scripts separately for each configuration, and update the multi-configuration generators to read variables on a per-config basis.

That still doesn’t work. What do we do if a project has:

if (CMAKE_BUILD_TYPE STREQUAL "Release")
  add_library(foo STATIC source1_fast.c)
else ()
  add_library(foo SHARED source1_reliable.c)
endif ()

or other dark magic? How about:

if (CMAKE_BUILD_TYPE STREQUAL "Release")
  set(val 1)
else ()
  set(val 2)
endif ()
configure_file(
  config.h.in # uses `val`
  config.h)

Projects that want to support Multi-Config need to consider this when writing their CMake code.

I don’t see an issue with add_library(). If you’re literally executing the build script once per config, then all the output for each config should be passed to the generator. This includes per-config target/file lists, attributes, etc. Visual Studio projects routinely have static and shared configs, and I doubt that any of the other multi-config targets would have a problem with it.

You’re right that the configure_file() code is potentially problematic. If config.h gets saved in the config’s build sub-directory, then everything would work just fine. If a script adds/modifies files directly in the source tree, then obviously you cannot have multiple build configs side-by-side at all. I sometimes have multiple build directories side by side with single-config generators. Each have their own config (e.g., debug, release, or even cross-compiling to different targets). I’d have some very confusing trouble if I tried that with a project that modifies the source tree directly.