CMake command line define macro without value - c++

I have the following line in my CMakeLists.txt
add_compile_definitions(DEBUG=$(DEBUG))
so when I compile my code with Makefile, I can do this
make DEBUG=1
But what I really want is to just define the DEBUG macro without setting any value to it.
Is there a way I can do this on a command line with cmake?

With CMake you can, at configuration time, add some CMake variables. For example you can do this cmake -S <src_folder> -B <build_folder> -DDEBUG=ON. This way you will have access to the variable DEBUG in your CMake.
In your CMake you will have this code
if(DEBUG)
add_compile_definition(DEBUG)
endif()
(Note that instead of add_compile_definitions, it is recommended to use target_compile_definitions which will set your DEBUG macro only for one target and not globally to your project.
Example:
add_executable(my_target main.cpp)
target_compile_definition(my_target PRIVATE DEBUG)
PRIVATE means that this compile_definition will only be used by the target my_target and will not be propagated to others.)
But if you're only concern of the building type, I suggest that you use CMake variables that are already present within CMake. You can use CMAKE_BUILD_TYPE which will contains Debug, Release or whatever depending on what type of build you want. Your code will now be this
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_compile_definition(DEBUG)
endif()
And you can use this command line cmake -S <src_folder> -B <build_folder> -DCMAKE_BUILD_TYPE=Debug
And here the documentation https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
Note that this solution will only works for Mono-config generators like Makefile or Ninja and will not works with Visual Studio or Xcode

Related

Which variable for compiler flags of CMake's ADD_LIBRARY function?

