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

Sub*_* S. 349 cmake c++11

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

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

我尝试添加add_definitions(-std=c++0x)到我的CMakeLists.txt,但它没有帮助.我也试过这个:

if(CMAKE_COMPILER_IS_GNUCXX)
    add_definitions(-std=gnu++0x)
endif()
Run Code Online (Sandbox Code Playgroud)

当我这样做时g++ --version,我得到:

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

我也试过SET(CMAKE_CXX_FLAGS "-std=c++0x"),这也行不通.

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

Dav*_*son 378

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

set (CMAKE_CXX_STANDARD 11)
Run Code Online (Sandbox Code Playgroud)

如果你需要支持旧版本的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)
Run Code Online (Sandbox Code Playgroud)

宏现在只支持GCC,但应该直接将其扩展到其他编译器.

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

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

如果您使用CMake和clang来定位MacOS,则会出现一个错误,导致该CMAKE_CXX_STANDARD功能无法正常工作(不添加任何编译器标志).确保您执行以下操作之一:

  • 使用cmake_minimum_required来要求CMake 3.0或更高版本,或
  • project命令之前,使用以下代码将策略CMP0025设置为NEW,并将其放在CMakeLists.txt文件的顶部:

    # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS.
    if (POLICY CMP0025)
      cmake_policy(SET CMP0025 NEW)
    endif ()
    
    Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案.它不需要单独触摸每个目标的属性,而是跨平台工作. (12认同)
  • 同意,这应该是CMake 3.1+的接受答案.虽然它似乎对我不起作用.您可以强制它使用--stdlib = libc ++(Mac上的默认值)为您提供--std = c ++ 11.相反,如果支持的话,CMAKE_CXX_STANDARD总是包含gnu扩展,并且结果似乎不是针对--stdlib = libc ++构建的.相反,你必须切换到gnu的--stdlib = libstdc ++.Mac虽然是特例.对于Linux,选择带有libstdc ++的gnu ++ 11是常态.当然,使用if(APPLE)add_compile_options()可以很容易地纠正这个问题. (4认同)
  • 这种方法的一个问题是强制执行`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}") (2认同)
  • 在macOS(CMake 3.9.4,homebrew-clang)上对我不起作用。拯救别人的绝望。不知道为什么它适用于@EvanMoran,但不适用于我。 (2认同)
  • @Unapiedra:这是一个CMake错误,但您可以解决它,请参阅https://gitlab.kitware.com/cmake/cmake/issues/15943 (2认同)
  • 正如@Antonio所暗示的,始终附加标志,不要直接设置标志,因为这可能会覆盖上游的任何其他设置(或从命令行传递)。正确:`set(CMAKE_CXX_FLAGS“ $ {CMAKE_CXX_FLAGS} -std = c ++ 11”)`。 (2认同)

Eri*_*und 184

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)
Run Code Online (Sandbox Code Playgroud)

无需使用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++标准,而不是使用您 .

另见我的更详细的答案.

  • 我认为这是应该做的.其他答案只是手动添加标志,因此引入不兼容性.然而,这似乎只适用于CMake 3.1+ (8认同)
  • 从今天起编辑似乎是误导.CMake 3.0.0不包含target_compile_features.如我错了请纠正我.我认为这个命令只存在于CMake的夜间版本中. (4认同)
  • 我想这是最准确的答案 (4认同)
  • @UliKöhler实际上它仍然不可用,*可能*在3.2中出现*某些编译器*.不要在短期内使用这种方法; 它完全不便携. (2认同)
  • 知道如何在CMake 2.6中做到这一点吗? (2认同)
  • 现在有 `cxx_std_XX` 功能可以轻松设置标准。那太棒了! (2认同)

KoK*_*oru 92

我在用

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()
Run Code Online (Sandbox Code Playgroud)

但是,如果你要玩C++11,g++ 4.6.1是很老.尝试获得更新的g++版本.

  • 对我来说,这是对这个问题的唯一正确和好的答案,使用g ++在最近的Linux上使用当前(推出)cmake. (4认同)

小智 55

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

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)
Run Code Online (Sandbox Code Playgroud)

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

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

Sub*_* S. 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")
Run Code Online (Sandbox Code Playgroud)

按照这种方法,不知何故,-std=c++0x标志被覆盖,它不起作用.逐个设置标志或使用列表方法正在运行.

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

  • 我总是使用:SET(CMAKE_CXX_FLAGS"$ {CMAKE_CXX_FLAGS} -std = c ++ 11")#for gcc> = 4.7,或c ++ 0x for 4.6 (36认同)
  • -1.如果从命令行指定任何CMAKE_CXX_FLAGS,则第二种方法将在构建命令中生成分号(并重复原始CMAKE_CXX_FLAGS两次). (9认同)
  • `CXX_STANDARD` 属性更好,因为它与编译器无关。 (2认同)

alv*_*rez 23

最简单的方法:

add_compile_options(-std=c++11)

  • 仅适用于cmake 3.0 (5认同)
  • 在同一项目中编译C文件时,这会导致警告和错误. (4认同)

Hin*_*dol 16

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

ADD_DEFINITIONS(
    -std=c++11 # Or -std=c++0x
    # Other flags
)
Run Code Online (Sandbox Code Playgroud)

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

  • 这只有在你只使用C++编译器时才有效.如果您还使用CC编译器,它将失败. (9认同)
  • `add_definitions`只能用于添加DEFINITIONS,即-D SOMETHING.正如@Emmanuel所说,它在许多情况下都不起作用. (5认同)

eye*_*ash 16

对于CMake 3.8和更新版本,您可以使用

target_compile_features(target PUBLIC cxx_std_11)
Run Code Online (Sandbox Code Playgroud)

  • 这是最新版本的 CMake 推荐的方式 (2认同)
  • @RotsiserMho`PUBLIC`意味着依赖于你的目标的其他目标也将使用C++ 11.例如,如果您的目标是一个库,那么使用`target_link_libraries`链接到您的库的所有目标都将使用C++ 11支持进行编译. (2认同)
  • 到目前为止,这在技术上是定义标准版本的最佳方法,并且应该是公认的答案(尽管埃里克的答案仍然有效,但如果需要细粒度的设置)。 (2认同)

Mat*_*szL 9

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

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
Run Code Online (Sandbox Code Playgroud)

它转换为"我想要所有目标的C++ 11,它不是可选的,我不想使用任何GNU或MS扩展." 从c ++ 17开始,这仍然是恕我直言的最佳方式.

资料来源:https: //crascit.com/2015/03/28/enabling-cxx11-in-cmake/

  • 不过,没有理由不使用最新的 CMake。Chocolatey、Homebrew 和 Snap 都有最新的软件包。 (2认同)
  • @Sandburg 为什么我更愿意为多个目标分别指定多个功能?您认为对单个项目的不同目标有不同的期望是很常见的吗?我知道这个功能,但老实说,当这是可取的主要方法时,我想不出单一的用例。无论如何:根据链接的文章,它在 3.1 中有效 (2认同)

Kev*_*zke 6

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

set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
Run Code Online (Sandbox Code Playgroud)

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

  • @安东尼奥`设置(CMAKE_CXX_EXTENSIONS OFF)` (2认同)

cod*_*ing 6

如果您想始终激活最新的 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)
Run Code Online (Sandbox Code Playgroud)

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


RAM*_*RAM 5

现代 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
    )
Run Code Online (Sandbox Code Playgroud)