【问题标题】:How to get CMake to pass either std=c++14/c++1y or c++17/c++1z based on GCC version?如何让 CMake 基于 GCC 版本通过 std=c++14/c++1y 或 c++17/c++1z?
【发布时间】:2017-08-07 16:08:32
【问题描述】:

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

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

【问题讨论】:

  • “也许C++11也有类似的问题。” 那就是c++11 vs c++0x,前者是在gcc4.7/中引入的8个左右。
  • 顺便说一句,即使在支持现代编译器的编译器上,旧开关(0x、1y、1z)也能正常工作,因此没有真正需要让这个“正确” "。
  • 这里需要得到这个“正确”,因为传递原始编译器标志是 CMake 反模式并且违反元构建系统/构建的整个概念系统生成器。

标签: c++ cmake c++14 gcc4


【解决方案1】:

当想要指定特定的 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 应根据编译器支持的内容为请求的 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_STANDARDCXX_EXTENSIONS 都会受到尊重。

【讨论】:

    【解决方案2】:

    现代 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 文档中的要求语言标准部分了解更多信息。

    【讨论】:

    • 什么是“构建要求”而不是“使用要求”?
    • 还应该强调的是,对 cxx_std_YY 元功能的支持也仅在 CMake 3.8 中添加,而 CXX_STANDARD 目标属性系列的存在时间更长,cxx_std_YY 元功能单独不控制是否可以使用编译器扩展。
    • @einpoklum 如答案中所用,build requirements 指的是构建目标本身所需的东西,而 usage requirements 是任何链接的东西针对目标将作为要求继承。
    • @einpoklum 我应该使用official documentation 中使用的术语构建规范使用要求。克雷格斯科特已经正确解释了它。另一个很好的解释可以在 Daniel Pfeifer 的演讲 Effective CMake 中找到。我强烈建议观看链接的视频。
    【解决方案3】:

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

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

    【讨论】:

    • @einpoklum 没有猜测,我已经使用这个确切的代码几年了,没有问题。同时使用 GCC 和 Clang(我上次尝试不支持 -std=c++17 选项)。
    • 当 CMake 提供您想要的一切时,为什么还要维护自己的代码?
    • @usr1234567 向后兼容旧版本的 CMake,它没有新 C++ 标准的标志和设置。
    猜你喜欢
    • 2015-05-03
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-07
    • 2021-12-02
    相关资源
    最近更新 更多