如何让 CMake 根据 GCC 版本通过 std=c++14/c++1y 或 c++17/c++1z?

How to get CMake to pass either std=c++14/c++1y or c++17/c++1z based on GCC version?

GCC 4.x 不接受 C++14 代码的 --std=c++14 开关 - 它需要 --std=c++1y 代替。更高版本采用 --std=c++1z 但(可能)不是 --std=c++17 尚未设置(在 2016 年编写)。也许 C++11 也有类似的问题。

CMake 是否有一些工具(可能作为一个模块)根据 GCC 版本传递正确的开关?

检查编译器是否支持标志?也许像

include(CheckCXXCompilerFlag)

# Check for standard to use
check_cxx_compiler_flag(-std=c++17 HAVE_FLAG_STD_CXX17)
if(HAVE_FLAG_STD_CXX17)
    # Have -std=c++17, use it
else()
    check_cxx_compiler_flag(-std=c++1z HAVE_FLAG_STD_CXX1Z)
    if(HAVE_FLAG_STD_CXX1Z)
        # Have -std=c++1z, use it
    else()
        # And so on and on...
    endif()
endif()

当想要指定特定的 C++ 版本时,使用 CMake 3.1 及更高版本执行此操作的推荐方法是使用 CXX_STANDARDCXX_STANDARD_REQUIREDCXX_EXTENSIONS 目标属性,或者它们的变量等价物来指定目标默认值。可以找到完整的详细信息 here,但简短的版本是这样的:

cmake_minimum_required(VERSION 3.1)
project(Example)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# ... Define targets, etc. as usual

CMake 然后应该 select 根据编译器支持的内容为请求的 C++ 标准设置适当的编译器标志,或者如果它不支持请求的标准则出错。

还应注意,CMake 可能会升级目标以使用比其 CXX_STANDARD 目标 属性 指定的语言标准更新的语言标准。使用 compile feature requirements (如@FlorianWolters 回答中所述)可以提高语言标准要求。事实上,CMake 将始终选择由 CXX_STANDARD 目标 属性 或目标上设置的编译功能要求指定的更强的语言要求。另请注意,早期版本的 CMake 文档并未准确反映 CXX_EXTENSIONS 与编译功能交互的方式。对于 CMake 3.21 或更早版本,CXX_EXTENSIONS 仅在还指定了 CXX_STANDARD 时才会生效,对于大多数常见的编译器(因为它们与一个编译器标志一起指定)。从 CMake 3.22 开始,无论 CXX_STANDARD 是否设置,CXX_EXTENSIONS 都被尊重。

现代 CMake 代码应该使用 target_compile_features 命令来请求特定的 C++ 标准。这可以指定为仅构建要求 (PRIVATE)、仅使用要求 (INTERFACE) 或构建和使用要求 (PUBLIC)。

示例:

cmake_minimum_required(VERSION 3.9.4)

project(cpp-snippets)
add_executable(cpp-snippets "main.cpp")
target_compile_features(cpp-snippets PRIVATE cxx_std_17)

请参阅 cmake-compile-features 的官方 CMake 文档中的 需要语言标准 部分以了解更多信息。