CMake 使用学习
1. 概述
CMake 工具能够自动生成 Makefile 文件,减轻手写 Makefile 文件的工作量,同时减少书写 Makefile 文件产生的错误。
2. CMake 命令
CMake 运行主要分为两个阶段:
-
配置阶段:解析 CMakeLists.txt 文件
-
生成阶段:生成构建环境
有关 cmake
的详细参数参见 cmake --help
,本文仅对其中较难理解的选项加以描述。
2.1 缓存选项
CMake 支持缓存选项。在 CMake 中,如果一个变量被标记为「缓存」,则 cmake
的时候会将其写入到 CMakeCache.txt 文件中。当 cmake
命令寻找变量时,它会首先去 CMakeCache.txt 文件中寻找。cmake
创建缓存选项的格式如下:
1 | cmake -D <var>[:<type>]=<value> # <var>[:<type>]=<value> 具体参见下文「CMakeCache.txt 编写」 |
2.2 常用选项
-
-DCMAKE_BUILD_TYPE=
:指定编译软件的版本格式,取值为Release
、RelWithDebInfo
、Debug
等。 -
-DCMAKE_INSTALL_PREFIX=
:指定需要安装的软件路径,默认为安装路径为/usr/local
(默认系统安装)。
仅用户安装一般指定安装路径为
~/.local
,当然也可以随用户自定义。
-DBUILD_SHARED_LIBS=
:DBUILD_SHARED_LIBS
是一个全局的 flag,为bool
类型,取值为ON
或OFF
(默认为ON
)。其作用是:
如果
DBUILD_SHARED_LIBS
设定为ON
,则 CMakeLists.txt 中所有的add_library()
创建的库都默认为共享库而不是静态库,除非add_library()
中有显式地指定编译为静态库。反之则为静态库。
-DBUILD_TESTING=
:DBUILD_TESTING
是一个全局的 flag,为bool
类型,取值为ON
或OFF
(默认为ON
)。其作用是:
当使用 CTest 模块时,
DBUILD_TESTING
用来控制是否使能 testing。
--trace
:用于详细输出cmake
的每一行信息。
--trace-source=<file>
:将cmake
输出的所有信息都保存在file
文件中。
3. CMakeLists.txt 编写
3.1 设定编译器
在运行 CMake 前首先需要指定 CC、CXX 编译器,否则 CMake 将使用系统默认的 CC、CXX 编译器。可以在 bash shell 中临时设定:
1 | CC=/usr/bin/gcc |
也可以在 CMakeLists.txt 文件中设定:
1 | set(CMAKE_C_COMPILER "/usr/bin/gcc") |
3.2 添加 CMake 最小要求版本
1 | cmake_minimum_required(VERSION 3.1) |
3.3 添加项目信息
1 | project(MyProject VERSION 1.0 # 项目版本 |
CMake 支持的语言有:C , CXX , Fortran , ASM , CUDA (CMake 3.8+), CSharp (3.8+), and SWIFT (CMake 3.15+experimental)
。默认为 C
和 CXX
。
3.4 生成文件
- 生成目标文件
1 | add_executable(one two.cpp three.h) |
one 既是生成的可执行文件名称,也是 CMake 创建的目标文件的名称。one 后面紧跟着项目的源文件,比如这里示例的 two.cpp three.h 都是源文件。
- 生成库文件
1 | add_library(onelib STATIC twolib.cpp threelib.h) |
可选的库文件类型有:STATIC、SHARED、MODULE
。
3.5 为目标文件添加内容
【注】可以为目标文件添加这些内容:
include directories, linked libraries (or linked targets), compile options, compile definitions, compile features, and more.
- 为目标文件添加 include 路径
1 | target_include_directories(one PUBLIC include) |
PUBLIC/PRIVATE/INTERFACE
用来指定「是/否/仅需要时」影响其他依赖于当前目标文件 one 的目标文件。
- 为目标文件添加链接库
1 | target_link_libraries(one -lcrypt -lcap) |
one 是 CMake 创建的目标文件的名称。
3.6 设定变量、缓存项、属性
【注】访问一个名为 VARIABLE
的局部变量使用 ${VARIABLE}
,访问一个名为 VARIABLE
的环境变量使用 $ENV{VARIABLE}
。
- 设定局部变量
1 | set(MY_VARIABLE "value") |
局部变量的值还可以是列表:
1 | set(MY_VARIABLE "one" "two") |
上述两条语句等价,因为变量的列表值在内部存储时就是使用 “;” 分隔的。可以添加 PARENT_SCOPE
关键字指定将变量的作用域往外跳一级。
- 设定缓存变量
1 | set(MY_CACHE_VARIABLE "VALUE" CACHE STRING "Description") # 不会覆盖已存在的变量 |
- 修改命令行参数变量
1 | option(MY_OPTION "This is settable from the command line" OFF) # 此处假定 MY_OPTION 为 bool 值 |
- 设定环境变量
1 | set(ENV{variable_name} value) |
- 设定属性 & 访问属性
属性可以看作是依附于某一项(比如目录、目标文件等)的全局变量。
1 | set_property(TARGET TargetName[TargetName1...] PROPERTY CXX_STANDARD 11) # 可以为多个 targets/files/tests 设置属性 |
3.7 if 语句块
1 |
|
if 语句块中可以包含的关键字有:
-
一元:NOT、TARGET、EXISTS(file)、DEFINED 等
-
二元:STREQUAL、AND、OR、MATCHES(regular expression)、VERSION_LESS、VERSION_LESS_EQUAL 等
-
括号:()
3.8 生成表达式
-
$<KEYWORD>
:计算 KEYWORD 的值 -
$<KEYWORD:value>
:根据 KEYWORD 的值来控制整个表达式的值,KEYWORD = 1 时表达式值为 value,KEYWORD = 0 时表达式值为空字符串。
常用的生成表达式有 BUILD_INTERFACE
和 INSTALL_INTERFACE
生成表达式。
1 | target_include_directories( |
BUILD_INTERFACE 表达式包装的构建需求只被在同一个构建系统下,或者使用 export() 指令导出的目标上使用。INSTALL_INTERFACE 表达式包装的构建需求只被用在使用 install(EXPORT) 指令安装和导出的目标上:
3.9 函数和宏
函数和宏的唯一区别在于作用域,函数有作用域但宏没有。
1 |
|
CMake 中有一个参数接收模块:cmake_parse_arguments(),用来定义函数/宏需要接收的参数。
1 |
|
上文调用函数后可以发现:
1 | COMPLEX_PREFIX_SINGLE = TRUE |
如果函数/宏调用时传入了 cmake_parse_arguments() 未指定的其他参数,则其内容均保存在 COMPLEX_PREFIX_UNPARSED_ARGUMENTS
变量中。
4. CMakeCache.txt 编写
CMakeCache.txt 文件本是由 cmake
命令默认生成的,但其内容是可以修改的。CMakeCache.txt 文件主要保存的是 cmake
过程中需要使用的环境变量,当 cmake
命令寻找变量时,它会首先去 CMakeCache.txt 文件中寻找。
4.1 内容条目
随便看一个 CMakeCache.txt 文件就会发现,其文首给出了该文件的作用和内容条目格式:
1 | # This is the CMakeCache file. |
简单来说,CMakeCache.txt 文件就是一条条环境变量的键(包含类型)值对条目组成的,而条目的具体格式如下:
1 | KEY:TYPE=VALUE |
5. 注释
在可编写的 CMake 文件(CMakeLists、CMakeCache.txt等)中,其注释规则都是一样的。
5.1 单行注释
1 | # 要注释的单行内容 |
5.2 多行注释
1 | #[[ |