【问题标题】:How do I activate C++ 11 in CMake?如何在 CMake 中激活 C++ 11?
【发布时间】:2012-06-06 18:02:48
【问题描述】:

当我尝试运行 CMake 生成的 makefile 来编译我的程序时,我得到了错误

C++ 98 模式不支持基于范围的 for 循环。

我尝试将add_definitions(-std=c++0x) 添加到我的CMakeLists.txt,但没有帮助。

我也试过这个:

if(CMAKE_COMPILER_IS_GNUCXX)
    add_definitions(-std=gnu++0x)
endif()

当我执行g++ --version 时,我得到:

g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

我也试过SET(CMAKE_CXX_FLAGS "-std=c++0x"),还是不行。

我不明白如何使用 CMake 激活 C++ 11 功能。

【问题讨论】:

  • SET(CMAKE_CXX_FLAGS "-std=c++0x") 对我来说很好用,所以 CMakeLists 文件中的其他地方可能存在问题。确保以后不会意外覆盖 CMAKE_CXX_FLAGS 的内容。
  • add_definitions(-std=c++11) 适用于 CMake 2.8.8
  • 对于 CMake ≥3.1,set(CMAKE_CXX_STANDARD 11)(在定义目标之前)是最好的方法。
  • @tuple_cat 你也可以基于目标来做。但请注意,CXX_STANDARD在 MSVC 上工作,所以基本上如果你想要跨平台工作的东西,你必须回退到 target_compile_features
  • 关于 CMake 的问题在 SO 上很快就会过时 very。在 2020 年,您绝对不应该摆弄 CMakeLists.txt 中的编译器标志来执行此操作。如果您只想使用 C++11、14 等进行构建,请参阅MateuszL's answer。如果您还需要传播行为(即您的库的用户必须使用该 C++ 版本编译),请参阅eyelash's answer

标签: c++11 cmake


【解决方案1】:

CMake 3.1 引入了您可以使用的CMAKE_CXX_STANDARD 变量。如果您知道 CMake 3.1 或更高版本始终可用,您可以将其写入顶级 CMakeLists.txt 文件,或将其放在定义任何新目标之前:

set (CMAKE_CXX_STANDARD 11)

如果你需要支持旧版本的 CMake,我想出一个宏供你使用:

macro(use_cxx11)
  if (CMAKE_VERSION VERSION_LESS "3.1")
    if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
      set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
    endif ()
  else ()
    set (CMAKE_CXX_STANDARD 11)
  endif ()
endmacro(use_cxx11)

该宏目前仅支持 GCC,但应该可以直接将其扩展到其他编译器。

然后您可以在任何定义使用 C++11 的目标的 CMakeLists.txt 文件的顶部写 use_cxx11()

针对 macOS 的 clang 用户的 CMake 问题 #15943

如果您使用 CMake 和 clang 来定位 macOS,则有一个 bug 可能导致 CMAKE_CXX_STANDARD 功能根本不起作用(不添加任何编译器标志)。确保您执行以下操作之一:

  • 使用cmake_minimum_required 要求 CMake 3.0 或更高版本,或者

  • project 命令之前,在您的 CMakeLists.txt 文件顶部使用以下代码将策略 CMP0025 设置为 NEW:

      # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS.
      if (POLICY CMP0025)
        cmake_policy(SET CMP0025 NEW)
      endif ()
    

