352 lines
8.1 KiB
Markdown
352 lines
8.1 KiB
Markdown
---
|
||
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.自定义编译选项
|
||
|
||
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)
|
||
```
|
||
|
||
## 12.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
|
||
```
|
||
|
||
## 13.编译项目
|
||
|
||
通常会创建一个 build 目录为 cmake 的工作目录,用于存放 cmake 临时文件:
|
||
|
||
```bash
|
||
mkdir build && cd build
|
||
cmake ..
|
||
make
|
||
make install
|
||
```
|
||
|
||
为了便于交互式的选择该变量的值,可以使用:
|
||
|
||
```bash
|
||
ccmake
|
||
# 或
|
||
cmake -i
|
||
```
|
||
|
||
该命令会提供一个会话式的交互式配置界面。
|
||
|
||
## 14.CMake 标准宏
|
||
|
||
### 14.1.CMAKE_INSTALL_PREFIX
|
||
|
||
用于指定 make install 的安装根目录,默认值为:/usr/local/。
|
||
|
||
## 15.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 的文档。
|
||
|
||
## 16.支持 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")
|
||
```
|
||
|
||
## 17.添加版本号
|
||
|
||
首先修改顶层 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;
|
||
}
|
||
```
|
||
|
||
## 18.生成安装包
|
||
|
||
首先在顶层的 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 的文档。
|
||
|
||
## 19.外部参考资料
|
||
|
||
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)
|
||
4. [CMake 入门实战](https://www.hahack.com/codes/cmake/)
|