CMake入门
前言
或许你已经见过 GUN make
,
还有很多诸如 qmake
, pmake
, MS nmake
, Makepp
等等,
但这些都有不同的标准和规范,导致需要在每个平台上都需要写一种makefile,很麻烦.
但是有个工具能够自动生成这些makefile文件,这就是 CMake
- 需要开发者写的只是一个CMakeList.txt文件,该文件与平台无关
- 该工具可以生成
makefile
文件,也可以生成Visual Studio工程文件 - 然后做拥有
makefile
后该做的事–make - 一般后面还有安装
单个源文件
文件结构
- main.c
- CMakeLists.txt
文件内容
1 |
|
1 | # CMake 最低版本号要求 |
CMake使用#号作为注释符号
使用方法(下略)
cmake .
make
./Demo1 2 3
多个源文件
文件目录
- main.c
- MathFunctions.c
- MathFunctions.h
- CMakeLists.txt
文件内容
1 |
|
1 | /** |
1 |
|
注意要定义头文件以使程序能够找到外部的函数
1 | # CMake 最低版本号要求 |
注意新增的后两个用法,CMake有自动查找源文件的功能
引用变量的方法也是linux系统常用方法
新函数
aux_source_directory(<dir> <variable>)
- 用于查找指定路径下的源文件列表并保存至指定变量
包含子目录
文件结构
- main.c
- CMakeLists.txt
- math/
- MathFunctions.c
- MathFunctions.h
- CMakeLists.c
文件内容
1 |
|
注意这里自定义头文件的使用,是需要带路径的,不然找不到
1 | # CMake 最低版本号要求 |
添加math
子目录之后,math/Mathfunctions.txt文件与源文件也会被处理,并且应该会在父文件夹下生成库文件
生成目标与添加链接库是两回事,所以使用了两个函数
MathFunctions.c
与上一个例子相同
MathFunctions.h
与上一个例子也相同
1 | # 查找当前目录下的所有源文件 |
新函数
add_subdirectory(<dir>)
- 增加子目录
target_link_libraries(<dst> <lib>)
- 添加链接库
add_library (<lib> <src>)
- 生成链接库
- 作为对比,
add_executable(<exe> <src>)
是生成最终的程序
增加编译选项
文件结构
- main.c
- config.h.in
- CMakeLists.txt
- math/
- MathFunctions.c
- MathFunctions.h
- CMakeLists.txt
在使用编译选项时文件本身必须是有该功能的
文件内容
1 |
|
- 其中
config.h
是由cmake根据config.h.in
文件自动生成的,
主要功能是将 编译选项 转化为程序中使用的 变量
- 这里也有了根据预编译参数而采取不同动作的代码
1 | #cmakedefine USE_MYMATH |
- 顺便贴上生成的头文件
config.h
-
选项打开时
1
-
选项关闭时
1
/* #undef USE_MYMATH */
-
- 算是选项传递给程序的关键了吧
1 | # CMake 最低版本号要求 |
${PROJECT_SOURCE_DIR}
不知道是什么时候定义的
MathFunctions.c
与上一个例子相同
MathFunctions.h
与上一个例子也相同
math/CMakeLists.txt
也与上一个例子相同
使用方法
ccmake .
- 一开始什么都没有,使用=c=读取设置
- 使用方向键移动,使用回车更改选项内容
- 确定后再次按
c
- 没有错误就显示
g
- 按下=g=后开始生成=makefile=文件
make
…
新函数
configure_file(<configfile> <headfile>)
- 设置配置用头文件是从哪里生成的
option(<OPTION> <msg> <ON/OFF>)
- 为cmake添加可以设置的选项
if(<OPTION>)...endif(<OPTION>)
- 定义选项相应的操作
include_directories ("<path>")
用于检测路径是否存在,不存在时能够在cmake界面显示错误信息- 添加路径的功能
add_subdirectory
已经有了,
但是好像不负责报错,前面直接使用是因为作者本人确定吧
- 添加路径的功能
set()
- 使用方法暂时不清楚,只知道是设置变量
定义安装规则
安装规则指库文件的放置位置,头文件放置位置等
文件结构
同上个例子
文件内容
仅不同的
在 CMakeLists.txt
中添加
1 | # 指定安装路径 |
在 math/CMakeLists.txt
中添加
1 | # 指定 MathFunctions 库的安装路径 |
生成的 Demo
文件将会被复制到 /usr/local/bin
中
libMathFunctions.o
文件将会被复制到 /usr/local/lib
中
MathFunctions.h =和生成的 =config.h =文件会被复制到 =/usr/local/include
中
新函数
install(TARGETS/FILES <obj> DESTINATION <subdir>)
- 设置安装对象的位置,其中
subdir
对应的父文件夹路径在使用ccmake时就能看到设置项
CMAKE_INSTALL_PREFIX
,默认使用的是/usr/local
- 设置安装对象的位置,其中
使用方法
- 生成了
makefile
文件 - 使用
sudo make install
-
输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16> sudo make install
[sudo] xxx 的密码:
Scanning dependencies of target MathFunctions
[ 25%] Building CXX object math/CMakeFiles/MathFunctions.dir/MathFunctions.cc.o
[ 50%] Linking CXX static library libMathFunctions.a
[ 50%] Built target MathFunctions
Scanning dependencies of target Demo
[ 75%] Building CXX object CMakeFiles/Demo.dir/main.cc.o
[100%] Linking CXX executable Demo
[100%] Built target Demo
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/bin/Demo
-- Installing: /usr/local/include/config.h
-- Installing: /usr/local/lib/libMathFunctions.a
-- Installing: /usr/local/include/MathFunctions.h -
在安装时候动态库(
.o
)被改成了静态库(.a
)
-
- 然后在其他路径下就能使用=Demo=了
测试
CMake 提供了一个称为 CTest
的测试工具.
在根目录 CMakeLists.txt
文件中使用 add_test
命令即可
基础测试
-
文件目录
同上个例子
-
文件内容
在根目录
CMakeLists.txt
文件中添加1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# 启用测试
enable_testing()
# 测试程序是否成功运行
add_test (test_run Demo 5 2)
# 测试帮助信息是否可以正常提示
add_test (test_usage Demo)
set_tests_properties (test_usage
PROPERTIES PASS_REGULAR_EXPRESSION "Usage: .* base exponent")
# 测试 5 的平方
add_test (test_5_2 Demo 5 2)
set_tests_properties (test_5_2
PROPERTIES PASS_REGULAR_EXPRESSION "is 25")
# 测试 10 的 5 次方
add_test (test_10_5 Demo 10 5)
set_tests_properties (test_10_5
PROPERTIES PASS_REGULAR_EXPRESSION "is 100000")
# 测试 2 的 10 次方
add_test (test_2_10 Demo 2 10)
set_tests_properties (test_2_10
PROPERTIES PASS_REGULAR_EXPRESSION "is 1024") -
新命令
enable_testing()
- 启用测试
add_test (<testName> <Function> [<args>])
- 下面什么都写,有输出就是通过?
set_tests_properties (<testName> PROPERTIES PASS_REGULAR_EXPRESSION "<expression>")
- 添加测试通过条件
-
使用方法
- 生成
makefile
文件 - 先生成程序本身,使用
make
- 再使用测试命令
make test
-
测试输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15> make test
Running tests...
Test project /path/to/Demo5
Start 1: test_run
1/5 Test #1: test_run ......................... Passed 0.00 sec
Start 2: test_usage
2/5 Test #2: test_usage ....................... Passed 0.00 sec
Start 3: test_5_2
3/5 Test #3: test_5_2 ......................... Passed 0.00 sec
Start 4: test_10_5
4/5 Test #4: test_10_5 ........................ Passed 0.00 sec
Start 5: test_2_10
5/5 Test #5: test_2_10 ........................ Passed 0.00 sec
100% tests passed, 0 tests failed out of 5
Total Test time (real) = 0.01 sec -
自动计数的
-
- 关于 CTest 的更详细的用法可以通过
man 1 ctest
参考 CTest 的文档
- 生成
使用宏测试
在要测试的数量多的情况下,可以使用宏来简化 CMakeLists.txt
文件的编写
在上述 CMakeLists.txt
文件中使用
1 | # 定义一个宏,用来简化测试工作 |
- 别看现在是复制粘贴,在没有鼠标,不能复制窗口内容的时代宏是非常有用的
- 现在使用宏也能保持非常好的易读性
-
新命令
macro(<apiName <args>)...endmacro(<apiName>)
- 定义宏,并且宏可以使用参数,在宏定义中使用=${}=调用参数
支持gdb
gdb是 GNU Debugger
的简称,可以使用命令行接口(CLI)进行众多错误检测等
让 CMake 支持 gdb
的设置也很容易,只需要指定 Debug
模式下开启 -g
选项:
1 | set(CMAKE_BUILD_TYPE "Debug") |
之后可以直接对生成的程序使用 gdb 来调试。
添加环境检查
跨平台时最常见的应用场景了
文件结构
同上
文件内容
1 |
|
文件本身需要支持根据环境检测结果改变代码.
顶层的 CMakeLists.txt
文件中增加
1 | # 检查系统是否支持 pow 函数 |
- 注意这部分应该写在
configure_file
命令前
配置文件 config.h.in
改成设置环境检查的结果
1 | // does the platform provide pow function? |
新命令
include()
这里导入了后面的函数check_function_exists (<funcName> <var>)
- 将检测函数
<funcName>
存在与否并将结果存入<var>
- 将检测函数
添加版本号
文件结构
同上
文件内容
只需要在顶层=CMakeLists.txt=文件中添加
1 | set (Demo_VERSION_MAJOR 1) |
分别添加主版本号与副版本号
在程序中获取版本号信息
是通过 config.h.in
文件传递给 config.h
再在 main.c
文件中include实现的
config.h.in
1 | // the configured options and settings for Tutorial |
注意cmake变量在设置文件中的引用方法
main.c
1 |
|
-
新命令
无
生成安装包
软件做出来给自己用还不够爽,给别人用才爽
这里使用了=CPack=,同样是CMake的一个工具
安装包有*二进制安装包*与*源码安装包*
发布软件需要附带证书,不然别人也不敢乱用
文件结构
- main.c
- config.h.in
- CMakeLists.txt
- License.txt
- math/
- MathFunctions.c
- MathFunctions.h
- CMakeLists.txt
文件内容
在顶层的=CMakeLists.txt=文件中增加
1 | # 构建一个 CPack 安装包 |
说明
- 先导入
InstallRequiredSystemLibraries
模块,以便之后导入CPack
模块; - 然后设置许可证信息
- 再设置版本信息
- 导入
CPack
模块
使用方法
- 生成
makefile
文件 - 生成安装文件
-
二进制安装包
1
cpack -C CPackConfig.cmake
-
生成源码安装包
1
cpack -C CPackSourceConfig.cmake
-
生成的文件
name-v-v-linux.sh
name-v-v-linux.tar.gz
name-v-v-linux.gar.Z
-
生成的文件内容相同
-
- 安装(
./xxx.sh
)- 出现了CPack自动生成的安装页面
- 显示证书
- 提问与应答
- 出现了CPack自动生成的安装页面
- 在路径下使用
关于 CPack 的更详细的用法可以通过 man 1 cpack
参考 CPack 的文档。
其他平台项目迁移到CMake
CMake
可以很轻松地构建出在适合各个平台执行的工程环境。而如果当前的工程环境不是
CMake ,而是基于某个特定的平台,是否可以迁移到 CMake
呢?答案是可能的。下面针对几个常用的平台,列出了它们对应的迁移方案。
autotools
- am2cmake 可以将
autotools 系的项目转换到 CMake,这个工具的一个成功案例是 KDE 。 - Alternative Automake2CMake 可以转换使用 automake 的 KDevelop 工程项目。
- Converting autoconf tests
qmake
- qmake converter 可以转换使用 QT 的 qmake 的工程。
Visual Studio
- vcproj2cmake.rb 可以根据 Visual
Studio 的工程文件(后缀名是.vcproj
或 =.vcxproj=)生成
CMakeLists.txt 文件。 - vcproj2cmake.ps1 vcproj2cmake
的 PowerShell 版本。 - folders4cmake 根据
Visual Studio 项目文件生成相应的 “source~group~”
信息,这些信息可以很方便的在 CMake 脚本中使用。支持 Visual Studio 9/10
工程文件。
CMakeLists.txt 自动推导
- gencmake 根据现有文件推导
CMakeLists.txt 文件。 - CMakeListGenerator 应用一套文件和目录分析创建出完整的
CMakeLists.txt 文件。仅支持 Win32 平台。