CMake笔记-01-设置C++标准
本文最后更新于 2023年3月25日 下午
引言
C++ 语言有不同版本的标准,如 C++ 98、C++ 11、C++ 14 等。不同标准提供的特性有所区别,故经常有必要在 CMakeLists.txt
中为项目指定使用何种标准,进而让 CMake 使用正确的编译器标志(比如 -std=c++11
)。对于 CMake v3.1 以上版本,可以通过 CMAKE_CXX_STANDARD
变量指定标准,或通过 target_compile_features
函数根据使用的特性自动推断适用于目标的编译器标志。
在早期版本的 CMake 中指定标准,方法参见 C++ Standard Common Method。
CMAKE_CXX_STANDARD 变量
CMAKE_CXX_STANDARD
变量用于设置创建目标时使用的 CXX_STANDARD
目标属性默认值。
基本使用
下面是一个简单的例子,演示如何指定使用 C++ 11 标准:
1 |
|
项目文件只有两个:包含 CMake 命令的 CMakeLists.txt
、一个使用 C++ 11 标准的简单 “Hello World” 源文件 main.cpp
。
其中 CMakeLists.txt
文件内容如下:
1 |
|
在第 8 行中通过设置变量指定了该项目使用的 C++ 标准,当前所有可用的标准可以在 CXX_STANDARD 中查询。
强制指定标准
出于对编译器的兼容性之考虑,上面这种设置标准的方法并不是强制执行。假设某个项目设置使用 C++ 11 标准,但用户使用的编译器并不支持 -std=gnu++11
(或等价的)标志,将不会导致错误或警告,而是在允许的情况下添加 -std=gnu++98
标志。换言之,CMake 将自动“衰减”至最接近的标准。如果确实需要强制指定标准,禁用这种自动衰减调整,那么可以通过设置 CXX_STANDARD_REQUIRED
实现。
CXX_STANDARD_REQUIRED
是一个布尔类型的变量,用于描述是否需要(强制)指定 CXX_STANDARD
。当打开此选项,且当前使用的编译器不支持指定的标准时,会在 configuring 阶段报错失败,不会进行编译。
对上一节中的小例子稍加修改,使其强制使用 C++ 11 标准:
1 |
|
禁用编译器特有扩展
另一个经常与 CMAKE_CXX_STANDARD
一同设置的布尔变量是 CMAKE_CXX_EXTENSIONS
。该属性用于指定是否使用编译器特有的扩展(即,不同的编译器在 C++ 标准之外自行实现的、非通用的特性)。对于某些编译器来说,启用此选项后会在编译行中添加特殊的标志,比如用 -std=gnu++11
替换 -std=c++11
。该属性默认为 ON
。如果某个项目对可移植性有较高的要求,可能为不同的平台使用不同的编译器,那么建议将其设置为 OFF
。
继续更新完善上面的示例:
1 |
|
目标级设置
在上面几节的例子中,均是通过 set(CMAKE_CXX_* value)
的方式设置 CXX_*
全局级别的变量来实现,这也是最为推荐的做法。在极少数情况下,可能需要为项目中的不同目标设置不同的 C++ 标准(比如某项目其实更像是由几个较独立的子部分构成、且这些不同的部分不能使用相同的标准),可以通过设置目标属性的方法来为每个目标细致调整:
1 |
|
再次强调,除非有非常充分的理由,否则不要这样设置。
target_compile_features 函数
target_compile_features 函数用于将期望的编译器特性添加到目标中。其完整语法为:
1 |
|
指定编译一个给定目标时需要的编译器特性。如果该特性没有在 CMAKE_C_COMPILE_FEATURES
、CMAKE_CUDA_COMPILE_FEATURES
或 CMAKE_CXX_COMPILE_FEATURES
变量中列出,那么 CMake 将报告一个错误。如果使用该特性需要一个额外的编译器标志,例如 -std=gnu++11
,该标志将被自动添加。
INTERFACE
、PUBLIC
和 PRIVATE
关键字是用来指定特性的范围的。PRIVATE
和PUBLIC
项将填充 <target>
的 COMPILE_FEATURES
属性。PUBLIC
和INTERFACE
项目将填充 <target>
的 INTERFACE_COMPILE_FEATURES
属性。对同一个 <target>
的重复调用会追加项目。
下面仍然以一个简单的小例子来演示如何通过该函数为目标设置合适的 C++ 标准。
项目文件结构与上一节中的完全相同:
1 |
|
CMakeLists.txt
文件内容如下:
1 |
|