如何在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特性。

491748 次浏览

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

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

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

我遇到过只有这个方法有效而其他方法失败的例子。也许和最新版本的CMake有关。

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_STANDARD 而且 < >强CXX_STANDARD_REQUIRED < / >强为你的CMake目标

另见我更详细的回答

我在用

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

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

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

更多细节参见CMake文档

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

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

针对macOS的clang用户的CMake issue #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 ()
    

OS X和Homebrew LLVM相关:

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

或者CMake将隐式地在第1行之前插入project(),导致Clang版本检测出现问题,并可能出现其他类型的问题。这里是一个相关的问题

最简单的方法:

add_compile_options(-std=c++11)

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

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

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

对于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)

这在现代CMake介绍 ->添加功能->c++ 11及以上版本。它还提供了关于如何在旧版本的CMake上实现这一点的建议,如果你受到限制的话。

我想这两行就够了。

set(CMAKE_CXX_STANDARD 11)


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

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

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

它翻译成“我想要c++ 11的所有目标,这不是可选的,我不想使用任何GNU或微软扩展。” 在c++ 17中,这仍然是我认为最好的方法

来源:在CMake中启用c++ 11及以后的版本 .

如果你想总是激活最新的c++标准,这里是我的大卫·格雷森的回答扩展,根据最近(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)。)

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

你可以使用下面的方法。这将根据您的环境自动修改特性。

target_compile_features(your_target INTERFACE cxx_std_20)

例如,

  • 在Gnu/Linux上,下面添加-std=gnu++20
  • 在Windows上使用Clang/Ninja,它变成-std=c++20
  • 在Windows MSVC上,它变成/std=c++20

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

现代的方法是将最低要求标准指定为c++ 11:

target_compile_features(foo PUBLIC cxx_std_11)

这种方式:

  • 如果编译器的c++标准大于c++ 11, CMake可以支持默认的c++标准
  • 您可以清楚地指定是在构建时需要c++标准,还是在使用时需要c++标准,或者两者都需要。这对图书馆来说很好。
  • 公共编译特性被传播到下游目标,因此即使这些目标不直接使用该特性,这些目标也可以免费使用该特性。
  • 用户可以从命令行或CMake预置中使用CMAKE_CXX_STANDARD在外部设置另一个c++标准(基本上是最近的标准)。如果你在CMakeLists中硬编码CMAKE_CXX_STANDARD,没有人可以在不编辑你的CMakeLists的情况下重写c++标准,这不是很令人愉快。

它需要CMake >= 3.8

以防你在使用cmake时遇到和我一样的错误。 需要设置

set (CMAKE_CXX_STANDARD 11)

激活线程,因为它只支持c++ 11++

希望这能有所帮助