69

At the beginning of my CMake project, I'm setting general compilation flags in the variable CMAKE_CXX_FLAGS, like

set(CMAKE_CXX_FLAGS "-W -Wall ${CMAKE_CXX_FLAGS}")

Later on, I need to append additional configuration-specific compilation flags (stored in BUILD_FLAGS). Can I use the following command for this:

set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS ${BUILD_FLAGS})

or do I have to add the CMAKE_CXX_FLAGS manually:

set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BUILD_FLAGS}")

to prevent CMAKE_CXX_FLAGS being overriden by BUILD_FLAGS?

Milan Hanus
  • 714
  • 1
  • 5
  • 7
  • 2
    I believe that they are appended to the CMAKE_CXX_FLAGS, you can verify this by invoking a verbose make file `make target VERBOSE=1` – Ramon Zarazua B. Feb 23 '11 at 21:49

2 Answers2

70

The accepted answer is still working but outdated since 2013.
This answer is based and new functions from CMake v2.8.12, v3.3 and v3.13.

Since CMake-2.8.12 (2013)

Two new commands to set CMAKE_CXX_FLAGS:

The documentation of last version has not changed a lot since cmake-2.8.12:

In you case you can use:

target_compile_options(${TARGET} PRIVATE ${BUILD_FLAGS})

Or simply if you have a single target:

add_compile_options(${BUILD_FLAGS})

More examples

target_compile_options(mylib PRIVATE   -O2) # only internal
target_compile_options(mylib INTERFACE -gl) # only external
target_compile_options(mylib PUBLIC    -g)  # same as PRIVATE + INTERFACE

# multiple targets and flags
target_compile_options(mylib1 mylib2 PRIVATE -Wall -Wextra)

target_compile_options(    mylib PUBLIC -DUSEXX)  # Bad
target_compile_definitions(mylib PUBLIC -DUSEXX)  # OK

add_compile_options(-Wall -Wextra) # for all targets in current directory
add_compile_options(-DUSEXX)       # Bad
add_definitions(-DUSEXX)           # OK

Deprecated COMPILE_FLAGS

cmake-3.0 documentation flags COMPILE_FLAGS as deprecated:

COMPILE_FLAGS

Additional flags to use when compiling this target’s sources.

The COMPILE_FLAGS property sets additional compiler flags used to build sources within the target. Use COMPILE_DEFINITIONS to pass additional preprocessor definitions.

This property is deprecated. Use the COMPILE_OPTIONS property or the target_compile_options command instead.

If you still want to use set_target_properties() you may use COMPILE_OPTIONS instead of COMPILE_FLAGS:

set_target_properties(${TARGET} PROPERTIES COMPILE_OPTIONS ${BUILD_FLAGS})

Since CMake-3.3 (2015)

Anton Petrov suggests to use generator expressions as presented in an answer of ar31.

The CMake generator expressions applies your ${BUILD_FLAGS} to:

  • C++ language using $<COMPILE_LANGUAGE:CXX> (can also be C, CUDA...)
  • Clang compiler using $<CXX_COMPILER_ID:Clang>
    (can also be GNU for gcc, or MSVCfor Visual C++... see full list)
    (use $<C_COMPILER_ID:Clang> instead if language is C)
  • and more as supported C++ feature or compiler version... (see documentation)

In you case you can use:

target_compile_options(${TARGET} PRIVATE
          $<$<COMPILE_LANGUAGE:CXX>:${BUILD_FLAGS_FOR_CXX}>
          $<$<COMPILE_LANGUAGE:C>:${BUILD_FLAGS_FOR_C}>)

or about compilers:

target_compile_options(${TARGET} PRIVATE
          $<$<CXX_COMPILER_ID:Clang>:${BUILD_FLAGS_FOR_CLANG}>
          $<$<CXX_COMPILER_ID:GNU>:${BUILD_FLAGS_FOR_GCC}>
          $<$<CXX_COMPILER_ID:MSVC>:${BUILD_FLAGS_FOR_VISUAL}>)

Since CMake-3.13 (2018)

A new function target_link_options() allow to pass options to the linker, as mentioned by Craig Scott.

