21

I would like to add -std=c++11 to my

add_compile_options("-std=c++11")

However, this also adds them to compilation of C files, not only C++. I know I can add conditional compile flags depending on the configuration used:

add_compile_options("$<$<CONFIG:DEBUG>:-addMeInDebugOnly>")

How can I add my flag only to c++ files? I'm looking for something like:

add_compile_options("$<$<??:??>:-std=c++11>")

But what do I need to fill in with the question marks?

Jan Rüegg
  • 9,587
  • 8
  • 63
  • 105
  • are you using g++/gcc ? – Piotr Skotnicki Aug 27 '14 at 10:45
  • Either g++/gcc or clang, depending on the platform. – Jan Rüegg Aug 27 '14 at 10:48
  • 1
    You might want to take a look at the experimental [`target_compile_features` command](http://www.steveire.com/cmake-future/manual/cmake-compile-features.7.html) that would allow us to get rid of non-portable compiler flags for this use case altogether. As of now (CMake 3.0.1) this feature does not ship with CMake, but we should get it with one of the next releases. – ComicSansMS Aug 27 '14 at 11:09
  • 2
    target_compile_features looks awesome, thanks for the comment! Although I'm not sure if it solves the problem really: Doing it globally (for all following targets) and doing it just for C++ and not C files might still not be possible, if I understand it correctly... – Jan Rüegg Aug 28 '14 at 06:05
  • @ComicSansMS: wouldn't this be a pretty big job to do? Define the mapping of each feature into an option, for each known compiler. Also, since I know which compilers I want to use (gcc), I set other flags, like `-wno-unused-variable`. It would be easier for me to do something like `add_compile_options( -std=c++11 -wno-unused-variable LANGUAGE C++ )`. – telephone Sep 22 '14 at 15:51
  • @telephone It has its advantages. The resulting CMake code is certainly more self-documenting than an arcane set of compiler switches. Also, portability is of course a huge plus: You simply tell which features you want and it will just do the right thing, out-of-the-box, with any compiler. But I do agree, if you are absolutely sure that you will only ever support a single compiler, just hardcoding the options is a lot more convenient. Use the right tool for the job: If the build is simple enough that hardcoded options do fine, by all means, go ahead. – ComicSansMS Sep 22 '14 at 18:21

3 Answers3

48

When you have mixed C and C++ sources, the LINKER_LANGUAGE property might apply the wrong flags for compilation of individual sources. The solution is to use the COMPILE_LANGUAGE generator expression (introduced with CMake 3.3). The simplest example for your original C++1x flag is:

add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-std=c++11>)

When you have a string of compile options (for example, for usage with the COMPILE_FLAGS target property), you have to split the flags

set(WARNCFLAGS "-Wall -Wextra -Wfuzzle -Wbar")
# ...
string(REPLACE " " ";" c_flags "${WARNCFLAGS}")
string(REPLACE " " ";" cxx_flags "${WARNCXXFLAGS} ${CXX1XCXXFLAGS}")
add_compile_options(
  "$<$<COMPILE_LANGUAGE:C>:${c_flags}>"
  "$<$<COMPILE_LANGUAGE:CXX>:${cxx_flags}>"
)
# Two alternative variants for single targets that take strings:
target_compile_options(some-target PRIVATE "${WARNCFLAGS}")
set_target_properties(some-target PROPERTIES
  COMPILE_FLAGS "${WARNCFLAGS}")

Use of strings is however deprecated in favor of lists. When lists are in use, you can use:

set(c_flags -Wall -Wextra -Wfuzzle -Wbar)
# ...
add_compile_options(
  "$<$<COMPILE_LANGUAGE:C>:${c_flags}>"
  "$<$<COMPILE_LANGUAGE:CXX>:${cxx_flags}>"
)
# Two alternative variants for single targets given a list:
target_compile_options(some-target PRIVATE ${f_flags})
set_target_properties(some-target PROPERTIES
  COMPILE_OPTIONS "${c_flags}")

Pay attention to the quoting. If a list is not quotes, it is expanded to its items (and is no longer a list). To pass a list between commands, quote it.

Lekensteyn
  • 64,486
  • 22
  • 159
  • 192
  • Starting with CMake 3.15 you also have `$` that helps even more in cases your project needs to build on more than one compiler. – Adam Badura Jun 02 '22 at 22:11
6

You can use LINKER_LANGUAGE target property to add flag only to C++ targets*:

add_compile_options(
    "$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,CXX>:-std=c++11>"
)

*Note that this will not work for targets with mixed C/C++ sources

CMAKE_CXX_FLAGS should work fine too:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

Probably you need to add them to cache if it set before project command (e.g. in toolchain):

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" CACHE STRING "" FORCE)
  • Awesome, "target_property:linker_language" was exactly what I was looking for :) – Jan Rüegg Sep 01 '14 at 06:19
  • Hmm... actually doesn't seem to work after all if C and C++ code are mixed in the same target :( – Jan Rüegg Sep 01 '14 at 07:02
  • @ruslo: But does `CMAKE_CXX_FLAGS` works for all build types (`CMAKE_BUILD_TYPE_DEBUG`, `CMAKE_BUILD_TYPE_RELWITHDEBINFO`, ...), or do I need to do it the old way, http://binglongx.wordpress.com/tag/cmake_build_type/ ? – telephone Sep 22 '14 at 21:13
  • 1
    `set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" CACHE STRING "" FORCE)` adds `-std=c++11` to the flags field every time cmake is run, so each time it *gains* another -std=c++11 – kfsone Oct 31 '16 at 08:56
3

I'd rather do it like this:

set_source_files_properties(
    ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
    PROPERTIES COMPILE_FLAGS "-std=c++11")

where the documentation for set_source_files_properties is at http://www.cmake.org/cmake/help/v3.0/command/set_source_files_properties.html

bames53
  • 86,085
  • 15
  • 179
  • 244
Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167
  • The problem with this is that I would like to use the code in a top level CMakeLists.txt file, and have it applied to all cmake files in all subdirectories. So I would have to add your line to dozens of different CMakeLists.txt files, which is not very nice... – Jan Rüegg Aug 27 '14 at 10:46
  • @JanRüegg did you try setting `CMAKE_CXX_FLAGS` like `SET ( CMAKE_CXX_FLAGS "-std=c++11" CACHE STRING "compile flags" FORCE)` (http://stackoverflow.com/questions/15100351/changing-cmake-cxx-flags-in-project) – Ferenc Deak Aug 27 '14 at 10:54
  • Thats what I'm currently doing, however I would have liked to get rid of this, since I thought its the "old ugly" way of doing it, while add_compile_options is more modern. – Jan Rüegg Aug 27 '14 at 10:56
  • @JanRüegg Don't stress about the modernness of things ... some of us still use vi or emacs :) as long as it works it does its job and it's supported by cmake it's ok to use it... – Ferenc Deak Aug 27 '14 at 10:59
  • 2
    Ok, sure... I guess I'll have to stick with the old way, then. And who said vi is not modern? ;) – Jan Rüegg Aug 27 '14 at 11:04
  • This did not seem to work for me, probably because of the glob pattern? – Lekensteyn Feb 12 '16 at 11:10