CMake 小计

CMake 是一个高效的 C/C++ Makefile 生成工具,具有很好的跨平台性。利用它可以让代码在各个平台上顺利的编译。

现在最愿意看到的编译流程就是:

1
2
3
4
mkdir build
cd build
cmake ..
make

这里可能不是详尽的解释,但是展示了我本人在编写中常用的命令。
利用 CMake 的契机主要是想要摆脱 XCode 以及使用 CLion。当然,也是为自己的一些小项目做管理。(主要是不想写 MakeFile)

CMakeLists.txt

CMakeList.txt 是 CMake 的核心文件,所有对 CMake 的编辑配置都集中于此。所以,使用 CMake 来管理你的项目核心就在如何编写 CMakeLists.txt
具体参考教程可以查看参考资料的第一条进行练习。

常用指令

括号中的是可选项。

version

1
cmake_minimum_required(VERSION 3.9)

指定 CMake 的最低版本,非必要,但是最好有,因为可能有兼容性问题。

project

1
project( ProjectName )

指明 CMakeLists.txt 目录是一个项目,并且项目名为指定的名称。CLion 依靠此命令来识别项目。

set

1
set(<var_name> <value>)

设置变量命令,类似代码中的变量,可以设置成想要的字符串。

find_package

1
find_package(<pkg_name> [REQUIRED])

查找库的命令。

库一般会有二进制文件以及头文件两个内容需要查找。

此命令会以两种模式寻找库的信息。一种以 Module 模式查找,该命令会从 CMAKE_MODULE_PATH 变量存储的路径(可以包含多个路径,以 : 分隔)中查找格式为 Find<PackageName>.cmake 的文件,根据包名来加载对应的 cmake 文件查找对应的内容。具体路径可以查看cmake的查询目录结构。

如果加载完成,以下变量就会被设置为对应的查找路径:

1
2
3
<PackageName>_FOUND
<PackageName>_INCLUDE_DIR
<PackageName>_LIBRARIES

如果上述模式没有查找成功,会进入 Config 模式,会在提供的 path 中查找 <PackageName>Config.cmake 或者 <lower-case-package-name>.pc来读取配置。如果加载完成,同样会设置上诉的三个变量。

当然还有更复杂的用法以及更多的变量设置,但是简单实用的是上面三个。

PkgConfig

1
find_package(PkgConfig REQUIRED)

加载这个包会加载一些 cmake 命令,从而可以加载由 pkg-config 管理的库。

加载这个库后会引用三个命令可供使用:

1
2
3
pkg_search_module()
pkg_check_module()
pkg_get_variable()

主要讨论 pkg_search_module:
用法如下:

1
pkg_search_module(<your_prefix> <libname> [比较符 版本号] ...)

可以同时查找多个库,继续往后写就行。

所有库都找到以后,一下变量会被设置:

1
2
3
4
5
6
7
8
9
<XXX>_FOUND ... set to 1 if module(s) exist
<XXX>_LIBRARIES ... only the libraries (without the '-l')
<XXX>_LINK_LIBRARIES ... the libraries and their absolute paths
<XXX>_LIBRARY_DIRS ... the paths of the libraries (without the '-L')
<XXX>_LDFLAGS ... all required linker flags
<XXX>_LDFLAGS_OTHER ... all other linker flags
<XXX>_INCLUDE_DIRS ... the '-I' preprocessor flags (without the '-I')
<XXX>_CFLAGS ... all required cflags
<XXX>_CFLAGS_OTHER ... the other compiler flags

可以根据需要选用,用的比较多应该还是一下两个:

1
2
<XXX>_INCLUDE_DIRS ... the '-I' preprocessor flags (without the '-I')
<XXX>_LIBRARIES ... only the libraries (without the '-l')

因为 mac 用 brew 安装一些库的时候有时并不会包含 FINDXXX.cmake,但是 xxx.pc 是被正确设置了的。使用 pkg-config --list-all 可以查看是否成功安装。

include_directories

1
include_directories(<paths>)

指定头文件的搜索路径。外部路径最好使用 <> 引用,虽然使用 "" 也没什么问题,工程目录的最好使用 "" 引用。

aux_source_directory

1
aux_source_directory(<path> <var_name>)

该命令会搜索该目录下的所有源文件,组织过后全都放在变量中。防止重复修改配置文件的利器。

add_executable

1
add_executable(<exec_name> <src> <src> ...)

将多个源文件编译链接成一个可执行文件。这个目录下的 cmake 文件的主要目标,可以设置多个可执行文件。根据需要进行编译。

1
target_link_libraries(<exec_name> <lib_name> <lib_name>)

将库与可执行文件进行链接。

add_subdirectory

1
add_subdirectory(<path>)

这种情况下,path 下也有一个 CMakeLists.txt 来配置子目录的行为,子目录的配置会被加载并将相关的内容添加到当前的配置中。

二进制库相关

add_library

1
add_library(<lib_name> [STATIC | SHARED | MODULE] <src> <src>)

用法与 add_executable 相似,不过根据需求可以选择生成静态库还是共享库还是模块。

常用模板

下面是管理一个小项目的 cmake 模板,可以根据自己的需求进行修改。如果项目更加复杂,cmake 也可像脚本一样使用循环判断等功能。玩的开心 🚀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cmake_minimum_required(VERSION 3.9)
project(Template)
// find_package() 等等
// source dir
aux_source_directory(./src SRC)
// include path
include_directories(./include)
// cmake config
set(CMAKE_CXX_STANDARD 11)
// add exec
add_executable(${EXEC} ${SRC})
// link target
//target_link_libraries(${EXEC} ...)

参考资料