如何在CMake中启用C++ 11?

416

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


15
"SET(CMAKE_CXX_FLAGS "-std=c++0x")" 对我来说运行良好,因此 CMakeLists 文件中可能存在其它问题。确保您不会在后续过程中意外覆盖 CMAKE_CXX_FLAGS 的内容。 - ComicSansMS
9
在使用CMake 2.8.8时,add_definitions(-std=c++11)对我有效。 - kyku
@ComicSansMS:你说得对!我覆盖了它,这是我的错误。我已经纠正了它,现在它运行得很好!C++11的东西非常酷!我想循环遍历一个结构体向量,这需要迭代器和不必要的编码噪音,如果我没有范围基于for循环。虽然我猜我可以使用BOOST_FOREACH,但是算了... - Subhamoy S.
44
对于 CMake ≥3.1,set(CMAKE_CXX_STANDARD 11)(在定义目标之前)是最好的方法。 - emlai
2
@tuple_cat 你也可以基于目标进行操作。但是请注意,CXX_STANDARD 在 MSVC 上不起作用,因此如果您想要跨平台的功能,基本上必须退回到 target_compile_features - Ela782
2
关于CMake的问题在SO上很快就会过时。在2020年,您绝对不应该在CMakeLists.txt中纠结编译器标志来做这件事。如果您只想使用C++11、14等构建,请参见MateuszL的答案。如果您还希望具有传播行为(即,您的库的用户必须使用该C++版本进行编译),请参见eyelash的答案 - Alex Reinking
17个回答

5

如果你想始终激活最新的C++标准,这里是我对David Grayson的答案进行的扩展,考虑到最近(CMake 3.8和CMake 3.11)添加了17和20的值用于CMAKE_CXX_STANDARD:

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)的位置即可。


4
我的做法是在CMakeLists.txt中设置以下行:
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

设置该命令会为编译器启用C++11功能,在执行cmake ..命令后,您应该能够在您的代码中使用基于范围的for循环并且编译它时不会出现任何错误。


1
如果你确切地想要-std=c++11,那么这最终是最好的答案,因为set (CMAKE_CXX_STANDARD 11)将使用-std=gnu++11标志,可能是不理想的。 - Antonio
2
@Antonio set (CMAKE_CXX_EXTENSIONS OFF) => @安东尼奥 set (CMAKE_CXX_EXTENSIONS OFF) - mloskot

2

我认为这两行足够了。

set(CMAKE_CXX_STANDARD 11)

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

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

2
现代方法是使用以下方式指定对 C++11 的最低要求标准:

target_compile_features(foo PUBLIC cxx_std_11)

这样做:
  • CMake可以遵循编译器的默认C++标准,如果它大于C++11
  • 您可以明确指定C++标准是否在构建时间、消耗时间或两者都需要。这对于库非常有用。
  • 公共编译特性会传递到下游目标,因此即使它们不直接使用此特性,这些目标也会免费获得该特性。
  • 用户可以使用CMAKE_CXX_STANDARD从命令行或CMake预设外部设置另一个C++标准(更近期的标准)。如果您在CMakeLists中硬编码了CMAKE_CXX_STANDARD,没有人可以在不编辑您的CMakeLists的情况下覆盖C++标准,这不太好。
需要CMake >= 3.8

2
如果你在使用cmake时遇到了同样的错误,你需要设置。
set (CMAKE_CXX_STANDARD 11)

要启用线程,因为它仅支持从c++11 ++开始

希望这有所帮助


0
您可以使用以下内容。这将根据您的环境自动修改功能。
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

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


-6

与 OS X 和 Homebrew LLVM 相关:

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

否则,CMake 将在第一行之前隐式插入 project(),导致 Clang 版本检测和可能出现其他问题。这里有一个 相关问题


2
问题并非特定于OSX或LLVM。此外,没有理由要求C++11开发需要CMake v3.x。至于clang版本检测-这不是OP所问的。 - einpoklum

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