NotePublic/Software/Development/Environment/CMake/CMake_基本语法.md

402 lines
8.9 KiB
Markdown
Raw Normal View History

---
layout: post
title: "CMake 基本语法"
subtitle: ""
description: "CMake 的简明语法。"
excerpt: "通过简明的方式对 CMake 构建系统基本语法进行说明。"
date: 2020-01-20 15:17:00
author: "Rick Chan"
tags: ["Development", "Environment", "CMake"]
categories: ["Software"]
published: true
---
CMake 支持大写、小写、混合大小写的命令。
## 1. 最小版本号
```cpp
cmake_minimum_required(VERSION 2.8)
```
## 2. 工程名
```cpp
project(<Project Name>)
```
## 3. Include 路径
*需要出现在 add_executable 和 add_library 等之前。*
```cpp
include_directories(
<Path 1>
<Path 2>
...
<Path N>
)
```
## 4. 添加库路径
*需要出现在 add_executable 和 add_library 等之前。*
```cpp
link_directories(
<Path 1>
<Path 2>
...
<Path N>
)
```
## 5. 添加库文件
*已经被废弃了,需要出现在 add_executable 和 add_library 等之前。*
```cpp
link_libraries(
<Library 1>
<Library 2>
...
<Library N>
)
```
支持直接全路径的写法。
## 6. 可执行文件目标和源码
```cpp
add_executable(
<Executable Name>
<Source 1>
<Source 2>
...
<Source N>
)
```
## 7. 库文件目标和源码
```cpp
add_library(
<Library>
<SHARED/STATIC>
<Source 1>
<Source 2>
...
<Source N>
)
```
## 8. 为目标添加库文件
*可添加的动态库或静态库,可以在 add_executable 和 add_library 等之后。*
```cpp
target_link_libraries(
<Target Name>
<Library 1>
<Library 2>
...
<Library N>
)
```
## 9. 添加依赖工程
```cpp
add_dependencies(
<Target Name>
<Depend Target 1>
<Depend Target 2>
...
<Depend Target N>
)
```
## 10. 添加子目录
添加的子目录下的 CMakeLists.txt 和源码将被处理。
```cpp
add_subdirectory(
<sub dir 1>
<sub dir 2>
...
<sub dir N>
)
```
## 11. 宏
```cpp
set(A_MACRO <value>)
```
可通过
```bash
${A_MACRO}
```
方式引用宏。
## 12. 自定义编译选项
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)
```
## 13. Config File
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
```
## 14. 编译项目
通常会创建一个 build 目录为 cmake 的工作目录,用于存放 cmake 临时文件:
```bash
mkdir build && cd build
cmake ..
make
make install
```
为了便于交互式的选择该变量的值,可以使用:
```bash
ccmake
# 或
cmake -i
```
该命令会提供一个会话式的交互式配置界面。
## 15. CMake 标准宏
宏取值类型如下:
* string
* int
* boolTRUE/FALSE
### 15.1. CMAKE_INSTALL_PREFIX
类型string
用于指定 make install 的安装根目录,默认值为:/usr/local/。
### 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
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 的文档。
## 17. 支持 GDB
让 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")
```
## 18. 添加版本号
首先修改顶层 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;
}
```
## 19. 生成安装包
首先在顶层的 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.Z3 个不同格式的二进制包文件。
关于 CPack 的更详细的用法可以通过 man 1 cpack 参考 CPack 的文档。
## 20. 内部参考关键字
1. 常用宏
## 21. 外部参考资料
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_librariesFIND_PACKAGE实践篇2](https://blog.csdn.net/KYJL888/article/details/85109782)
4. [CMake 入门实战](https://www.hahack.com/codes/cmake/)