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


356

当我尝试运行CMake生成的makefile来编译程序时,出现以下错误:

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

我尝试添加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功能。


11
SET(CMAKE_CXX_FLAGS "-std=c++0x")工程对我来说很好,因此CMakeLists文件中的其他地方可能存在问题。确保以后不要意外覆盖CMAKE_CXX_FLAGS的内容。
ComicSansMS 2012年

7
add_definitions(-std = c ++ 11)对我来说适用于CMake 2.8.8
kyku 2012年

@ComicSansMS:您完全正确!我重写了,这是我自己的错误。我已更正它,现在它工作正常!C ++ 11的东西非常酷!我想在结构的向量上循环,如果我没有基于范围的循环,则需要迭代器和不必要的编码噪声。我想我可以使用BOOST_FOREACH,但是好吧……
Subhamoy S.

32
对于CMake≥3.1,set(CMAKE_CXX_STANDARD 11)(在定义目标之前)是最佳方法。
emlai 2015年

@tuple_cat您也可以基于目标。但要知道,CXX_STANDARD上MSVC的工作,所以基本上你必须退回到target_compile_features,如果你想要的东西,跨平台工作。
Ela782

Answers:


395

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,但将其扩展到其他编译器应该很简单。

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

针对面向macOS的Clang用户的CMake问题#15943

如果您使用CMake和clang定位macOS,则存在一个错误,该错误可能导致该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 ()

12
这应该是公认的答案。它不需要单独触摸每个目标的属性,并且可以跨平台工作。
DevSolar

4
同意,从CMake 3.1+开始,这应该是公认的答案。在Mac上,它似乎对我不起作用。您可以使用--stdlib = libc ++(在Mac上默认为它)强制使用--std = c ++ 11。相反,如果受支持,则CMAKE_CXX_STANDARD始终包含gnu扩展,并且结果似乎不是针对--stdlib = libc ++构建的。相反,您必须切换到gnu的--stdlib = libstdc ++。Mac是特例。对于Linux,通常将gnu ++ 11与libstdc ++一起使用。当然,可以使用if(APPLE)add_compile_options()很容易地纠正这些错误,以添加标记。
Atifm '16

2
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}")
安东尼奥(Antonio)

2
在macOS(CMake 3.9.4,homebrew-clang)上对我不起作用。拯救别人的绝望。不知道为什么它适用于@EvanMoran,但不适用于我。
Unapiedra

2
@Unapiedra:这是一个CMake错误,但是您可以解决它,请参阅gitlab.kitware.com/cmake/cmake/issues/15943
David Grayson

186

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 ++程序使用以外的其他C ++功能cxx_range_for。CMake全局属性CMAKE_CXX_KNOWN_FEATURES列出了可以选择的C ++功能。

除了使用之外,target_compile_features()还可以通过设置CMake属性CXX_STANDARDCXX_STANDARD_REQUIREDCMake目标来显式指定C ++标准 。

另请参阅我的更详细的答案


4
看来今天的编辑具有误导性。CMake 3.0.0不包含target_compile_features。如我错了请纠正我。我认为该命令仅出现在CMake的夜间版本中。
ErikSjölund2014年

4
我会说这是最准确的答案
米哈尔Walenciak

8
我认为这是应该做的。其他答案只是手动添加标志,因此引入了不兼容性。但是,这似乎仅适用于CMake 3.1+
UliKöhler'15

2
@UliKöhler实际上仍然不可用,对于3.2中的某些编译器可能会出现。短期不要使用此方法;它完全不便携。
2015年

2
任何想法如何在CMake 2.6中做到这一点?
nuzzolilo 2015年

93

我在用

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++版本。


4
对我来说,这是对这个问题的唯一正确且不错的答案,在最近使用g ++的Linux上,当前(推出)了cmake。
Patrick B.

1
复制并粘贴此文件,效果很好。我正在使用CMAKE 2.8.9在Cygwin上。我知道我在这里阅读的大多数方法,因为我遵循CMAKE邮件列表,并且已将WebKit移植到各种编译器。我们为WebKit端口所做的是安装CMake 2.8.12。但是,因为我知道Cygwin的CMAKE很旧,所以我想要一些适用于该版本的东西。(抱歉,未将WebKit移植到Cygwin)
卡迪夫太空人

