Is there a workaround that I can use so that I can test the build type when using CMake in combination with Visual Studio and multiple configurations? - cmake

I would like to work with 'Debug', 'Release', 'Debug_Unicode' and 'Release_Unicode'
I have been able to use the DEBUG_CONFIGURATIONS variable so that the 'Debug Unicode' configuration correctly gets used as debug
This is what I tried to do in the CmakeLists.txt file:
target_link_libraries(tests
optimized ${CMAKE_BINARY_DIR}/src/${CMAKE_BUILD_TYPE}/foo.lib
debug ${CMAKE_BINARY_DIR}/src/${CMAKE_BUILD_TYPE}/foo.lib
)
Clearly CMake is able to make a choice between debug and release at this point, as it has to choose the 'optimized' or 'debug' library.
However, CMAKE_BUILD_TYPE is an empty string.
The best that I have been able to come up with is to work with a separate solution file for each of the configurations,
passing in CMAKE_BUILD_TYPE myself:
cmake -G Visual Studio 11 2012 Win64 -DCMAKE_BUILD_TYPE=Debug_Unicode C:\foo

As Antonio was mentioning
target_link_libraries(tests foo)
or just
add_dependencies(tests foo)
would be sufficient to link the correct library from the same configuration.
If you want to do more advanced stuff, take a look at the generator expressions. They are configuration sensitive incl. in Visual Studio's multi-configuration environment and they would work also for the target_link_libraries() command.
So your example would look like:
target_link_libraries(tests ${CMAKE_BINARY_DIR}/src/$<CONFIG>/foo.lib)
I have used generator expression e.g. in custom commands that need to be aware of the output path of my DLL (if foo would be generating an MSTest DLL):
add_test(
NAME RunFooTest
WORKING_DIRECTORY $<TARGET_FILE_DIR:foo>
COMMAND vstest.console.exe /InIsolation /Platform:x86 $<TARGET_FILE:$foo>
)
And - just because you mentioned different solutions - you can use CMake to build a certain configuration from the command line. This would in your case look like e.g.
cmake --build C:\foo --target ALL_BUILD --config Debug_Unicode

Related

what is the difference between configuration type and build type in cmake

