2020-01-20 16:10:21 +08:00
|
|
|
|
---
|
|
|
|
|
layout: post
|
|
|
|
|
title: "CMake 基本语法"
|
|
|
|
|
subtitle: ""
|
|
|
|
|
description: "CMake 的简明语法。"
|
|
|
|
|
excerpt: "通过简明的方式对 CMake 构建系统基本语法进行说明。"
|
|
|
|
|
date: 2020-01-20 15:17:00
|
|
|
|
|
author: "Rick Chan"
|
2020-05-21 15:58:25 +08:00
|
|
|
|
tags: ["Development", "Environment", "CMake"]
|
2020-01-20 16:10:21 +08:00
|
|
|
|
categories: ["Software"]
|
|
|
|
|
published: true
|
|
|
|
|
---
|
2019-12-31 11:55:45 +08:00
|
|
|
|
|
|
|
|
|
CMake 支持大写、小写、混合大小写的命令。
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 1. 最小版本号
|
2019-12-31 11:55:45 +08:00
|
|
|
|
|
2020-05-20 16:18:39 +08:00
|
|
|
|
```cpp
|
2019-12-31 11:55:45 +08:00
|
|
|
|
cmake_minimum_required(VERSION 2.8)
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 2. 工程名
|
2019-12-31 11:55:45 +08:00
|
|
|
|
|
2020-05-20 16:18:39 +08:00
|
|
|
|
```cpp
|
2019-12-31 11:55:45 +08:00
|
|
|
|
project(<Project Name>)
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 3. Include 路径
|
2019-12-31 11:55:45 +08:00
|
|
|
|
|
|
|
|
|
*需要出现在 add_executable 和 add_library 等之前。*
|
|
|
|
|
|
2020-05-20 16:18:39 +08:00
|
|
|
|
```cpp
|
2019-12-31 11:55:45 +08:00
|
|
|
|
include_directories(
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Path 1>
|
|
|
|
|
<Path 2>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
...
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Path N>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 4. 添加库路径
|
2019-12-31 11:55:45 +08:00
|
|
|
|
|
|
|
|
|
*需要出现在 add_executable 和 add_library 等之前。*
|
|
|
|
|
|
2020-05-20 16:18:39 +08:00
|
|
|
|
```cpp
|
2019-12-31 11:55:45 +08:00
|
|
|
|
link_directories(
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Path 1>
|
|
|
|
|
<Path 2>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
...
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Path N>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 5. 添加库文件
|
2019-12-31 11:55:45 +08:00
|
|
|
|
|
|
|
|
|
*已经被废弃了,需要出现在 add_executable 和 add_library 等之前。*
|
|
|
|
|
|
2020-05-20 16:18:39 +08:00
|
|
|
|
```cpp
|
2019-12-31 11:55:45 +08:00
|
|
|
|
link_libraries(
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Library 1>
|
|
|
|
|
<Library 2>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
...
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Library N>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
支持直接全路径的写法。
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 6. 可执行文件目标和源码
|
2019-12-31 11:55:45 +08:00
|
|
|
|
|
2020-05-20 16:18:39 +08:00
|
|
|
|
```cpp
|
2019-12-31 11:55:45 +08:00
|
|
|
|
add_executable(
|
|
|
|
|
<Executable Name>
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Source 1>
|
|
|
|
|
<Source 2>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
...
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Source N>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 7. 库文件目标和源码
|
2019-12-31 11:55:45 +08:00
|
|
|
|
|
2020-05-20 16:18:39 +08:00
|
|
|
|
```cpp
|
2019-12-31 11:55:45 +08:00
|
|
|
|
add_library(
|
|
|
|
|
<Library>
|
|
|
|
|
<SHARED/STATIC>
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Source 1>
|
|
|
|
|
<Source 2>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
...
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Source N>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 8. 为目标添加库文件
|
2019-12-31 11:55:45 +08:00
|
|
|
|
|
|
|
|
|
*可添加的动态库或静态库,可以在 add_executable 和 add_library 等之后。*
|
|
|
|
|
|
2020-05-20 16:18:39 +08:00
|
|
|
|
```cpp
|
2019-12-31 11:55:45 +08:00
|
|
|
|
target_link_libraries(
|
|
|
|
|
<Target Name>
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Library 1>
|
|
|
|
|
<Library 2>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
...
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Library N>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 9. 添加依赖工程
|
2019-12-31 11:55:45 +08:00
|
|
|
|
|
2020-05-20 16:18:39 +08:00
|
|
|
|
```cpp
|
2019-12-31 11:55:45 +08:00
|
|
|
|
add_dependencies(
|
|
|
|
|
<Target Name>
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Depend Target 1>
|
|
|
|
|
<Depend Target 2>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
...
|
2021-08-11 13:41:18 +08:00
|
|
|
|
<Depend Target N>
|
2019-12-31 11:55:45 +08:00
|
|
|
|
)
|
|
|
|
|
```
|
2019-12-31 12:04:15 +08:00
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 10. 添加子目录
|
2021-08-11 13:41:18 +08:00
|
|
|
|
|
|
|
|
|
添加的子目录下的 CMakeLists.txt 和源码将被处理。
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
add_subdirectory(
|
|
|
|
|
<sub dir 1>
|
|
|
|
|
<sub dir 2>
|
|
|
|
|
...
|
|
|
|
|
<sub dir N>
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 11. 宏
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
set(A_MACRO <value>)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
可通过
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
${A_MACRO}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
方式引用宏。
|
|
|
|
|
|
|
|
|
|
## 12. 自定义编译选项
|
2021-08-11 13:41:18 +08:00
|
|
|
|
|
|
|
|
|
CMake 允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
option (USE_MYMATH
|
|
|
|
|
"Use provided math implementation" ON)
|
|
|
|
|
|
|
|
|
|
if (USE_MYMATH)
|
|
|
|
|
include_directories ("${PROJECT_SOURCE_DIR}/math")
|
|
|
|
|
add_subdirectory (math)
|
|
|
|
|
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
|
|
|
|
|
endif (USE_MYMATH)
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 13. Config File
|
2021-08-11 13:41:18 +08:00
|
|
|
|
|
|
|
|
|
configure_file 命令用于加入一个配置头文件(如 config.h),这个文件由 CMake(从 config.h.in)生成,通过这样的机制,将可以通过预定义一些参数和变量来控制代码的生成。
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
configure_file (
|
|
|
|
|
"${PROJECT_SOURCE_DIR}/config.h.in"
|
|
|
|
|
"${PROJECT_BINARY_DIR}/config.h"
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
编写一个 config.h.in 文件,内容如下:
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
#cmakedefine USE_MYMATH
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 14. 编译项目
|
2021-08-11 13:41:18 +08:00
|
|
|
|
|
|
|
|
|
通常会创建一个 build 目录为 cmake 的工作目录,用于存放 cmake 临时文件:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
mkdir build && cd build
|
|
|
|
|
cmake ..
|
|
|
|
|
make
|
|
|
|
|
make install
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
为了便于交互式的选择该变量的值,可以使用:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
ccmake
|
|
|
|
|
# 或
|
|
|
|
|
cmake -i
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
该命令会提供一个会话式的交互式配置界面。
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 15. CMake 标准宏
|
|
|
|
|
|
|
|
|
|
宏取值类型如下:
|
2021-08-11 13:41:18 +08:00
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
* string
|
|
|
|
|
* int
|
|
|
|
|
* bool:TRUE/FALSE
|
|
|
|
|
|
|
|
|
|
### 15.1. CMAKE_INSTALL_PREFIX
|
|
|
|
|
|
|
|
|
|
类型:string
|
2021-08-11 13:41:18 +08:00
|
|
|
|
|
|
|
|
|
用于指定 make install 的安装根目录,默认值为:/usr/local/。
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
### 15.2. CMAKE_SKIP_RPATH
|
|
|
|
|
|
|
|
|
|
类型:bool
|
|
|
|
|
|
|
|
|
|
简单的来说,就是强制 CMake 不在构建期间和 install 期间给你加上它所认为的 RPATH。
|
|
|
|
|
|
|
|
|
|
### 15.3. CMAKE_SKIP_BUILD_RPATH
|
|
|
|
|
|
|
|
|
|
类型:bool
|
|
|
|
|
|
|
|
|
|
在构建期间和安装期间不允许 CMake 加入 BUILD RPATH。
|
|
|
|
|
|
|
|
|
|
### 15.4. CMKAE_INSTALL_RPATH
|
|
|
|
|
|
|
|
|
|
类型:bool
|
|
|
|
|
|
|
|
|
|
在构建期间和安装期间不允许 CMake 加入 INSTALL RPATH。
|
|
|
|
|
|
|
|
|
|
### 15.5. CMAKE_BUILD_WITH_INSTALL_RPATH
|
|
|
|
|
|
|
|
|
|
类型:bool
|
|
|
|
|
|
|
|
|
|
编译时 RPATH 是否使用 INSTALL RPATH。也就是决定了编译时是否去 INSTALL RPATH 下查找所需的 Lib 库文件
|
|
|
|
|
|
|
|
|
|
## 16. CTest
|
2021-08-11 13:41:18 +08:00
|
|
|
|
|
|
|
|
|
CMake 提供了一个称为 CTest 的测试工具。我们要做的只是在项目根目录的 CMakeLists 文件中调用一系列的 add_test 命令。
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
# 启用测试
|
|
|
|
|
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")
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
上面的代码包含了四个测试。第一个测试 test_run 用来测试程序是否成功运行并返回 0 值。剩下的三个测试分别用来测试 5 的 平方、10 的 5 次方、2 的 10 次方是否都能得到正确的结果。其中 PASS_REGULAR_EXPRESSION 用来测试输出是否包含后面跟着的字符串。
|
|
|
|
|
|
|
|
|
|
让我们看看测试的结果:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
[ehome@xman Demo5]$ make test
|
|
|
|
|
Running tests...
|
|
|
|
|
Test project /home/ehome/Documents/programming/C/power/Demo5
|
|
|
|
|
Start 1: test_run
|
|
|
|
|
1/4 Test #1: test_run ......................... Passed 0.00 sec
|
|
|
|
|
Start 2: test_5_2
|
|
|
|
|
2/4 Test #2: test_5_2 ......................... Passed 0.00 sec
|
|
|
|
|
Start 3: test_10_5
|
|
|
|
|
3/4 Test #3: test_10_5 ........................ Passed 0.00 sec
|
|
|
|
|
Start 4: test_2_10
|
|
|
|
|
4/4 Test #4: test_2_10 ........................ Passed 0.00 sec
|
|
|
|
|
|
|
|
|
|
100% tests passed, 0 tests failed out of 4
|
|
|
|
|
|
|
|
|
|
Total Test time (real) = 0.01 sec
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
如果要测试更多的输入数据,像上面那样一个个写测试用例未免太繁琐。这时可以通过编写宏来实现:
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
# 定义一个宏,用来简化测试工作
|
|
|
|
|
macro (do_test arg1 arg2 result)
|
|
|
|
|
add_test (test_${arg1}_${arg2} Demo ${arg1} ${arg2})
|
|
|
|
|
set_tests_properties (test_${arg1}_${arg2}
|
|
|
|
|
PROPERTIES PASS_REGULAR_EXPRESSION ${result})
|
|
|
|
|
endmacro (do_test)
|
|
|
|
|
|
|
|
|
|
# 使用该宏进行一系列的数据测试
|
|
|
|
|
do_test (5 2 "is 25")
|
|
|
|
|
do_test (10 5 "is 100000")
|
|
|
|
|
do_test (2 10 "is 1024")
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
关于 CTest 的更详细的用法可以通过 man 1 ctest 参考 CTest 的文档。
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 17. 支持 GDB
|
2021-08-11 13:41:18 +08:00
|
|
|
|
|
|
|
|
|
让 CMake 支持 gdb 的设置也很容易,只需要指定 Debug 模式下开启 -g 选项:
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
set(CMAKE_BUILD_TYPE "Debug")
|
|
|
|
|
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
|
|
|
|
|
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 18. 添加版本号
|
2021-08-11 13:41:18 +08:00
|
|
|
|
|
|
|
|
|
首先修改顶层 CMakeLists 文件,在 project 命令之后加入如下两行:
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
set (Demo_VERSION_MAJOR 1)
|
|
|
|
|
set (Demo_VERSION_MINOR 0)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
分别指定当前的项目的主版本号和副版本号。
|
|
|
|
|
|
|
|
|
|
之后,为了在代码中获取版本信息,我们可以修改 config.h.in 文件,添加两个预定义变量:
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
// the configured options and settings for Tutorial
|
|
|
|
|
#define Demo_VERSION_MAJOR @Demo_VERSION_MAJOR@
|
|
|
|
|
#define Demo_VERSION_MINOR @Demo_VERSION_MINOR@
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
这样就可以直接在代码中打印版本信息了:
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
int main(void)
|
|
|
|
|
{
|
|
|
|
|
printf("Version %d.%d\n",
|
|
|
|
|
Demo_VERSION_MAJOR,
|
|
|
|
|
Demo_VERSION_MINOR);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 19. 生成安装包
|
2021-08-11 13:41:18 +08:00
|
|
|
|
|
|
|
|
|
首先在顶层的 CMakeLists.txt 文件尾部添加下面几行:
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
# 构建一个 CPack 安装包
|
|
|
|
|
include (InstallRequiredSystemLibraries)
|
|
|
|
|
set (CPACK_RESOURCE_FILE_LICENSE
|
|
|
|
|
"${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
|
|
|
|
|
set (CPACK_PACKAGE_VERSION_MAJOR "${Demo_VERSION_MAJOR}")
|
|
|
|
|
set (CPACK_PACKAGE_VERSION_MINOR "${Demo_VERSION_MINOR}")
|
|
|
|
|
include (CPack)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
上面的代码做了以下几个工作:
|
|
|
|
|
|
|
|
|
|
1. 导入 InstallRequiredSystemLibraries 模块,以便之后导入 CPack 模块;
|
|
|
|
|
2. 设置一些 CPack 相关变量,包括版权信息和版本信息,其中版本信息用了上一节定义的版本号;
|
|
|
|
|
3. 导入 CPack 模块。
|
|
|
|
|
|
|
|
|
|
接下来的工作是像往常一样构建工程,并执行 cpack 命令。
|
|
|
|
|
|
|
|
|
|
* 生成二进制安装包:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
cpack -C CPackConfig.cmake
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
* 生成源码安装包
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
cpack -C CPackSourceConfig.cmake
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
在生成项目后,执行 cpack -C CPackConfig.cmake 命令,此时会在该目录下创建:Demo8-1.0.1-Linux.sh、Demo8-1.0.1-Linux.tar.gz、Demo8-1.0.1-Linux.tar.Z,3 个不同格式的二进制包文件。
|
|
|
|
|
|
|
|
|
|
关于 CPack 的更详细的用法可以通过 man 1 cpack 参考 CPack 的文档。
|
|
|
|
|
|
2021-10-16 17:50:51 +08:00
|
|
|
|
## 20. 内部参考关键字
|
|
|
|
|
|
|
|
|
|
1. 常用宏
|
|
|
|
|
|
|
|
|
|
## 21. 外部参考资料
|
2019-12-31 12:04:15 +08:00
|
|
|
|
|
2020-08-14 11:33:10 +08:00
|
|
|
|
1. [cmake手册详解](https://blog.csdn.net/chengde6896383/article/details/81330564)
|
|
|
|
|
2. [cmake 的link_libraries和target_link_libraries](https://blog.csdn.net/harryhare/article/details/89143410)
|
|
|
|
|
3. [【学习cmake】cmake如何使用链接库 (link_directories, LINK_LIBRARIES, target_link_libraries,FIND_PACKAGE)实践篇2](https://blog.csdn.net/KYJL888/article/details/85109782)
|
2021-08-11 13:41:18 +08:00
|
|
|
|
4. [CMake 入门实战](https://www.hahack.com/codes/cmake/)
|