41

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.)

Ela782
  • 5,041
  • 5
  • 53
  • 66
  • See https://gitlab.kitware.com/cmake/cmake/issues/16482, this is work in progress. – Florian Jul 07 '17 at 07:17
  • Update: `CMAKE_CXX_STANDARD 17` is now possible in the latest CMake nightly and will land in CMake-3.10. – Ela782 Aug 27 '17 at 14:53
  • @Ela782 As time has passed, could you consider accepting my answer instead, as I believe it's the more up-to-date one. – tambre Mar 24 '18 at 14:24
  • @tambre What's the SO policy on this? The accepted answer was the right one, at that time. On this particular instance I am inclined to agree with you and change the accepted answer. Any thoughts from @Florian? – Ela782 Mar 25 '18 at 15:50
  • @Ela782 It's perfectly acceptable that you (the asker) later on accept another answer. See [here](https://meta.stackoverflow.com/a/256595/2176813). – tambre Mar 25 '18 at 15:58
  • Add it right after project ```project(prj VERSION 0.0.1) set(CMAKE_CXX_STANDARD 17)``` – att Jan 30 '20 at 07:32

3 Answers3

27

Turning my comment into an answer

  1. The CMake team is working on it for VS2017 (as for July 2017, for upcoming CMake version 3.10):

    CMake: MSVC standard version switches

    Those flags seem to be rather new switches (as related to the date of this question):

    VS 2017 15.3 preview now supports /std:c++17

    So for Visual Studio you have to "manually" replace or append the compiler switches until CMake officially does support it.

    Here is a code snippet that I've tested for std:c++latest (which is already supported e.g. in my CMake 3.8.0 version):

    if (MSVC_VERSION GREATER_EQUAL "1900")
        include(CheckCXXCompilerFlag)
        CHECK_CXX_COMPILER_FLAG("/std:c++latest" _cpp_latest_flag_supported)
        if (_cpp_latest_flag_supported)
            add_compile_options("/std:c++latest")
        endif()
    endif()
    
  2. For CLang and GNU the support was merged into the main source code branch begin of 2017 and is part of CMake version 3.8 and above:

    CMake: Features: Add support for C++ 17 language standard

Florian
  • 39,996
  • 9
  • 133
  • 149
  • Hmm! Too bad that didn't land in CMake yet, the issue is 7 months old :-( (The flags are not really too new, VS2015 already had them). Anyway. Given I'm using above "modern" and target-based approach, what would be the best way to manually replace/add the flag for MSVC? – Ela782 Jul 07 '17 at 10:04
  • I think this is going to be a headache. I can't `get_target_property(my_compile_flags mylib COMPILE_FLAGS)` because it's an INTERFACE target (header-only library)... – Ela782 Jul 07 '17 at 18:43
  • I've asked this in a new question: https://stackoverflow.com/questions/44977868/cmake-replace-compile-flags-of-an-interface-target – Ela782 Jul 07 '17 at 18:55
  • @Ela782 Added a code snippet that should work as a global setting. Just don't put any `CMAKE_CXX_STANDARD` definition parallel to it (to avoid conflicts in the generated project file). – Florian Jul 07 '17 at 20:00
  • With `add_compile_options` we can pass whatever we want, so this is not actually interesting. Is there a way to set `/std:c++latest` in a portable way with e.g. `CMAKE_CXX_STANDARD`? – Mikhail Mar 24 '18 at 12:33
22

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)
tambre
  • 4,625
  • 4
  • 42
  • 55
  • Is there a way to set `/std:c++latest` with it? – Mikhail Mar 24 '18 at 12:29
  • 1
    @Mikhail No. Consensus [here](https://gitlab.kitware.com/cmake/cmake/issues/16608) seems to be to not add a `LATEST` value for `CXX_STANDARD`, but rather support each standard version separately. I've created [an issue](https://gitlab.kitware.com/cmake/cmake/issues/17849) for adding C++2a support. – tambre Mar 24 '18 at 14:23
  • 4
    @Mikhail Support for C++20 is now in [CMake nightlies](https://cmake.org/files/dev/?C=M;O=D). Mind trying out? – tambre Mar 29 '18 at 14:53
  • bit of an update, using CMake 3.14.3 and VS2019, all I had to do was `set(CMAKE_CXX_STANDARD 17)` in my CMakeLists.txt files – yano Dec 04 '21 at 21:10
0

You can add the following line to your CmakeLists.txt file

set(GCC_COMPILE_FLAGS "${GCC_COMPILE_FLAGS} /std:c++17")
Pedro77
  • 5,176
  • 7
  • 61
  • 91
Renju Ashokan
  • 428
  • 6
  • 18