What is the difference between CMAKE_CONFIGURATION_TYPES and CMAKE_BUILD_TYPE?
The document claims they are dinstinguished by multi-config or single-config, what does it mean?
CMake is a generator of a build system (yeah, it doesn't build anything by itself).
Some generators are single-configuration (e.g., Unix Makefiles or Ninja). This means that you specify a building type (via -DCMAKE_BUILD_TYPE=XXX) and cmake --build . will build only this type (e.g. Debug, Release, ...) from the generated build directory.
The others are multi-config generators (e.g., Visual Studio NN YYYY or Ninja Multi-Config) -- i.e., you provide a set of configurations (via -DCMAKE_CONFIGURATION_TYPES=Debug;Release) and the generated build system can build any (or all) of the list out of the single build directory (via cmake --build . --config <name>).
So, generally, single-configuration generators (not all of them) check the CMAKE_BUILD_TYPE variable for the desired configuration type. Whereas the multi-configuration generators look for the list of desired configurations in the CMAKE_CONFIGURATION_TYPES.
Except for these (two) variables a generator may check some other variables in order to "tune" smth. Better to read the documentation of the particular generator for the details.

How can I make colcon work with a plain preset-based CMake project with multiple presets in parallel?

Prologue
I have a preset-based plain CMake project so that I can build and test it with cmake --preset $PRESET && cmake --build --preset $PRESET && ctest --preset $PRESET. Note that it nicely interacts with Microsoft's CMake Tools extension for Visual Studio Code, be it for building, testing, debugging and Intellisense.
Since I want to handle multiple presets in parallel, I set CMakePresets.json's binaryDir property to ${sourceDir}/build/${presetName}/.
Issue
I want to also build this plain CMake project with colcon. colcon build --cmake-args "--preset $PRESET" doesn't work, though, as it produces
WARNING:colcon.colcon_cmake.task.cmake.build:Could not build CMake package 'root_project_name' because the CMake cache has no 'CMAKE_PROJECT_NAME' variable
root_project_name being the argument to CMake's project() command in the top CMakeLists.txt.
How can I resolve this warning and the subsequent build failure?
Straightforward solution
Not setting CMakePresets.json's binaryDir property at all works fine with colcon, but doesn't allow for multiple preset builds in parallel.
Solution with multiple preset builds in parallel
The reason for this behavior is colcon-core's build verb's passing the build base directory (default: build) suffixed by the found package's name (here: root_project_name) to the colcon-cmake extension here.
The solution is to pass the correct build base to colcon (i.e. colcon build --build-base ./build/$PRESET/ --cmake-args "--preset $PRESET") and to adapt your CMakePresets.json's binaryDir property to ${sourceDir}/build/${presetName}/root_project_name/.
Note that this then works with colcon test as well, i.e. colcon test --build-base ./build/$PRESET/ --ctest-args "--preset $PRESET".

How to run Clang-based tool as a separate CMake target

I have written a Clang-based tool and I want to run it on existing CMake executable target. I want this to be a separate Makefile target, so I can run it without builiding exe target.
There is a solution to run it during exe target build (described in cmake clang-tidy (or other script) as custom target)
set(CLANG_TIDY_EXE ${MY_CLANG_BASED_TOOL} )
set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}" " --my-additional-options")
set_target_properties(
my_exe_target PROPERTIES
CXX_CLANG_TIDY "${DO_CLANG_TIDY}"
)
CMake runs my tool during my_exe_target build. In build log I see:
...
cmake -E __run_co_compile --tidy=my_tool --source=main.cpp -- ..
But is it possible to create a separate target?
Maybe you could use add_custom_command, e.g. (adjust according to your vars and other needs):
add_custom_target(tidyup
COMMAND ${DO_CLANG_TIDY} [...] ${SOURCES}
DEPENDS [...]
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
edit (to address OP question):
A good starting point is to search for __run_co_compile and try to recreate the command from the Makefile rule (if your generator is make). There's no "automatic" propagation of the attributes, because a custom target or command can be anything. You could use the corresponding cmake variables (e.g. CMAKE_CXX_FLAGS, etc) or target properties (e.g. COMPILE_DEFINITIONS) to emulate that.

How to make a multi-config generator behave like a single-config generator in a project using ExternalProjects?

I am using CMake to build a cross-platform (e.g. Linux/Windows) application which uses also thirdparty libraries as external projects.
I'm aware of the fact that MSVC is a multi-configuration environment, hence
CMAKE_BUILD_TYPE is not used, instead it uses the CMAKE_CONFIGURATION_TYPES set to build every possible configuration.
I'm also aware of the fact that instead of providing a configuration at configuration type (e.g. cmake -DCMAKE_BUILD_TYPE ..) I need to provide the configuration at build type (cmake --build . --config Release)
See https://stackoverflow.com/questions/24460486/cmake-build-type-not-being-used-in-cmakelists-txt]
What I completely fail to understand is:
I don't want multi-configuration builds. I want to build either Debug or Release- but only one of them in the generated buildsystem. Can I achieve that with CMake + multi-config generator (like MSVC or Ninja Multi-Config) + ExternalProject projects? If yes, how?
You should be able to achieve this by just setting CMAKE_CONFIGURATION_TYPES to a single-entry-list on the command line (with the -D argument format) like "-DCMAKE_CONFIGURATION_TYPES=Debug" or "-DCMAKE_CONFIGURATION_TYPES=Release" when you configure the buildsystem, and configuring your calls to ExternalProject_Add of external projects that use CMake to also pass on that value of CMAKE_CONFIGURATION_TYPES to the external project, like:
ExternalProject_Add(
# ...
CMAKE_CACHE_ARGS
"-DCMAKE_CONFIGURATION_TYPES:STRING=${CMAKE_CONFIGURATION_TYPES}"
# ...
)

CMake workflow?

I am learning CMake and I am having problems in understanding its multi-step workflow. So far, my understanding is that you:
write a CMakeLists.txt
run cmake from a subdirectory to generate a build file (a Makefile, in my case)
run make
However, I don't understand how you should handle different targets (Release vs Debug). By running CMake in two different subdirectories?
Also, I don't understand why you would edit CMakeCache.txt (there is also a GUI tool for that). To emulate what you would accomplish with ./configure by passing different options?
You got it pretty much right. The write CMakeLists.txt > cmake > make sequence is correct.
Regarding different configurations (Debug vs. Release), you have to differentiate between multi-config generators (Visual Studio, XCode), and single-config generators (everything else). With the multi-config generators, you generate one buildsystem (e.g. solution file) which contains all configurations, and choosing between them happens at build time.
With single-config generators, different configurations are obtained by generating different buildsystems, that is, by running CMake multiple times in different directories (and with a different value of the CMAKE_BUILD_TYPE CMake variable).
So you'd do something like this:
> cd my_project/bld/debug
> cmake ../../src -DCMAKE_BUILD_TYPE=Debug
> cd ../release
> cmake ../../src -DCMAKE_BUILD_TYPE=Release
Regarding editing the cache (usually through CMake GUI or ccmake): you're right again, this largely corresponds to passing options to ./configure from AutoMake world. This would be the typical workflow with a freshly downloaded project (using CMake GUI):
Run CMake GUI, point it to the source directory (input) and binary directory (output) you want
Configure. This will fill the cache with project-specified defaults. If CMake cannot find some dependencies of the project automatically, this will end with an error.
Inspect the cache, change any values you don't like (such as compilation options), fill in any missing options (paths to libraries CMake couldn't find etc.)
Repeat steps 2 & 3 until you're satisfied with the project's setup.
Generate the buildsystem.
Exit CMake GUI and build using the appropriate build tool.
What #Angew said. Plus here's an image of the cmake-gui:
Also note that you install it (the CMake GUI) on Ubuntu with sudo apt install cmake-qt-gui, and you run it with cmake-gui.
Source: Where is the CMake GUI for Linux?
Here's my cmake-gui image: