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

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

Related

CMake command line define macro without value

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

Alternatives for CMake commands

I am new to CMake and was going through the CMake documentations and tutorials. I was able to understand that the target_include_directories command is just the -I option for the compiler (gcc for me). I tried doing it adding the directories manually by using set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I <Path>") and it worked perfectly fine!!
My CMakeLists.txt looks something like this:
cmake_minimum_required(VERSION 3.6)
project(Project VERSION 1.0 DESCRIPTION "C Project" LANGUAGES C)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I <path-to-header>")
add_library(basic file1.c file2.c)
#target_include_directories(basic PUBLIC "path-to-header")
#target_include_directories() is commented out as CMAKE_C_FLAGS have been set
add_executable(main.out main.c)
target_link_libraries(main.out PRIVATE basic)
I wanted to know if there any similar and alternative for the target_link_libraries command using which we can pass -L and -l options to linker in CMake??
To answer your question literally: There is the variable CMAKE_EXE_LINKER_FLAGS and its specializations CMAKE_EXE_LINKER_FLAGS_<CONFIG> for certain configurations like RELEASE or DEBUG or whatever configurations you might have defined. See the CMake documentation for more.
BUT, I highly disrecommend to use these unless you need to pass a very special compiler/linker option CMake does not know about, because these are specific to your compiler.
The point of using CMake is to describe the build process independent of the concrete compiler and platform, such that you can easily switch to another one or at least update your compiler without having to refactor your build code. So, better stick with the generic target_include_directories, target_link_libraries, and similar commands as much as possible.
If you really have to use CMAKE_C_FLAGS or CMAKE_EXE_LINKER_FLAGS I'd recommend to wrap them into an if clause making sure that you are building with the expected compiler on the expected platform and put a fatal error message into the else clause to make future users aware of a possible problem.

Appending CXX_FLAGS in cmake invocation [duplicate]

This question already has answers here:
Passing compiler options in CMake
(6 answers)
Closed 5 years ago.
I am wondering if it is possible to append to inferred variables when calling cmake. Due either the compiler or the app supplied CMakeLists.txt C++11 support isn't detected by cmake even though it is supported and the application requires it. If I do:
cmake-DCMAKE_CXX_FLAGS='-std=c++11' ../source_dir
The flags get overwritten and I wouldn't like to lose the inferred flags. I could manually run without overwriting and just copy the flags and append c++11 but I think there must be a better solution.
I have found a number of posts on adding c++11 support to CMakeLists.txt but not in cmake call, so I am wondering if this is possible at all. Please let me know.
Yes, this is possible. First, create a variable called MY_FLAGS in the command line with the flags you want.
cmake -DMY_FLAGS='-std=c++11' ../source_dir
Then, in your CMakeLists.txt, do the following:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MY_FLAGS}")
This will effectively amend your flags to the flags that CMake generates. However, if you want to set the C++ standard to C++11, you can just do the following without directly dealing with flags:
cmake -DCMAKE_CXX_STANDARD=11 -DCMAKE_CXX_STANDARD_REQUIRED=ON ../source_dir
On a side note, make sure that the ../source_dir is after the CMake options, since otherwise CMAKE_CXX_STANDARD_REQUIRED would not work. (Read)
I recently did this, when building a dependency for one of the applications I work to.
There are 2 CMake variables that you can make use of, namely:
-DCMAKE_BUILD_TYPE=Debug/Release
-DCMAKE_CXX_FLAGS_[DEBUG/RELEASE]
When specifying a build type, cmake will add to the compiler flags the flags that are specified in that second variable. So for me, using:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS_RELEASE=-fPIC
did the thing.
In your case, you can try the following approaches:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS_RELEASE=-std=c++11
or
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS_DEBUG=-std=c++11
Of course, this will work if the variables are not overwritten in the script. Try both approaches.
You are probably looking for
set (CMAKE_CXX_STANDARD 11)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
Or via command line:
cmake -DCMAKE_CXX_STANDARD=11 -DCMAKE_CXX_STANDARD_REQUIRED=ON
That being said, CMAKE_CXX_FLAGS is not overridden by cmake, so your CMakeLists.txt must be doing it somewhere.
The polite way of setting the flags from within a script is to append to the variable, that is:
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} stuff")

How to add preprocessor definitions on CMake's command line? [duplicate]

I try to set a preprocessor macro in the command line of CMake. I've tried:
set generator="Visual Studio 8 2005"
set params=-D MY_MACRO=1
cmake.exe -G %generator% %params% ..\some_project
but it's neither defined when I compile nor can I find the name MY_MACRO in the files generated by CMake at all, except for CMakeCache.txt where it's present in the form:
MY_MACRO:UNINITIALIZED=1
How can I do it?
A good alternative would be to define a cmake option:
OPTION(DEFINE_MACRO "Option description" ON) # Enabled by default
Followed by a condition:
IF(DEFINE_MACRO)
ADD_DEFINITIONS(-DMACRO)
ENDIF(DEFINE_MACRO)
Then you can turn that option ON/OFF via command line with cmake using the -D flag. Example:
cmake -DDEFINE_MACRO=OFF ..
To make sure the compiler is receiving the definition right, you can call make in verbose mode and check for the macro being defined or not:
make VERBOSE=1
This is a good solution also because make will recompile your code when any of cmake options changes.
Try this: -D CMAKE_CXX_FLAGS=/DMY_MACRO=1
The motivation behind the question was to batch build 3rd party libraries, which is why I wanted to avoid modifying CMakeLists. So years later, even though I don't need that anymore, I figured out that it's easily achievable by means external to CMake:
Invoke CMake as usual, no special flags.
Then:
With MSVC: The compiler reads the CL environment variable to get extra command line arguments. So
set CL=/DMY_MACRO=1 %CL%
then invoke MSBuild to do its job.
With Makefiles: The generated makefiles use the CFLAGS and CXX_FLAGS variables as makefiles are expected to do. So the build can be started by
make CXX_FLAGS=-DMY_MACRO=1
or by setting the corresponding environment variables.
Unless you have a good reason not to, you should use ADD_DEFINITIONS(<name>=<value>[, ...]).
Just add the following line to your CMakeLists.txt:
ADD_DEFINITIONS("MY_MACRO=1")
CMake will take care of the syntax of the switches (be it -D<name>=<value>, or /D<name>=<value>).

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...