Passing compiler options cmake

Viewed 113374

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.

6 Answers

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.

Perhaps this would work -

cmake -DCMAKE_CXX_FLAGS="$(CMAKE_CXX_FLAGS) -DYOUR_CUSTOM_DEFINE=1" <rest of original cmake cmdline>

like Tomaz mentioned above. -m

Most of answers here are valid, but I have also stumbled on how to pass CMAKE_CXX_FLAGS and add include directory with space in it (Windows).

Apparently if you run that argument from command line - you need to be extra careful with quotation (See also here)

cmake ... -DCMAKE_CXX_FLAGS="-fms-compatibility-version=19.00 --target=i686--windows -X -I """C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um""" "

So if include path contains spaces, and that needs to be quoted, but you need also to quote CMAKE_CXX_FLAGS, which ends up with starting quotation with single quote character ("), and whenever you need quote - you place three quotation characters instead. (""")

That's bit odd in overall. Took a while to figure this out.

I simply use the $ENV() operator to get the environment variable, for example in a CMakeLists.txt:

add_compile_options($ENV{MY_CXXFLAG})

The only problem is that $ENV() is only read on configuration stage so cmake does not see the environment setting on the current build stage. But re-configuring is triggered by changed cmake files so I just use touch to simulate a change. Here is an example of a command line:

touch CMakeLists.txt && MY_CXXFLAG="-D DEBUG" cmake --build build --config Debug

or what other options do you use. With this simple example there are still some quirks with the flag string of the environment variable, e.g. more than one option. But it shouldn't be a big problem with string handling in CMakeLists.txt to beautify this.

Related