What is the default build configuration of cmake - c++

In this answer, it says Debug is the default cmake build configuration.
But I have a different observation:
I have following in my CMakeLists.txt to choose debug and release versions of a lib according to the current build configuration.
target_link_libraries(MyApp debug Widgets_d)
target_link_libraries(MyApp optimized Widgets)
It seems that when I invoke cmake without sepcifying -DCMAKE_BUILD_TYPE flag, Widgets is used instead of Widgets_d (When I delete Widgets and try to build, make complains that lib is not there). So that means by default the build configuration is optimized, not debug.
So what actually is the default build configuration? If it is debug, what could be wrong with my CMakelists.txt?

target_link_libraries with optimized keyword corresponds to all configurations, which are not debug.
Try adding message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") to your CMakeLists.txt to see the actual build type (I suppose it should be empty).

If depends on whether you are using a single-configuration generator (Makefiles) or a multi-configuration generator (Visual Studio, XCode).
The link cited in the question is about a multi-configuration generator. When using a multi-configuration generator, the configuration variable CMAKE_BUILD_TYPE is ignored. To select the configuration to build, cmake allows the switch --config, and this defaults to Debug. So
cmake --build .
in a multi-configuration project builds a Debug version.
However, when using a single-configuration generator, the switch --config is ignored. Only the configuration variable CMAKE_BUILD_TYPE is used to determine the build type, and this defaults to Release.
More background info on single- and multiconfiguration-generators in this answer.

Related

How to determine current build type of visual studio in CMakeList.txt

This is my build command in CMD:
cmake --build . --config Debug
This Debug can sometimes be Release, or sometimes it is the default. And I have a code in my CMakeList.txt:
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_link_libraries(${PROJECT_NAME} PRIVATE LLUd wstp64i4)
else()
target_link_libraries(${PROJECT_NAME} PRIVATE LLU wstp64i4)
endif()
I think its grammar is fine. But it is a great pity that Visual Studio(multi-config generators) does not recognize the CMAKE_BUILD_TYPE variable as the document. How should I change it?
I have found a similar topic here, but it seem don't work for me.
This is all you should need:
find_package(LLU REQUIRED PATH_SUFFIXES LLU)
target_link_libraries(MyTarget PRIVATE LLU::LLU)
If the above isn't working, you should ask about that error, not your attempted workaround.
The code you show is broken on several levels. First, the value of CMAKE_BUILD_TYPE should never be used to check the active build type because it is not set when using a multi-config generator like Visual Studio. Every in-project use of CMAKE_BUILD_TYPE is a code smell. It is meant to be set by the person building your project (maybe you, maybe not) as a cache variable from the outside.
Second, what you are actually trying to do is to pick a different physical (i.e. on disk) library for Debug mode versus Release (and other *Rel*) mode(s). But this is handled by CMake already. You shouldn't have to do what you're attempting.
I'm assuming that LLU is the Wolfram LibraryLink Utilities. If so, you should read the documentation which shows very nearly the same code I gave above. Notice that LLU::LLU is an imported target. Unless Wolfram's LLU package is broken, this will handle per-config library selection automatically. If it is broken, you should complain to the developers, loudly.
The moral of the story is, as always, to link to imported targets. If what you're linking to doesn't have :: in its name, you should be wary.
Here's a little background on why this is the case:
Imported targets that are generated by CMake's package export mechanism have the following properties set on them. These properties control CMake's view of which physical libraries should be used in which build types:
IMPORTED_LOCATION_<CONFIG> - This property names the path to the physical library that is to be used in the given configuration.
IMPORTED_CONFIGURATIONS - This property contains a list of the configurations that have been imported for the given target.
MAP_IMPORTED_CONFIG_<CONFIG> - This is a per-config property that maps <CONFIG>, which should not be present in IMPORTED_CONFIGURATIONS, to a second config that is present in IMPORTED_CONFIGURATIONS. The physical library from the second configuration will be used.
Regarding point (3), some packages forget to map MinSizeRel and RelWithDebInfo to Release. If you are getting an error in these configs (but not in Release) you can add the following code to your project before importing any packages:
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release)
set(CMAKE_MAP_IMPORTED_CONFIG_MINSIZEREL Release)
This happens with LLVM's broken CMake packages. Most of the time, though, you don't have to worry about any of this.

Generate preprocessor definitions based on CMAKE_CONFIGURATION_TYPES

