如何在CMake中启用 C++17

132

我正在使用支持集成CMake 3.8的VS 15.3。如何在不为每个特定编译器编写标志的情况下针对C++17进行目标设置?我的当前全局设置不起作用:

# https://cmake.org/cmake/help/latest/prop_tgt/CXX_STANDARD.html
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# expected behaviour
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest")

我希望CMake在生成VS解决方案文件时添加"/std:c++latest"或相应的选项,但没有找到c++17标志,导致编译器错误:

C1189 #error: class template optional is only available with C++17.

1
通常情况下,CMake 不能消除为每个特定编译器编写标志的需要。 - user7860670
2
你所说的“VS 15.3”是指Visual Studio 2017预览版3吗?还是指Visual Studio 2015更新版3(它几乎不支持C++17)? - Some programmer dude
@Someprogrammerdude 我正在使用 std::optional 特性,如果我在 CMakeLists 中手动添加 "/std:c++lastest" 标志,则可以使用它。 - MiP
你需要向编译器传递标志。接受C++17的是编译器,而不是cmake - Basile Starynkevitch
1
它是最新的,不是laStest。 - Alexander Enaldiev
只是补充一下,发布的方法在 CMake 3.10 之后非常有效。 - fuzzyTew
9个回答

81

现代 CMake 提供了一个用于此目的的接口 target_compile_features。 相关文档可以在这里找到:要求语言标准

使用它就像这样:

target_compile_features(${TARGET_NAME} PRIVATE cxx_std_17)


@vitaut 你能解释一下为什么你把 ${PROJECT_NAME} 改成 ${TARGET_NAME} 吗? - nbout
在CMake中,“Project”有不同的含义:https://cmake.org/cmake/help/v3.0/command/project.html。`target_compile_features`适用于目标。 - vitaut
2
所以我为了清晰起见进行了更改。如有需要可以恢复原状。 - vitaut
2
我希望随着新的语言特性的推出,被接受的答案能够自动更新...这是正确的答案。以上的答案都非常过时。 - tjwrona1992
使用CMake 3.13和Visual 2017,我认为这个现代命令没有添加/std:c++17标志,但是set(CMAKE_CXX_STANDARD 17)确实可以...但只是将INTERFACE关键字改为PUBLIC就解决了。 - Sandburg
3
在CMake中,PUBLIC(对所有人)= INTERFACE(对其他人)+ PRIVATE(对我自己) - Sandburg

48

4
较新的CMake 3.10(及更高版本)文档称其支持Visual Studio 2015更新版3或更新的版本。仅不支持2015 更新版3之前的Visual Studio版本。上面的链接实际上指向最新文档,其中有相关说明。 - Marcus10110
1
@Marcus10110 没错,已将链接更改为指向3.9文档,并添加了关于新版本已修复的说明。谢谢。 - Some programmer dude
4
可能有点学究气的评论:为了让MSVC表现得像一个符合规范的编译器,你还需要使用/Zc:__cplusplus标志,因为否则__cplusplus宏的值不会被设置为正确的值。毫无疑问,我认为这是cmake中的一个bug:当我请求C++11、C+14、C++17时,我希望cmake设置所有必要的标志,以使编译器符合规范,这包括__cplusplus宏的值。 - tobi_s

34
在现代 CMake 中,我发现将 CXX 标准分配给目标(而不是全局变量级别),并使用内置属性(在此处查看:https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html)以保持编译器无关性是最佳实践。
例如:
set_target_properties(FooTarget PROPERTIES
            CXX_STANDARD 17
            CXX_EXTENSIONS OFF
            etc..
            )

根据文档,CXX_STANDARD_REQUIRED 是一个布尔值。https://cmake.org/cmake/help/v3.10/prop_tgt/CXX_STANDARD_REQUIRED.html - Brent
5
“现代”CMake的确切含义是什么? - ar2015
22
似乎每个 CMake 特性都会迅速过时,因此网络上充满了过时的问题和答案。 - zwcloud
"Craig Scott在他的书中描述了现代CMake。一路上已经进行了许多重新思考,这导致脚本更加专注于抽象目标,而不是硬塞编译器标志等。在此处查看他的书:https://crascit.com/professional-cmake/" - Den-Jason

30

对于诸如Clang和GCC之类的其他编译器,您可以保留set(CMAKE_CXX_STANDARD 17)。但是对于Visual Studio来说,这是无用的。

如果CMake仍不支持此功能,则可以针对Visual Studio执行以下操作:

if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17")
endif(MSVC)

编辑:由于问题标题没有提到编译器,所以让我补充一下,对于gccclang和类似的编译器,这是启用C++17的命令:

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

3
最近的VS更改允许使用/std:c++14/std:c++17/std:c++latest标志来设置标准。 - user7860670
2
在我的情况下则相反。我使用的是CMake 3.19.1、VS2019和gcc 7.5.0。 set(CMAKE_CXX_STANDARD 17) 对于VS2019来说已经足够了,但是对于gcc来说需要 target_compile_features(${TARGET_NAME} PRIVATE cxx_std_17)。即使是显式的 add_compile_options("-std=gnu++17") 也不够用。 - olepinto

17

在使用 VS2019

set(CMAKE_CXX_STANDARD 17)

它正在运行。谢谢。 - Behrouz.M

5

CMake标志中的Bash命令行:

-DCMAKE_CXX_STANDARD=17 \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
-DCMAKE_CXX_EXTENSIONS=OFF \

3

根据我的测试,以下代码将使VS2019选择/std:c++latest,否则将为其他平台设置C++版本为C++17。我已在emscripten、raspbian和windows上进行了测试。

if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest")
else(MSVC)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17)
endif(MSVC)

2
尽管这段代码可以回答问题,但提供关于它如何或为什么解决问题的额外背景信息会提高答案的长期价值。 - Donald Duck
请注意,该语句存在一些错误。根据cmake文档cxx_std_17特性表示“至少C++17”。因此,它实际上类似于/std:c++latest,只是它确保您不会使用旧版本进行编译(如果没有新版本可用,则cmake会失败)。 - Alexis Wilke

2

您还可以使用target_compile_options为Visual Studio 2019设置/std:c++latest标志。

if (MSVC_VERSION GREATER_EQUAL "1900")
    include(CheckCXXCompilerFlag)
    CHECK_CXX_COMPILER_FLAG("/std:c++latest" _cpp_latest_flag_supported)
    if (_cpp_latest_flag_supported)
        target_compile_options(${TARGET_NAME} PRIVATE "/std:c++latest")
    endif()
endif()

${TARGET_NAME}替换为实际的目标名称。


0
我来到这里是为了找到使用CMAKE启用标准C++17的正确标志。 我不使用MSVS,而是gcc。所以,我希望这对其他人有所帮助。
具体来说,我正在使用CMAKE v3.22.0和g++ v11.2.0。
通过在CMakeLists.txt文件中包含以下行,我可以获得所需的选项-std=c++17:
set(CMAKE_CXX_STANDARD 17 CACHE STRING "v")
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_EXTENSIONS OFF)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON) #Optional

如果省略了set(CMAKE_CXX_EXTENSIONS OFF),则会使用-std=gnu++17代替! 最后一行是可选的,但检查标志非常有用。

这个问题是关于MSVC的,所以我认为这并不相关。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接