【讨论】:

  • 这应该是公认的答案。它不需要单独触摸每个目标的属性,并且可以跨平台工作。
  • 同意,这应该是 CMake 3.1+ 的公认答案。不过,它似乎对我在 mac 上不起作用。您可以强制它为您提供 --std=c++11 和 --stdlib=libc++,这是 Mac 上的默认设置。相反,如果支持,CMAKE_CXX_STANDARD 总是包含 gnu 扩展,并且结果似乎不是针对 --stdlib=libc++ 构建的。相反,您必须切换到 gnu 的 --stdlib=libstdc++。 Mac 是个特例。对于 Linux,选择 gnu++11 和 libstdc++ 是常态。当然,这很容易用 if(APPLE) add_compile_options() 来修正标志。
  • 这种方法的一个问题是gnu++11被强制执行,即使这些变量是定义set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang)set(CMAKE_ANDROID_STL_TYPE c++_static)。对我来说唯一可行的方法是经典的set (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
  • 在 macOS 上对我不起作用(CMake 3.9.4,homebrew-clang)。拯救别人的绝望。不知道为什么它适用于@EvanMoran 但不适用于我。
  • @Unapiedra:这是一个 CMake 错误,但您可以解决它,请参阅 gitlab.kitware.com/cmake/cmake/issues/15943
【解决方案2】:

CMake 命令target_compile_features() 用于指定所需的C++ 功能cxx_range_for。然后 CMake 将诱导使用 C++ 标准。

cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
project(foobar CXX)
add_executable(foobar main.cc)
target_compile_features(foobar PRIVATE cxx_range_for)

无需使用 add_definitions(-std=c++11) 或修改 CMake 变量 CMAKE_CXX_FLAGS,因为 CMake 会确保使用适当的命令调用 C++ 编译器行标志。

也许您的 C++ 程序使用了除 cxx_range_for 之外的其他 C++ 功能。 CMake 全局属性 CMAKE_CXX_KNOWN_FEATURES 列出了您可以选择的 C++ 功能。

除了使用target_compile_features(),您还可以通过设置 CMake 属性显式指定 C++ 标准 CXX_STANDARDCXX_STANDARD_REQUIRED 用于您的 CMake 目标。

另见my more detailed answer

【讨论】:

  • 今天的编辑似乎具有误导性。 CMake 3.0.0 不包含 target_compile_features。如果我错了纠正我。我认为该命令仅存在于 CMake 的夜间版本中。
  • 我会说这是最准确的答案
  • 我认为这是应该的。其他答案只是手动添加标志,因此引入了不兼容性。然而,这似乎只在 CMake 3.1+ 中可用
  • @UliKöhler 这实际上仍然不可用,并且可能出现在 3.2 中的某些编译器。短期内不要使用这种方法;它完全不便携。
  • 知道如何在 CMake 2.6 中执行此操作吗?
【解决方案3】:

我正在使用

include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
        message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

但是如果你想玩C++11g++ 4.6.1 已经很老了。 尝试获取更新的g++ 版本。

【讨论】:

  • 复制并粘贴它,它工作得很好。我在 Cygwin 上使用 CMAKE 2.8.9。我知道我在这里阅读的大多数方法,因为我遵循 CMAKE 邮件列表,并且我已经将 WebKit 移植到各种编译器。我们为 WebKit 端口所做的事情是安装 CMake 2.8.12。但是因为我知道 Cygwin 的 CMAKE 很旧,所以我想要一些适用于那个版本的东西。 (没有将 WebKit 移植到 Cygwin,抱歉)
  • 太棒了,这是旧 CMake 和 g++ 4.6(以及面向未来)的插件。我还赞成基于CXX_STANDARD 的答案,但这是对我的情况有用的唯一答案。
  • 这正是我一直在寻找的,但尚不清楚使用该模块所需的最低 cmake 版本是多少。 cmake --help-module 对此没有多大帮助。
  • @JanSegre 该模块首次出现在 2.4,cmake.org/…
【解决方案4】:

设置 Cxx 标准最简单的方法是:

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

更多详情请见the CMake documentation

【讨论】:

  • 是的,这绝对是现代 CMake (3.1+) 中最好的方法之一
  • 或者您也可以set(CMAKE_CXX_STANDARD 11) 为之后创建的所有目标定义默认属性。
  • 如果您想在不同的目标上设置不同的C++标准,这也是您需要的解决方案,因为@emlai建议的set命令是全局的,会影响所有后续目标。
【解决方案5】:

事实证明,SET(CMAKE_CXX_FLAGS "-std=c++0x") 确实激活了许多 C++11 功能。它不起作用的原因是该语句看起来像这样:

set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")

按照这种方法,不知何故 -std=c++0x 标志被覆盖,它不起作用。一个一个地设置标志或使用列表的方法是有效的。

list( APPEND CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")

【讨论】:

  • 我总是只使用: SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # for gcc >= 4.7, or c++0x for 4.6
  • 我曾经为此做了一个小脚本(虽然不完整):github.com/Morwenn/POLDER/blob/master/cmake/set_cxx_norm.cmake
  • -1。如果您从命令行指定任何 CMAKE_CXX_FLAGS,则第二种方法将在构建命令中生成一个分号(并重复原始 CMAKE_CXX_FLAGS 两次)。
  • 您应该将 CMAKE_BUILD_TYPE 变量设置为调试,而不是手动添加 -g 标志:voices.canonical.com/jussi.pakkanen/2013/03/26/…
  • CXX_STANDARD 属性更好,因为它与编译器无关。
【解决方案6】:

在现代 CMake (>= 3.1) 上,设置全局要求的最佳方式是:

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

它翻译为“我希望所有目标都使用 C++11,它不是可选的,我不想使用任何 GNU 或 Microsoft 扩展。” 从 C++17 开始,恕我直言,这仍然是最好的方法。

来源:Enabling C++11 And Later In CMake

【讨论】:

  • 如果你没有最新的 CMake,这种方式不适合最新版本的 C++。例如。在 CMake 3.12 之前,您无法以这种方式启用 C++2a。
  • 不过,没有理由不拥有最新的 CMake。 Chocolatey、Homebrew 和 Snap 都有最新的软件包。
  • 请注意,这些必须在定义任何目标之前设置;不这样做会导致仅在将目标设置为受到影响后定义目标。这是可以理解的,因为它们是默认值。
  • 在“更现代的 cmake = 3.12”中不再存在...如果您的目标介于 C++11 和 C++17 之间但不是以上。
  • @Sandburg 为什么我更愿意分别为多个目标指定多个功能?您认为在单个项目中对不同的目标有不同的期望是很常见的吗?我知道这个功能,但老实说,当它作为主要方法是可取的时,我想不出单一用例。无论如何:根据链接的文章,它在 3.1 中工作
【解决方案7】:

对于 CMake 3.8 及更高版本,您可以使用

target_compile_features(target PUBLIC cxx_std_11)

如果您希望在工具链无法遵守此标准的情况下使生成步骤失败,您可以将其设为必需。

set_target_properties(target PROPERTIES CXX_STANDARD_REQUIRED ON)

如果您想严格遵守标准 C++,即避免编译器提供的 C++ 扩展(如 GCC 的 -std=gnu++17),另外设置

set_target_properties(target PROPERTIES CXX_EXTENSIONS OFF)

这在An Introduction to Modern CMake -> 添加功能 -> C++11 及更高版本中有详细记录。如果您受到限制,它还提供了有关如何在旧版本的 CMake 上实现这一点的建议。

【讨论】:

  • 这是最新版CMake推荐的方式
  • 这里PUBLIC的作用是什么?
  • @RotsiserMho PUBLIC 表示其他依赖于您的目标的目标也将使用 C++11。例如,如果您的目标是一个库,那么所有使用 target_link_libraries 链接到您的库的目标都将使用 C++11 支持进行编译。
  • 到目前为止,这在技术上是定义标准版本的最佳方式,应该是公认的答案(尽管 Erik 仍然存在,但如果需要细粒度的设置)。
【解决方案8】:

最简单的方法:

add_compile_options(-std=c++11)

【讨论】:

  • 仅适用于 cmake 3.0
  • 这会导致在同一个项目中编译 C 文件时出现警告和错误。
  • 绝对不要这样做。它将破坏编译纯 C 程序。它将您的 CMakeLists.txt 粘合到特定的编译器,并且无论如何都有内置支持。
  • 这对于 Visual Studio 编译器来说会失败。请参阅我的答案以获得适用于所有编译器的更好答案:stackoverflow.com/a/69804542/7910299
【解决方案9】:

这是启用 C++11 支持的另一种方式,

ADD_DEFINITIONS(
    -std=c++11 # Or -std=c++0x
    # Other flags
)

我遇到过只有这种方法有效而其他方法失败的情况。可能跟最新版本的 CMake 有关系。

【讨论】:

  • 只有在你只使用 C++ 编译器时才有效。如果您还使用 CC 编译器,它将失败。
  • add_definitions 只应该用于添加定义,即 -D Something。正如@Emmanuel 所说,它在很多情况下都不起作用。
  • 我以前用过,但是当我包含一个 C 文件时遇到了问题,因为 add_definitions 不是用于设置标志的。
【解决方案10】:

现代 cmake 提供了更简单的方法来配置编译器以使用特定版本的 C++。任何人唯一需要做的就是设置相关的目标属性。在properties supported by cmake 中,用于确定如何配置编译器以支持特定版本的C++ 的有:

  • CXX_STANDARD 设置 C++ 标准,其功能需要构建目标。将此设置为 11 以针对 C++11。

  • CXX_EXTENSIONS,一个布尔值,指定是否请求编译器特定的扩展。将此设置为 Off 会禁用对任何编译器特定扩展的支持。

为了演示,这里是一个CMakeLists.txt 的最小工作示例。

cmake_minimum_required(VERSION 3.1)

project(testproject LANGUAGES CXX )

set(testproject_SOURCES
    main.c++
    )

add_executable(testproject ${testproject_SOURCES})

set_target_properties(testproject
    PROPERTIES
    CXX_STANDARD 11
    CXX_EXTENSIONS off
    )

【讨论】:

    【解决方案11】:

    如果您想始终激活最新的 C++ 标准,这里是我对David Grayson's answer 的扩展,鉴于最近(CMake 3.8 和 CMake 3.11)为 CMAKE_CXX_STANDARD 添加了值 17 和 20):

    IF (CMAKE_VERSION VERSION_LESS "3.8")
        SET(CMAKE_CXX_STANDARD 14)
    ELSEIF (CMAKE_VERSION VERSION_LESS "3.11")
        SET(CMAKE_CXX_STANDARD 17)
    ELSE()
        SET(CMAKE_CXX_STANDARD 20)
    ENDIF()
    
    # Typically, you'll also want to turn off compiler-specific extensions:
    SET(CMAKE_CXX_EXTENSIONS OFF)
    

    (使用该代码代替链接答案中的set (CMAKE_CXX_STANDARD 11)。)

    【讨论】:

      【解决方案12】:

      对我有用的是在您的 CMakeLists.txt 中设置以下行:

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

      设置此命令会激活编译器的 C++11 功能,在执行 cmake .. 命令后,您应该能够在代码中使用 range based for loops 并编译它而不会出现任何错误。

      【讨论】:

      • 如果您完全想要-std=c++11,这最终是最好的答案,因为set (CMAKE_CXX_STANDARD 11) 将使用标志-std=gnu++11,这可能是不可取的。
      • @Antonio set (CMAKE_CXX_EXTENSIONS OFF)
      【解决方案13】:

      我觉得这两行就够了。

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

      【讨论】:

      • 当项目中的所有目标都使用相同的 C++ 标准(例如,所有编译的库和可执行文件都使用 C++11)时,这是有意义的。否则,如其他答案所示,应用于每个单独目标的 Cmake target_compile_features 函数是更推荐的方法。
      • 鉴于第一行绝对不需要第二行,它只会在兼容编译器上添加一个冗余标志并破坏其他编译器(如 MSVC)的构建。
      【解决方案14】:

      您可以使用以下内容。这会根据您的环境自动修改功能。

      target_compile_features(your_target INTERFACE cxx_std_20)
      

      例如,

      • 在 Gnu/Linux 上,以下添加 -std=gnu++20
      • 在带有 Clang/Ninja 的 Windows 上,它变为 -std=c++20
      • 在带有 MSVC 的 Windows 上,它变为 /std=c++20

      所以你支持尽可能多的环境。

      【讨论】:

        【解决方案15】:

        OS X 和 Homebrew LLVM 相关:

        不要忘记在它之后调用 cmake_minimum_required(VERSION 3.3) 和 project()!

        或者 CMake 会在第 1 行之前隐式插入 project(),从而导致 Clang 版本检测出现问题并可能出现其他类型的问题。这里是a related issue

        【讨论】:

        • 这个问题与 OSX 或 LVVM 无关,特别是。此外,没有理由要求 CMake v3.x 进行 C++11 开发。至于 clang 版本检测 - 这不是 OP 所问的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-12
        • 2022-09-28
        • 1970-01-01
        • 2018-05-13
        • 1970-01-01
        相关资源
        最近更新 更多