太好了,这是旧版CMake和g ++ 4.6(以及面向未来的版本)的插件。我也赞成CXX_STANDARD基于答案的答案,但这是对我而言唯一有用的答案。
Tomasz Gandor

这正是我一直在寻找的东西,但是尚不清楚使用该模块所需的最低cmake版本是什么。cmake --help-module对此没有多大帮助。
2015年

1
@JanSegre该模块首次出现在2.4中,cmake.org /…
KoKuToru 2015年

57

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

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

有关更多详细信息,请参见CMake文档


2
是的,这绝对是现代CMake(3.1+)中最好的方法之一
埃尔伯特斯

14
或者,您可以set(CMAKE_CXX_STANDARD 11)为之后创建的所有目标定义默认属性。
emlai 2015年

1
如果要在不同的目标上设置不同的C ++标准,这也是您需要的解决方案,因为set@emlai建议的命令是全局命令,会影响所有后续目标。
艾略特·斯劳特

40

事实证明,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")

36
我总是只使用:SET(CMAKE_CXX_FLAGS“ $ {CMAKE_CXX_FLAGS -std = c ++ 11”)#gcc> = 4.7,或c ++ 0x 4.6
David Doria 2012年

我曾经为此做过一个小脚本(虽然没有完成):github.com/Morwenn/POLDER/blob/master/cmake/set_cxx_norm.cmake
Morwenn 2013年

9
-1。如果从命令行指定任何CMAKE_CXX_FLAGS,则第二种方法将在build命令中产生一个分号(并重复两次原始CMAKE_CXX_FLAGS)。
Nikolai

:代替手动添加-g标志应设置CMAKE_BUILD_TYPE变量调试voices.canonical.com/jussi.pakkanen/2013/03/26/...
bames53

1
CXX_STANDARD属性更好,因为它与编译器无关。
jaskmar


19

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

target_compile_features(target PUBLIC cxx_std_11)

1
这是最新版本的CMake推荐的方式
camino

PUBLIC这里的功能是什么?
Rotsiser Mho

2
@RotsiserMho PUBLIC意味着依赖于您的目标的其他目标也将使用C ++ 11。例如,如果您的目标是一个库,则所有与您的库链接的目标target_link_libraries都将使用C ++ 11支持进行编译。
睫毛

17

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

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

我遇到了仅此方法有效而其他方法失败的实例。也许与最新版本的CMake有关。


9
仅当您仅使用C ++编译器时,这才起作用。如果您还使用CC编译器,它将失败。
伊曼纽尔

5
add_definitions仅应用于添加定义,即-D SOMETHING。正如@Emmanuel所说,它在许多情况下都不起作用。
xuhdev 2014年

我以前用过,但是在包含C文件时遇到了问题,因为add_definitions它不是为设置标志而创建的。
2015年

17

在现代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开始,这仍然是恕我直言的最佳方法。

来源:在CMake中启用C ++ 11及更高版本


1
如果您没有最新的CMake,则这种方式对于最新版本的C ++并不理想。例如,直到CMake 3.12,您才能以这种方式启用C ++ 2a。
Ruslan

6

对我有用的是在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)将使用flag -std=gnu++11,这可能是不希望的。
安东尼奥

1
@安东尼奥set (CMAKE_CXX_EXTENSIONS OFF)
mloskot

3

我认为仅这两行就足够了。

set(CMAKE_CXX_STANDARD 11)

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

1
当项目中的所有目标都使用相同的C ++标准(例如,所有编译的库和可执行文件都使用C ++ 11)时,这才有意义。否则,target_compile_features如其他答案所示,将Cmake 函数应用于每个单独的目标是一种更推荐的方法。
艾伦(Allan)'18年

3

如果您想始终激活最新的C ++标准,这是我对David Grayson的回答的扩展,因为最近(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)在链接的答案中使用该代码。)


1

现代cmake提供了更简单的方法来配置编译器以使用特定版本的C ++。任何人唯一要做的就是设置相关的目标属性。在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
    )

-5

OS X和Homebrew LLVM相关:

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

否则CMake将project()在第1行之前隐式插入,从而导致Clang版本检测出现问题,并可能引起其他类型的麻烦。这是一个相关的问题


2
具体来说,该问题与OSX或LVVM不相关。同样,没有理由要求Cake 11开发使用CMakev3.x。至于c版本检测-这不是OP要求的。
einpoklum 2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.