Different options for C and C++ files

The best way is to distinguish C files and C++ files using two different targets.

oHo
  • 51,447
  • 27
  • 165
  • 200
  • 1
    What if you have mixed target? For example C and C++. How do you set options only for C target? – Martin Jun 02 '17 at 22:37
  • Hi @Martin. I do not know about a target mixing C and C++ files using different options each kind of source file. I may suggest to split this target in two : one target for C source code and the other one for C++. ... OK I am starting to add a section in may answer to propose a way to address this complex situation... – oHo Jun 03 '17 at 07:26
  • 1
    Why can't I use `set_target_properties()` with `LINK_FLAGS` the same way? It seems it never accepts more than one flag (Even in list form). – Royi Feb 21 '18 at 00:42
  • Hi @Royi, I do not know because I not use `set_target_properties()`. This function is an old usage of CMake (close to Makefiles mind). Hope you will find a modern way to use CMake. Have fun, Cheers – oHo Feb 21 '18 at 10:24
  • What do you mean? Isn't using "Target Properties" the "Modern" way using Cmake? – Royi Feb 21 '18 at 10:26
  • Hi @Royi. Sorry, yes, function `set_target_properties()` is still useful nowadays, and I use it sometimes as for `set_target_properties(mylib PROPERTIES LINKER_LANGUAGE CXX)` or `set_target_properties(mylib PROPERTIES POSITION_INDEPENDENT_CODE True)`. I mean I prefer to use modern functions [`target_*()`](https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html#id4) when possible. Do you see what I mean? – oHo Feb 21 '18 at 10:52
  • Yes. I also prefer those. Yet there is none for the Linker Flags unless I'm missing something. Thank You. – Royi Feb 21 '18 at 11:27
  • 1
    @olibre Please see this answer https://stackoverflow.com/a/21561742/423959 for language specific options. The right way is to use generator expressions. – Anton Petrov Mar 02 '18 at 08:04
  • @Royi "Yet there is none for the Linker Flags unless I'm missing something." --> CMake 3.13 adds the `target_link_options()` command which fills this gap, but you have always been able to (ab)use `target_link_libraries()` to add linker flags. – Craig Scott Nov 11 '18 at 04:58
  • 1
    `$<$:${BUILD_FLAGS_FOR_CXX}>` is probably a mistake, it should rather be `$<$:${BUILD_FLAGS_FOR_C}>` – Adam Romanek Jan 07 '19 at 11:48
  • Thank you @AdamRomanek I have fixed the mistake. \o/ Cheers – oHo Jan 19 '19 at 21:40
  • @oHo I couldn't find any docs related to having multiple targets in one option like the one you mentioned in your answer: "target_compile_options(mylib1 mylib2 PRIVATE -Wall -Wextra)" do you have any refs? Also, it didn't work for me. – AMCoded Sep 05 '22 at 05:12
  • Sorry @AMCoded since 2019 I have stopped using CMake (I was also a CMake coder). I am currently coding in Go/TS/Python and I have forgotten my CMake knowledge! – oHo Sep 26 '22 at 17:21
61

Use the first one:

set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS ${BUILD_FLAGS})

The flags stored in BUILD_FLAGS are appended after CMAKE_CXX_FLAGS when compiling the sources of TARGET. The documentation hints at this, but I've just tried it to make sure.

COMPILE_FLAGS

   Additional flags to use when compiling this target's sources. 
   
   The COMPILE_FLAGS property sets additional compiler flags used to
   build sources within the target.  Use COMPILE_DEFINITIONS to
   pass additional preprocessor definitions.

The full command line will be the equivalent of:

${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${COMPILE_FLAGS} -o foo.o -c foo.cc

And as Ramon said, you can always check with make VERBOSE=1.

Community
  • 1
  • 1
richq
  • 55,548
  • 20
  • 150
  • 144
  • 1
    You are right, thank you very much (and to Ramon too). I also didn't know about the VERBOSE parameter before and it is now much easier for me to learn how CMake actually processes my commands. – Milan Hanus Feb 24 '11 at 16:34