Does exist a variable which contains the compiler flags used in some call to CMake's ADD_LIBRARY function, for example the ones used when we add a module:
ADD_LIBRARY(mylib MODULE mysrc.cpp)
Or, is there a way of getting such flags?
Turning my comments into an answer
There is not a single CMake variable to get the all compiler flags. The problem is that the CMake generator will finally put together the compiler flags (from various CMake variables and properties incl. from depending targets). So you don't have all the flags during configuration step.
I see the following possible problem/solution pairs:
CMake is a cross-platform wrapper around your compiler (that's actually what the C stands for), so no need to extract the compiler flags into an external script
If you just want to add sort of a filter to what is called by CMake you can user set "launcher" variables/properties accordingly e.g. CMAKE_CXX_COMPILER_LAUNCHER or RULE_LAUNCH_LINK
If you want the compiler calls in a machine readable JSON format you could export those by setting CMAKE_EXPORT_COMPILE_COMMANDS
If you just want to see the compiler calls incl. all the flags you could set CMAKE_VERBOSE_MAKEFILE
If you really just need the compiler flags on the output and you don't want CMake to actually compile anything, you could - at least for CMake's Makefile generators - modify CMAKE_CXX_COMPILE_OBJECT and CMAKE_CXX_CREATE_SHARED_MODULE like this:
set(CMAKE_DEPFILE_FLAGS_CXX "")
set(
CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_COMMAND> -E echo <FLAGS>"
)
set(
CMAKE_CXX_CREATE_SHARED_MODULE
"<CMAKE_COMMAND> -E echo <CMAKE_SHARED_MODULE_CXX_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS>"
)
file(WRITE mysrc.cpp "")
add_library(mylib MODULE mysrc.cpp)
References
Is Cmake set variable recursive?
What does the "c" in cmake stand for?
How to use CMAKE_EXPORT_COMPILE_COMMANDS?
Using CMake with GNU Make: How can I see the exact commands?
Retrieve all link flags in CMake

How to get current configuration (Release/Debug) in CMake for Visual Studio

I am on Visual Studio 2013, CMake 3.5.1, Windows 10. I am trying to copy some files via CMake like below:
file(COPY ${IMAGES} DESTINATION ${CMAKE_BINARY_DIR}/bin/Release)
Is it possible to replace "Release" with a variable that represents the configuration like:
file(COPY ${IMAGES} DESTINATION ${CMAKE_BINARY_DIR}/bin/${Variable})
I attempted
file(COPY ${IMAGES} DESTINATION ${CMAKE_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE})
but CMAKE_BUILD_TYPE is an empty string when I use message to print it out, I also attempted
file(COPY ${IMAGES} DESTINATION ${CMAKE_BINARY_DIR}/bin/$<CONFIGURATION>)
but for some reason file command cannot decipher $<CONFIGURATION> whereas command like
add_custom_target(run COMMAND ${CMAKE_BINARY_DIR}/bin/$<CONFIGURATION>/Test.exe)
can. What is the right way to extract whether visual studio is currently built in Release or Debug in CMake?
The file command is executed during CMake runtime, not during build time (i.e. VS runtime).
This also means, that the generator expressions (e.g. $<CONFIG>) can not be used, as these are evaluated during build time.
(Hint: As long as there is no explicit reference to the use of generator expressions for a particular command in the CMake docu, they are not supported by that command).
The reason, why ${CMAKE_BUILD_TYPE} is empty, is due to the reason that you probably haven't specified it on the invocation of CMake:
cmake -DCMAKE_BUILD_TYPE=Debug ..
However, using that, would mean that the build files are only generated for the Debug configuration. That's obviously not what you want.
To solve your problem: Using generator expressions is the right way, as you've already figured out with the use of add_custom_target (or add_custom_command).
You can use custom commands as dependencies for other "real" targets and you can specify post-/pre-build and pre-link commands for a specific target via add_custom_command.
As the docu states for the COMMAND argument of add_custom_command:
Arguments to COMMAND may use generator expressions. References to target names in generator expressions imply target-level dependencies, but NOT file-level dependencies. List target names with the DEPENDS option to add file-level dependencies.
To copy a file after a successful build of a target:
add_custom_command(TARGET myTarget POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${IMAGE1}" "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${IMAGE2}" "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/"
)

Generator expressions cmake: copying works in debug but not release mode

I am trying to figure out how to copy some libs depending on the config in cmake.
I tried this:
add_custom_command(TARGET Myapp
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<$<CONFIG:Debug>:${_LIBS_DEBUG}>
$<$<CONFIG:Release>:${_LIBS_RELEASE}>
$<TARGET_FILE_DIR:MyApp>)
It copies libs in Debug but not in release:
Is this supposed to be legal and should work?
If it is not legal (I do not get error), how can I achieve the same effect?
Turning my comments into an answer
What I normally do to debug those case is to add another COMMAND before the actual line in question that just echos the command line. In your case:
COMMAND ${CMAKE_COMMAND} -E echo
$<$<CONFIG:Debug>:${_LIBS_DEBUG}>
$<$<CONFIG:Release>:${_LIBS_RELEASE}>
I've run this a few tests and you will see that the $<1:...> and $<0:...> expressions are not evaluated.
So seeing this I was searching CMake's bug tracker database and this is a known issue and yet (as for CMake 3.5.2) unresolved: 0009974: CMake should support custom commands that can vary by configuration.
There are several ways proposed in this ticket that do work with existing versions of CMake.
In your case - until this issue is resolved and if you want to have it shell independent - I would do it the "old way" and call a CMake script:
CopyLibsByConfig.cmake.in
if (_CONFIG STREQUAL "Debug")
file(COPY #_LIBS_DEBUG# DESTINATION "${_DEST_PATH}")
else()
file(COPY #_LIBS_RELEASE# DESTINATION "${_DEST_PATH}")
endif()
CMakeLists.txt
...
configure_file(CopyLibsByConfig.cmake.in CopyLibsByConfig.cmake #ONLY)
add_custom_command(TARGET MyApp
POST_BUILD
COMMAND ${CMAKE_COMMAND}
-D _CONFIG=$<CONFIG>
-D _DEST_PATH="$<TARGET_FILE_DIR:MyApp>"
-P "${CMAKE_CURRENT_BINARY_DIR}/CopyLibsByConfig.cmake"
)
But the solution can very much depend on the files you want to copy to your binary output folder. And there are a lot of way doing it, like using install():
install(FILES ${_LIBS_DEBUG} CONFIGURATIONS Debug DESTINATION $<TARGET_FILE_DIR:MyApp>)
install(FILES ${_LIBS_RELEASE} CONFIGURATIONS Release DESTINATION $<TARGET_FILE_DIR:MyApp>)
set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
Obviously that's not the way install() is meant to be used, so consider using the INSTALL or PACKAGE targets properly to distribute your application and all its dependencies.
And if we are talking about Visual Studio runtime DLLs you most likely want to take a look at the InstallRequiredSystemLibraries CMake module.
Other solution is to use generator expression.
For example I have cppzmq (shared library) and cppzmq-static (static library with static dependencies). I would like to have faster debug builds so I use cppzmq in Debug build and in (other) e.g. release I want one big fat exec.
target_link_libraries(CommunicationCommonLib PUBLIC
$<IF:$<CONFIG:Debug>,cppzmq,cppzmq-static>
Dexode::EventBus
gcpp
protobuf::libprotobuf
)

Using compiler prefix command(s) with CMake (distcc, ccache)

There are utilities which use an existing compiler by adding a command as a prefix (so instead of calling cc -c file.c you could call distcc cc -c file.c).
When using CMake the compiler command can be changed, however I ran into problems trying to use distcc, though this would likely apply to any command prefix to the compiler (ccache too).
CMake expects the compiler to be an absolute path,so setting CMAKE_C_COMPILER to /usr/bin/distcc /usr/bin/cc, gives an error:
/usr/bin/distcc /usr/bin/cc
is not a full path to an existing compiler tool.
Setting the compiler to /usr/bin/distcc andCMAKE_C_COMPILER_ARG1 or CMAKE_C_FLAGS to begin with /usr/bin/cc works in some cases, but fails with CHECK_C_SOURCE_COMPILES(checked if there was some way to support this, even prefixing CMAKE_REQUIRED_FLAGS didn't work).
The only way I found to do this is to wrap the commands in a shell script.
#!/bin/sh
exec /usr/bin/distcc /usr/bin/cc "$#"
While this works, It would be nice to be able to use compiler helpers with CMake, without having to go though shell scripts (giving some small overhead when the build system could just use a command prefix).
So my question is:
Can CMake use compiler prefix commands (such as distcc) directly?, without shell script wrappers?
Since CMake 3.4.0 there has been a CMAKE_<LANG>_COMPILER_LAUNCHER variable and corresponding target property <LANG>_COMPILER_LAUNCHER. So if your project is C-only you would do something like:
cmake -DCMAKE_C_COMPILER_LAUNCHER=ccache /path/to/source
CCACHE_PREFIX=distcc make -j`distcc -j`
If you have a C++ project, use -DCMAKE_CXX_COMPILER_LAUNCHER=ccache.
Or, make your CMakeLists.txt smart and use ccache automatically if it can be found:
#-----------------------------------------------------------------------------
# Enable ccache if not already enabled by symlink masquerading and if no other
# CMake compiler launchers are already defined
#-----------------------------------------------------------------------------
find_program(CCACHE_EXECUTABLE ccache)
mark_as_advanced(CCACHE_EXECUTABLE)
if(CCACHE_EXECUTABLE)
foreach(LANG C CXX)
if(NOT DEFINED CMAKE_${LANG}_COMPILER_LAUNCHER AND NOT CMAKE_${LANG}_COMPILER MATCHES ".*/ccache")
message(STATUS "Enabling ccache for ${LANG}")
set(CMAKE_${LANG}_COMPILER_LAUNCHER ${CCACHE_EXECUTABLE} CACHE STRING "")
endif()
endforeach()
endif()
Just as a hint: never use <LANG>_COMPILER_LAUNCHER to cross compile. If <LANG>_COMPILER_LAUNCHER is used together with distcc the absolute compiler path is sent to distcc and the host is not using the cross comping toolchain!
Instead you should use the old school method, just overwrite the compiler path:
export PATH=/usr/lib/distcc:$PATH
It took me hours to find out...

Adding include directories to CMake when calling it from the command line

I'm in a situation where I should not disturb the existing CMakeLists.txt files, but I still should add some g++ system include directory to my build.
In other words, I need -isystem /path/to/my/include added to my compiler flags, but when calling something like cmake ...
Maybe something like cmake .. -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS -isystem /path/to/my/include"? Is there a way to do this?
I have the same problem. I found two solutions:
The one proposed by sakra in a previous answer, i.e. setting an environment variable with C++ flags:
export CXXFLAGS=-isystem\ /path/to/my/include
cmake <path to my sources>
OR the same thing, but environment variable are set only for this CMake call:
CXXFLAGS=-isystem\ /path/to/my/include cmake <path to my sources>
IMPORTANT: you must clean your build directory (i.e. clean the CMake cache) before launching any of this form. Without cleaning the cache, CMake will continue using your cached CMAKE_CXX_FLAGS from the previous run.
Directly setting CMAKE_CXX_FLAGS in cmake string:
cmake -DCMAKE_CXX_FLAGS=-isystem\ /path/to/my/include <path to my sources>
I believe that it can be done by a more 'native' way, but I didn't find a variable responsible for paths to headers in CMake.
You can set the environment variable CXXFLAGS before invoking CMake.
$ export CXXFLAGS=-isystem\ /path/to/my/include
$ cmake ..
CMake will the initialize the cache variable CMAKE_CXX_FLAGS with the flags from the environment variable. The variable affects all build types.
Using -DCMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES=<something> worked for me even without toolchain file. This avoids cluttering compiler flags.
Just an additional note to the other answers: with CMake 3.15.3 on macOS 10.14.5, only the solution using the CMake flag seems to work properly.
So, in my case, only this solution worked fine:
cmake -DCMAKE_CXX_FLAGS=-I\ /path/to/include <path/to/source>