I want to generate a Visual Studio project with two configurations using cmake. I want cmake to define different preprocessor symbols for these configurations.
I generate the project with the following command
cmake -B intermediate/cmake -G "Visual Studio 16 2019" -T v142 -DCMAKE_GENERATOR_PLATFORM=x64
In my CMakeLists.txt I define configurations:
if(CMAKE_CONFIGURATION_TYPES)
set(CMAKE_CONFIGURATION_TYPES Debug Release)
endif()
Now, how do I define the preprocessor definitions per configuration? The quick search advises against using if(CMAKE_BUILD_TYPE STREQUAL "Release") because it doesn't work for multiconfiguration generators.
The conventional way to handle configuration-specific details in a multi-configuration generator is through the use of generator expressions.
Generator expressions allow you to specify symbols, values, flags, etc that will only be expanded at generation time based on the current state of the generator (such as the current build configuration).
For example, you can define custom pre-processor definitions with the -D flag with target_compile_definitions:
target_compile_definitions(MyTarget PRIVATE
$<$<CONFIG:Debug>:DEBUG_ONLY=1>
$<$<CONFIG:Release>:RELEASE_ONLY=2>
FOO=3
)
(This example is for PRIVATE definitions. Replace this with PUBLIC or INTERFACE as needed.)
This adds -DDEBUG_ONLY=1 to MyTarget for Debug builds, -DRELEASE_ONLY=2 for Release builds, and -DFOO=3 for all builds.
Also see this relevant/similar question: Cmake: Specifiy config specific settings for multi-config cmake project

Installation directory in CMakeLists.txt, suitable for Visual Studio and Qt Creator

I have to deal with CMake 3.x, Qt Creator 3.3.0, Qt 4.8.6, Visual Studio 2008 in Windows (and rarely Qt Creator + GCC in Debian).
This instruction
install(TARGETS ${PROJECT} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
is not comfortable because of mixing debug and release *.lib files in the same directory. I'd like to save libs in the corresponding subfolder.
I've tried the following instruction from here:
install(TARGETS ${PROJECT} DESTINATION
${CMAKE_INSTALL_PREFIX}/lib/\${BUILD_TYPE})
It works fine for Visual Studio, as it is a multi-configuration solution and we pass ${BUILD_TYPE}, protected by backslash '\' for further propagation.
But how can I achieve the same output for Qt Creator + MS C++ compiler? Should I assign Debug(for example) to ${CMAKE_BUILD_TYPE} (via command-line interface) and special custom flag, which tells CMake that we deal with nmake/make? I mean conditional install instruction which will work fine in Windows and Linux and require minimal differences in the command-line arguments for CMake. I don't want to reinvent the wheel if there is a standard solution.
You saw that you can use BUILD_TYPE variable set at compile time to configure the target folder of your library at installation. This is specific to Visual Studio.
In other build systems (make, nmake, ninja, etc.) you have to use CMAKE_BUILD_TYPE variable, set at configuration time to retrieve the same information. In such case, as you felt, different configurations (Debug and Release) have to be generated in separated build folders. In these folders, CMake generation step is done with the right value in CMAKE_BUILD_TYPE variable. Example:
cd /home/user/project/xx_project/build_release
cmake -DCMAKE_BUILD_TYPE=Release /home/user/project/xx_project/src
cd /home/user/project/xx_project/build_debug
cmake -DCMAKE_BUILD_TYPE=Debug /home/user/project/xx_project/src
To detect if the user is building from Visual Studio or from command line, "there is a variable for that": The MSVC_IDE Cmake variable
A solution can be something like
if(MSVC_IDE)
install(TARGETS ${PROJECT} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/\${BUILD_TYPE})
else()
install(TARGETS ${PROJECT} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_BUILD_TYPE})
endif()
I am not completely sure of the necessity of the backslash before ${CMAKE_BUILD_TYPE}. You should test that by yourself

How to change the executable output directory for Win32 builds, in CMake?

My problem is as such :
I'm developing a small parser using Visual Studio 2010.
I use CMake as a build configuration tool.
But I find the default executable building behaviour, inconvenient.
What I want is, have my final program be located in :
E:/parsec/bin/<exe-name>.<build-type>.exe
rather than
E:/parsec/bin/<build-type>/<exe-name>.exe
How would you do that using CMake ?
There are several options:
Copy the executable after building
Customizing the output-directory for your executable(s)
Copy the executable after building
After a succesful build you can copy the executable (see Beginners answer), but perhaps it is nicer to use an install target:
Use the install command to specify targets (executables, libraries, headers, etc.) which will be copied to the CMAKE_INSTALL_PREFIX directory. You can specify the CMAKE_INSTALL_PREFIX on the commandline of cmake (or in the cmake GUI).
Customizing the output-directory for your executable(s)
Warning: It is not advised to set absolute paths directly in your cmakelists.txt.
Use set_target_properties to customize the RUNTIME_OUTPUT_DIRECTORY
set_target_properties( yourexe PROPERTIES RUNTIME_OUTPUT_DIRECTORY E:/parsec/bin/ )
As an alternative, modifying the CMAKE_RUNTIME_OUTPUT_DIRECTORY allows you to specify this for all targets in the cmake project. Take care that you modify the CMAKE_LIBRARY_OUTPUT_DIRECTORY as well when you build dlls.
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
Additional info: Take a look at these questions:
In CMake, how do I work around the Debug and Release directories Visual Studio 2010 tries to add?
CMake : Changing name of Visual Studio and Xcode exectuables depending on configuration in a project generated by CMake
How to not add Release or Debug to output path?
Most probably you will need to copy your binaries with a separate custom command which would look similar to this one:
add_custom_command(target your_target_name
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${EXAMPLE_BIN_NAME} ${PROJECT_BINARY_DIR}/.
)

