How to enable /std:c++17 in VS2017 with CMake

Viewed 28156

I'm trying to add the /std:c++17 compiler flag to VS2017 with CMake. I'm using the "modern" cross-platform way so far:

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) # -std=c++11 instead of -std=gnu++11
set(MY_CXX_COMPILE_FEATURES cxx_generic_lambdas cxx_range_for cxx_strong_enums)

add_library(mylib INTERFACE)
target_compile_features(mylib INTERFACE ${MY_CXX_COMPILE_FEATURES})

This adds /std:c++14 in VS2017 (which might be the default anyway?). However I'm having trouble switching this to C++17 (i.e. having it add /std:c++17). If I just add it manually, I get the not-so-nice warning because both flags are present:

1>cl : Command line warning D9025: overriding '/std:c++14' with '/std:c++17'

I've tried set(CMAKE_CXX_STANDARD 17) but it has no effect, in fact the CMake documentation mentions that CMAKE_CXX_STANDARD has no effect on VS anyway.

As for adding a C++17 feature to target_compile_features, it doesn't seem like there are any yet (even in CMake-3.9.0-rc5), and even if there were, I'm specifically only using std::optional from C++17, and there's no target_compile_features flags for library features like std::optional.

So my question is, what's the best (or least ugly) way to do this with CMake? And in a way so it'll also work for gcc and clang? I'm happy to use a very recent CMake version (3.8 or 3.9). I prefer it to be "nice" and not manually looping through CXX_COMPILE_FLAGS and removing the string "/std:c++14" or some hack like that.

(Edit: It can also be the VS/std:c++latest switch - whichever is possible. Both work for the purpose.)

2 Answers

CMake versions higher than 3.10 support MSVC C++ standard switches for MSVC versions newer than 19.0.24215. If either of the version requirements are not met, then they have no effect.

The only portable approach, to ensuring your program is compiled with the correct C++ standard mode on Visual Studio, is to require at least CMake 3.10, set the target property CXX_STANDARD to your desired value and CXX_STANDARD_REQUIRED to ON.

Example usage:

set_property(TARGET my_target PROPERTY CXX_STANDARD 17)
set_property(TARGET my_target PROPERTY CXX_STANDARD_REQUIRED ON)
Related