c++oding="utf-8" ?>
set(CMAKE_CXX_STANDARD 17)可全局启用C++17标准,须置于project()之后、target定义之前;配合CMAKE_CXX_STANDARD_REQUIRED ON可强制编译器支持,CMAKE_CXX_EXTENSIONS OFF则禁用扩展以提升可移植性。

set(CMAKE_CXX_STANDARD) 是最直接的方式
在 CMakeLists.txt 里写 set(CMAKE_CXX_STANDARD 17) 就能全局启用 C++17,CMake 会自动给所有 target 加上 -std=c++17(GCC/Clang)或对应 MSVC 标志。这个变量必须在 project() 之后、任何 add_executable() 或 add_library() 之前设置,否则部分 target 可能不生效。
常见错误是把它放在 project() 前面,或者放在某个 target 定义之后——那样只影响后续新定义的 target,已定义的不会回溯更新。
-
CMAKE_CXX_STANDARD可设为11、14、17、20、23(取决于 CMake 版本,CMake 3.20+ 才完整支持 23) - 它默认是
98,不是11,老项目升级时容易踩坑 - 设了这个变量,CMake 还会自动加
-std=gnu++xx吗?不会——除非你额外设CMAKE_CXX_STANDARD_REQUIRED或CMAKE_CXX_EXTENSIONS
CMAKE_CXX_STANDARD_REQUIRED 和 CMAKE_CXX_EXTENSIONS 怎么配合用
这两个开关决定编译器行为是否“严格”:设 set(CMAKE_CXX_STANDARD_REQUIRED ON) 后,如果编译器不支持指定标准(比如设了 20 但用的是 GCC 9),CMake configure 阶段就直接报错;否则它会悄悄降级到支持的最近版本(比如用 c++17 代替 c++20)。
CMAKE_CXX_EXTENSIONS 控制是否启用 GNU/MS 扩展,默认是 ON(即用 -std=gnu++17 而非 -std=c++17)。想写可移植代码,应该关掉:set(CMAKE_CXX_EXTENSIONS OFF)。
- 推荐组合:
set(CMAKE_CXX_STANDARD 17)+set(CMAKE_CXX_STANDARD_REQUIRED ON)+set(CMAKE_CXX_EXTENSIONS OFF) - 关掉扩展后,
__attribute__、typeof、__int128这类非标准语法会编译失败 - MSVC 对
CMAKE_CXX_EXTENSIONS OFF的响应较弱,它本来就不带 GNU 扩展,但会影响某些跨平台宏判断
单个 target 覆盖全局标准怎么办
用 target_compile_features() 或 set_property() 可以给特定 target 单独设标准,比全局 CMAKE_CXX_STANDARD 更灵活。比如一个旧模块必须用 C++11,而主程序要用 C++20:
add_library(old_module src/old.cpp) set_property(TARGET old_module PROPERTY CXX_STANDARD 11) set_property(TARGET old_module PROPERTY CXX_STANDARD_REQUIRED ON) add_executable(main main.cpp) set_property(TARGET main PROPERTY CXX_STANDARD 20) set_property(TARGET main PROPERTY CXX_STANDARD_REQUIRED ON)
注意:set_property(... PROPERTY CXX_STANDARD ...) 的优先级高于全局 CMAKE_CXX_STANDARD,且对已有 target 立即生效。
-
target_compile_features(main PRIVATE cxx_auto_type cxx_constexpr)不等价于设标准——它只声明需要哪些特性,CMake 会自动推导最低所需标准并补全 flag - 混用
set_property和target_compile_features时,后者不会覆盖前者,但会叠加检查(比如要求cxx_concepts会隐式要求 C++20) - 别在
target_compile_features里写太激进的特性(如cxx_modules),目前各编译器支持度差异大,容易 configure 失败
为什么有时候 -std=c++xx 没出现在编译命令里
最常见原因是 CMake 版本太低(add_custom_target() 不参与编译标准设置,只有 add_executable() 和 add_library() 才受控;另外,如果用了 add_compile_options(-std=...) 手动加 flag,它会和 CMake 自动生成的冲突,导致后者被忽略甚至编译失败。
- 检查实际生成的编译命令:运行
make VERBOSE=1或看 Ninja 构建日志里的完整命令行 - 确认 target 是否被正确识别为 C++:文件后缀必须是
.cpp、.cc、.cxx等,.c文件走 C 标准,不受CMAKE_CXX_STANDARD影响 - Windows 上用 MSVC 时,
-std=c++xx不会出现——它用的是/std:c++xx,但效果等价;可通过message(STATUS "CXX flags: ${CMAKE_CXX_FLAGS}")查看最终生效的 flag
C++ 标准不是设完就一劳永逸的事,尤其是混合多标准、跨编译器、或依赖第三方库时,target_compile_features 的细粒度控制往往比硬设 CMAKE_CXX_STANDARD 更可靠。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