Debug vs Release in CMake

In a GCC compiled project,
How do I run CMake for each target type (debug/release)?
How do I specify debug and release C/C++ flags using CMake?
How do I express that the main executable will be compiled with g++ and one nested library with gcc?
With CMake, it's generally recommended to do an "out of source" build. Create your CMakeLists.txt in the root of your project. Then from the root of your project:
mkdir Release
cd Release
cmake -DCMAKE_BUILD_TYPE=Release ..
make
And for Debug (again from the root of your project):
mkdir Debug
cd Debug
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
Release / Debug will add the appropriate flags for your compiler. There are also RelWithDebInfo and MinSizeRel build configurations.
You can modify/add to the flags by specifying a toolchain file in which you can add CMAKE_<LANG>_FLAGS_<CONFIG>_INIT variables, e.g.:
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-Wall")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Wall")
See CMAKE_BUILD_TYPE for more details.
As for your third question, I'm not sure what you are asking exactly. CMake should automatically detect and use the compiler appropriate for your different source files.
A lot of the answers here are out of date/bad. So I'm going to attempt to answer it better. Granted I'm answering this question in 2020, so it's expected things would change.
How do I run CMake for each target type (debug/release)?
First off Debug/Release are called configurations in cmake (nitpick).
If you are using a single configuration generator (Ninja/Unix-Makefiles) you must specify the CMAKE_BUILD_TYPE.
Like this:
# Configure the build
cmake -S . -B build/ -D CMAKE_BUILD_TYPE=Debug
# Actually build the binaries
cmake --build build/
# Configure a release build
cmake -S . -B build/ -D CMAKE_BUILD_TYPE=Release
# Build release binaries
cmake --build build/
For multi-configuration generators it's slightly different (Ninja Multi-Config, Visual Studio)
# Configure the build
cmake -S . -B build
# Build debug binaries
cmake --build build --config Debug
# Build release binaries
cmake --build build --config Release
If you are wondering why this is necessary it's because cmake isn't a build system. It's a meta-build system (IE a build system that build's build systems). This is basically the result of handling build systems that support multiple-configurations in 1 build. If you'd like a deeper understanding I'd suggest reading a bit about cmake in Craig Scott's book "Professional CMake: A Practical Guide
How do I specify debug and release C/C++ flags using CMake?
The modern practice is to use target's and properties.
Here is an example:
add_library(foobar)
# Add this compile definition for debug builds, this same logic works for
# target_compile_options, target_link_options, etc.
target_compile_definitions(foobar PRIVATE
$<$<CONFIG:Debug>:
FOOBAR_DEBUG=1
>
)
NOTE: How I'm using generator expressions to specify the configuration!
Using CMAKE_BUILD_TYPE will result in bad builds for any multi-configuration generator!
Further more sometimes you need to set things globally and not just for one target.
Use add_compile_definitions, add_compile_options, etc. Those functions support generator expressions. Don't use old style cmake unless you have to (that path is a land of nightmares)
How do I express that the main executable will be compiled with g++ and one nested library with gcc?
Your last question really doesn't make sense.
For debug/release flags, see the CMAKE_BUILD_TYPE variable (you pass it as cmake -DCMAKE_BUILD_TYPE=value). It takes values like Release, Debug, etc.
https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/Useful-Variables#compilers-and-tools
cmake uses the extension to choose the compiler, so just name your files .c.
You can override this with various settings:
For example:
set_source_files_properties(yourfile.c LANGUAGE CXX)
Would compile .c files with g++. The link above also shows how to select a specific compiler for C/C++.
Instead of manipulating the CMAKE_CXX_FLAGS strings directly (which could be done more nicely using string(APPEND CMAKE_CXX_FLAGS_DEBUG " -g3") btw), you can use add_compile_options:
add_compile_options(
"-Wall" "-Wpedantic" "-Wextra" "-fexceptions"
"$<$<CONFIG:DEBUG>:-O0;-g3;-ggdb>"
)
This would add the specified warnings to all build types, but only the given debugging flags to the DEBUG build. Note that compile options are stored as a CMake list, which is just a string separating its elements by semicolons ;.
// CMakeLists.txt : release
set(CMAKE_CONFIGURATION_TYPES "Release" CACHE STRING "" FORCE)
// CMakeLists.txt : debug
set(CMAKE_CONFIGURATION_TYPES "Debug" CACHE STRING "" FORCE)
If you want to build a different configuration without regenerating if using you can also run cmake --build {$PWD} --config <cfg> For multi-configuration tools, choose <cfg> ex. Debug, Release, MinSizeRel, RelWithDebInfo
https://cmake.org/cmake/help/v2.8.11/cmake.html#opt%3a--builddir