ChatGPT解决这个技术问题 Extra ChatGPT

如何在 CMake 中激活 C++ 11?

当我尝试运行 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

D
David Grayson

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 或更高版本,或

在项目命令之前,使用 CMakeLists.txt 文件顶部的以下代码将策略 CMP0025 设置为 NEW:# Fix CMAKE_CXX_STANDARD 在针对 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
C
Community

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 目标设置 CMake 属性 CXX_STANDARDCXX_STANDARD_REQUIRED 来明确指定 C++ 标准。

另见my more detailed answer


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

我在用

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++11 一起玩,g++ 4.6.1 已经很老了。尝试获取更新的 g++ 版本。


对我来说,这是对这个问题的唯一正确和好的答案,当前(推出的)cmake 在最新的 Linux 上使用 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/…
P
Peter Mortensen

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

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

有关详细信息,请参阅 the CMake documentation


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

事实证明,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 两次)。
而不是手动添加 -g 标志,您应该将 CMAKE_BUILD_TYPE 变量设置为调试:voices.canonical.com/jussi.pakkanen/2013/03/26/…
CXX_STANDARD 属性更好,因为它与编译器无关。
P
Peter Mortensen

在现代 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 之间但不是以上,则更喜欢 target_compile_options(project_name PRIVATE option1 ...)target_compile_definitions 或仍然是 target_compile_features(ao-project_name PRIVATE some_feature)
@Sandburg 为什么我更愿意分别为多个目标指定多个功能?您认为在单个项目中对不同的目标有不同的期望是很常见的吗?我知道这个功能,但老实说,当它作为主要方法是可取的时,我想不出单一用例。无论如何:根据链接的文章,它在 3.1 中工作
l
legends2k

对于 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 仍然存在,如果需要细粒度的设置)。
有没有办法设置 global/CMAKE_ 默认目标功能?或者这是否意味着我们必须为每个目标重复设置语言标准?
a
alvarez

最简单的方法:

add_compile_options(-std=c++11)


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

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

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

我遇到过只有这种方法有效而其他方法失败的情况。也许它与最新版本的 CMake 有关。


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

现代 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
    )

E
E_net4 - Mr Downvoter

如果您想始终激活最新的 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)。)


K
Kevin Katzke

对我有用的是在 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,这可能是不可取的。
@安东尼奥set (CMAKE_CXX_EXTENSIONS OFF)
P
Pang

我认为只有这两行就足够了。

set(CMAKE_CXX_STANDARD 11)

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

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

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

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

因此,您支持尽可能多的环境。


S
SpacePotatoes

现代方法是指定 C++11 所需的最低标准:

target_compile_features(foo PUBLIC cxx_std_11)

这边走:

如果 CMake 大于 C++11,则 CMake 可以遵循编译器的默认 C++ 标准

您可以清楚地指定在构建时、消耗时或两者都需要 C++ 标准。这对图书馆来说很好。

公共编译功能会传播到下游目标,因此即使它们不直接使用此功能,这些目标也会免费提供。

用户可以从命令行或 CMake 预设使用 CMAKE_CXX_STANDARD 从外部设置另一个 C++ 标准(基本上是更新的)。如果您在 CMakeLists 中硬编码 CMAKE_CXX_STANDARD,则没有人可以在不编辑您的 CMakeLists 的情况下覆盖 C++ 标准,这不是很愉快。

它需要 CMake >= 3.8


P
Peter Mortensen

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 所要求的。