I want to write a cmake file that sets different compiler options for clang++, g++ and MSVC in debug and release builds. What I'm doing currently looks something like this:
if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest /W4")
# Default debug flags are OK
set(CMAKE_CXX_FLAGS_RELEASE "{CMAKE_CXX_FLAGS_RELEASE} /O2")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1z -Wall -Wextra -Werror")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} some other flags")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
else()
# nothing special for gcc at the moment
endif()
endif()
But I have a couple of problems with this:
- First the trivial: Is there relly no command like appen that would allow me to replace
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} Foo")
withappend(CMAKE_CXX_FLAGS "Foo")
? - I've read multiple times, that one should not manually set
CMAKE_CXX_FLAGS
and similar variables in the first place, but im not sure what other mechanism to use. - Most importantly: The way I do it here, I need a separate build directory for each compiler and configuration Ideally I'd like to transform that into havin multiple targets in the same directory so I can e.g. call
make foo_debug_clang
.
So my questions are
- a) Is there a better way to write th cmake script that solves my "pain points"? solution to the points mentioned above?
- b) Is there something like an accepted, modern best practice of how to set up such projects?
Most references I could find on the internet are either out of date or show only trivial examples. I currently using cmake3.8, but if that makes any difference, I'm even more interested in the answer for more recent versions.
Another way is to use .rsp files.
which might make the inclusion of multiple and esoteric options easier to manage.
You can use target_compile_options() to "append" compile options.
Your approach would - as @Tsyvarev has commented - be absolutely fine, just since you've asked for the "new" approach in CMake here is what your code would translate to:
You take
add_compile_options()
and - as @Al.G. has commented - "use the dirty generator expressions".There are some downsides of generator expressions:
$<IF:...,...,...>
expression is only available in CMake version >= 3.8string(APPEND ...)
, which you can also use to "optimize" yourset(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ...
calls.So better use a more readable and backward compatible approach with
add_compile_options()
:And yes, you don't explicitly specify the C++ standard anymore, you just name the C++ feature your code/target does depend on with
target_compile_features()
calls.For this example I've chosen
cxx_lambda_init_captures
which would for e.g. an older GCC compiler give the following error (as an example what happens if a compiler does not support this feature):And you need to write a wrapper script to build multiple configurations with a "single configuration" makefile generator or use a "multi configuration" IDE as Visual Studio.
Here are the references to examples:
So I've tested the following with the
Open Folder
Visual Studio 2017 CMake support to combine in this example the cl, clang and mingw compilers:CMakeSettings.json
mingw32-make.cmd
So you can use any CMake generator from within Visual Studio 2017, there is some unhealthy quoting going on (as for September 2017, maybe fixed later) that requires that
mingw32-make.cmd
intermediator (removing the quotes).Addressing the first two points, but not the third:
The command you want is
set_property
. CMake supports a bunch of properties - not everything, but lots - in a way which saves you the trouble of doing compiler-specific work. For example:which for some compilers will result in
--std=c++17
but for earlier ones with--std=c++1z
(before C++17 was finalized). or:will result it
-DHELLO
-DWORLD
for gcc, clang and MSVC but for weird compilers might use other switches.set_property
can be used either in set mode, or in append mode (see above examples).I can't say whether this is preferable to
add_compile_options
ortarget_compile_features
, though.