当我尝试运行 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 的内容。
set(CMAKE_CXX_STANDARD 11)
(在定义目标之前)是最好的方法。
CXX_STANDARD
不在 MSVC 上工作,因此如果您想要跨平台工作的东西,基本上您必须回退到 target_compile_features
。
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 命令 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_STANDARD
和 CXX_STANDARD_REQUIRED
来明确指定 C++ 标准。
我在用
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++
版本。
CXX_STANDARD
的答案,但这是在我的情况下唯一有用的答案。
设置 Cxx 标准的最简单方法是:
set_property(TARGET tgt PROPERTY CXX_STANDARD 11)
有关详细信息,请参阅 the CMake documentation。
set(CMAKE_CXX_STANDARD 11)
为之后创建的所有目标定义默认属性。
set
命令是全局的,会影响所有后续目标。
事实证明,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")
CXX_STANDARD
属性更好,因为它与编译器无关。
在现代 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
target_compile_options(project_name PRIVATE option1 ...)
或 target_compile_definitions
或仍然是 target_compile_features(ao-project_name PRIVATE some_feature)
。
对于 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 上实现这一点的建议。
PUBLIC
这里的作用是什么?
PUBLIC
意味着依赖于您的目标的其他目标也将使用 C++11。例如,如果您的目标是一个库,那么使用 target_link_libraries
链接到您的库的所有目标都将使用 C++11 支持进行编译。
最简单的方法:
add_compile_options(-std=c++11)
这是启用 C++11 支持的另一种方式,
ADD_DEFINITIONS(
-std=c++11 # Or -std=c++0x
# Other flags
)
我遇到过只有这种方法有效而其他方法失败的情况。也许它与最新版本的 CMake 有关。
add_definitions
只应该用于添加定义,即 -D Something。正如@Emmanuel 所说,它在很多情况下都不起作用。
add_definitions
不是用于设置标志的。
现代 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
)
如果您想始终激活最新的 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)
。)
对我有用的是在 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)
我认为只有这两行就足够了。
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
target_compile_features
函数是一种更推荐的方法。
您可以使用以下内容。这会根据您的环境自动修改功能。
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
因此,您支持尽可能多的环境。
现代方法是指定 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
OS X 和 Homebrew LLVM 相关:
不要忘记在它之后调用 cmake_minimum_required(VERSION 3.3) 和 project() !
或者 CMake 会在第 1 行之前隐式插入 project()
,从而导致 Clang 版本检测出现问题,并可能导致其他类型的问题。这是a related issue。
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}")