Passing compiler options cmake
I know how to pass compiler options using the cmake command
set(CMAKE_CXX_FLAGS "-Wall -Wno-dev -Wl,-rpath=/home/abcd/libs/")
Is there also any way to pass the options from the command line, that will override the CMakeList.txt options , something like -
cmake -Wl,-rpath=/home/abcd/newlibs/ path/to/CMakeLists.txt
or
cmake -D CMAKE_CXX_FLAGS="-Wno-dev -Wl,-rpath=/home/abcd/libs/" path/to/CMakeLists.txt
My main problem is that I want to know how to append flags and how to override existing compiler flags from the command line.
Yes, you can append compiler and linker options. But there are two things you have to differentiate in CMake: first call to generate the build environment and all consecutive calls for re-generating that build environment after changes to your CMakeList.txt
files or dependencies.
Here are some of the possibilities (excluding the more complex toolchain variants):
Append Compiler Flags
-
The initial content from the cached
CMAKE_CXX_FLAGS
variable is a combination ofCMAKE_CXX_FLAGS_INIT
set by CMake itself during OS/toolchain detection and whatever is set in theCXXFLAGS
environment variable. So you can initially call:cmake -E env CXXFLAGS="-Wall" cmake ..
Later CMake would expect that the user modifies the
CMAKE_CXX_FLAGS
cached variable directly to append things e.g. by using an editor likeccmake
commit with CMake.-
You can easily introduce your own build type like
ALL_WARNINGS
. The build type specific parts are appended:cmake -DCMAKE_CXX_FLAGS_ALL_WARNINGS:STRING="-Wall" -DCMAKE_BUILD_TYPE=ALL_WARNINGS ..
Append Linker Flags
The linker options are more or less equivalent to the compiler options. Just that CMake's variable names depend on the target type (EXE
, SHARED
or MODULE
).
-
The
CMAKE_EXE_LINKER_FLAGS_INIT
,CMAKE_SHARED_LINKER_FLAGS_INIT
orCMAKE_MODULE_LINKER_FLAGS_INIT
do combine with the evironment variableLDFLAGS
toCMAKE_EXE_LINKER_FLAGS
,CMAKE_SHARED_LINKER_FLAGS
andCMAKE_MODULE_LINKER_FLAGS
.So you can e.g call:
cmake -E env LDFLAGS="-rpath=/home/abcd/libs/" cmake ..
See above.
-
Build type specific parts are appended:
cmake -DCMAKE_SHARED_LINKER_FLAGS_MY_RPATH:STRING="-rpath=/home/abcd/libs/" -DCMAKE_BUILD_TYPE=MY_RPATH ..
Alternatives
Just be aware that CMake does provide special variable to set complier/linker flags in a platform independent way. So you don't need to know the specific compiler/linker option.
Here are some examples:
CMAKE_CXX_STANDARD
CMAKE_POSITION_INDEPENDENT_CODE
CMAKE_BUILD_RPATH
CMAKE_INSTALL_RPATH_USE_LINK_PATH
Unfortunately there is none for the compiler's warning level (yet)
References
- Change default value of CMAKE_CXX_FLAGS_DEBUG and friends in CMake
- How to set warning level in CMake?
My answer aims to prove one thing:
Command line options like CMAKE_C_FLAGS
and CMAKE_CXX_FLAGS
always append and never overwrite.
Here it comes.
Prepare files under folder hello_world
hello.c
#include <stdio.h>
int main(int argc, char* argv[]) {
printf("Hello World!\n");
#ifdef DEFINED_IN_CMAKELISTS
printf("You are here because you defined DEFINED_IN_CMAKELISTS in CMakeLists and it is not overwritten.\n");
#else
printf("You are here because CLI CMAKE_C_FLAGS overwrote DEFINED_IN_CMAKELISTS, or you have NOT defined DEFINED_IN_CMAKELISTS.\n");
#endif
#ifdef DEFINED_IN_CLI
printf("You are here because you defined DEFINED_IN_CLI when running cmake -DCMAKE_C_FLAGS.\n");
#else
printf("You are here because you have NOT defined DEFINED_IN_CLI when running cmake -DCMAKE_C_FLAGS.\n");
#endif // #ifdef DEFINED_IN_CLI
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1 FATAL_ERROR)
project(Hello)
set(HELLO_SRCS Hello.c)
add_executable(Hello ${HELLO_SRCS})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEFINED_IN_CMAKELISTS")
Generate CMake files
$ mkdir _build && cd _build && cmake ..
-- The C compiler identification is AppleClang 11.0.3.11030032
-- The CXX compiler identification is AppleClang 11.0.3.11030032
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/me/Desktop/_dev/playground/cmake/hello_world/_build
Make and run
$ make
Scanning dependencies of target Hello
[ 50%] Building C object CMakeFiles/Hello.dir/Hello.c.o
[100%] Linking C executable Hello
[100%] Built target Hello
$ ./Hello
Hello World!
You are here because you defined DEFINED_IN_CMAKELISTS in CMakeLists and it is not overwritten.
You are here because you have NOT defined DEFINED_IN_CLI when running cmake -DCMAKE_C_FLAGS.
Define new compiler options from command line
$ cmake -DCMAKE_C_FLAGS="-DDEFINED_IN_CLI" ..
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/me/Desktop/_dev/playground/cmake/hello_world/_build
Make and run
$ make
[ 50%] Building C object CMakeFiles/Hello.dir/Hello.c.o
[100%] Linking C executable Hello
[100%] Built target Hello
$ ./Hello
Hello World!
You are here because you defined DEFINED_IN_CMAKELISTS in CMakeLists and it is not overwritten.
You are here because you defined DEFINED_IN_CLI when running cmake -DCMAKE_C_FLAGS.
Conclusion
From the above test, you can see that even without hard-appending using something like
-DCMAKE_C_FLAGS="${CMAKE_C_FLAGS} -DDEFINED_IN_CLI"
, CMake still appends the CLI options to what's already in CMakeLists.txt
.