1. 主要关注点梳理

1.1 结构梳理

image.png

1.2 相关文档

命令行参数

https://cmake.org/cmake/help/latest/manual/cmake.1.html

构建系统

https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html

编译系统主要由后面的命令方法和变量组合而成

命令方法

https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html

变量

脚本变量 https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html

环境变量 https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html

工具链

https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html

语言选项、交叉编译工具等

2. 指引文档

全量指引文档见:https://cmake.org/cmake/help/latest/index.html

  • cmake-buildsystem(7)
  • cmake-commands(7)
  • cmake-compile-features(7)
  • cmake-configure-log(7)
  • cmake-cxxmodules(7)
  • cmake-developer(7)
  • cmake-env-variables(7)
  • cmake-file-api(7)
  • cmake-generator-expressions(7)
  • cmake-generators(7)
  • cmake-language(7)
  • cmake-modules(7)
  • cmake-packages(7)
  • cmake-policies(7)
  • cmake-presets(7)
  • cmake-properties(7)
  • cmake-qt(7)
  • cmake-server(7)
  • cmake-toolchains(7)
  • cmake-variables(7)
  • cpack-generators(7)

3. 入门教程

官网教程:https://cmake.org/cmake/help/latest/guide/tutorial/index.html

官网教程源码:https://github.com/Kitware/CMake/tree/master/Help/guide/tutorial

入门教程分为

  • cmake教程 CMake Tutorial
  • 用户交互指南 User Interaction Guide
  • 使用依赖指南 Using Dependencies Guide
  • 导入导出指南 Importing and Exporting Guide
  • IDE集成指南 IDE Integration Guide

这里我们只关注最常用的 cmake 教程

3.1 basic

1
2
3
4
5
6
# 指定最低 cmake 版本
cmake_minimum_required(VERSION 3.10)
# 指定项目名
project(Tutorial)
# 指定输出可执行文件
add_executable(Tutorial tutorial.cxx)

3.2 库编译链接

1
add_library(<name> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [<source>...])

下面以静态库为例

静态库 cmakelists.txt

1
2
# 指定代码文件,编译生成静态库
add_library(MathFunctions MathFunctions.cxx mysqrt.cxx)

可执行文件 cmakelists.txt

1
2
3
4
5
6
7
8
9
10
11
# 编译时添加子目录编译(若引入三方静态库,这个不需要)
add_subdirectory(MathFunctions)
# 指定代码文件,编译生成可执行文件
add_executable(Tutorial tutorial.cxx)
# 添加依赖的静态库(此处是子项目生成的 libMathFunctions.a 库)
target_link_libraries(Tutorial PUBLIC MathFunctions)
# 添加依赖库的头文件读取路径
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/MathFunctions"
)

3.3 cmake 编译选项使用

cmake 创建选项

1
option(USE_MYMATH "Use tutorial provided math implementation" ON)

cmake 中判断选项,给编译过程设置宏定义

1
2
3
if (USE_MYMATH)
target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
endif()

代码中使用编译选项宏

1
2
3
4
5
6
7
8
9
#ifdef USE_MYMATH
#include "mysqrt.h"
#endif
...
#ifdef USE_MYMATH
return detail::mysqrt(x);
#else
return std::sqrt(x);
#endif

编译命令中设置选项

1
cmake ... -DUSE_MYMATH

3.4 requirements

库项目设置

1
2
3
4
# INTERFACE 指定引用者需要将代码所在目录添加为 include 路径,但是自己不需要
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)

引用项目不再需要设置 include 目录

1
2
3
4
5
# 下面的设置不再需要
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/MathFunctions"
)

3.5 通过 Interface 设置 C++ 规范

默认的设置方法是这样的

1
2
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

干掉这俩选项后

1
2
3
4
5
6
7
8
9
# 定义 tutorial_compiler_flags INTERFACE,并设置编译 features cxx_std_11
add_library(tutorial_compiler_flags INTERFACE)
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
...
# 设置链接库时,使用 tutorial_compiler_flags 指定c++标准库版本
target_link_libraries(Tutorial PUBLIC MathFunctions tutorial_compiler_flags)
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
...

3.6 测试

https://cmake.org/cmake/help/latest/guide/tutorial/Installing%20and%20Testing.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 启用检测能力
enable_testing()

add_test(NAME Runs COMMAND Tutorial 25)

add_test(NAME Usage COMMAND Tutorial)
set_tests_properties(Usage
PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
)

add_test(NAME StandardUse COMMAND Tutorial 4)
set_tests_properties(StandardUse
PROPERTIES PASS_REGULAR_EXPRESSION "4 is 2"
)

function(do_test target arg result)
add_test(NAME Comp${arg} COMMAND ${target} ${arg})
set_tests_properties(Comp${arg}
PROPERTIES PASS_REGULAR_EXPRESSION ${result}
)
endfunction()

# do a bunch of result based tests
do_test(Tutorial 4 "4 is 2")
do_test(Tutorial 9 "9 is 3")
do_test(Tutorial 5 "5 is 2.236")
do_test(Tutorial 7 "7 is 2.645")
do_test(Tutorial 25 "25 is 5")
do_test(Tutorial -25 "-25 is (-nan|nan|0)")
do_test(Tutorial 0.0001 "0.0001 is 0.01")

运行 ctest -N / ctest -VV

3.7 能力检测

在 cmakelists.txt 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 开启源码检测能力
include(CheckCXXSourceCompiles)
...
# 定义能力检测代码片段
check_cxx_source_compiles("
#include <cmath>
int main() {
std::log(1.0);
return 0;
}
" HAVE_LOG)
check_cxx_source_compiles("
#include <cmath>
int main() {
std::exp(1.0);
return 0;
}
" HAVE_EXP)
...
# 根据检测结果设置编译宏
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(SqrtLibrary
PRIVATE "HAVE_LOG" "HAVE_EXP"
)
endif()

target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
...
# 代码中根据宏实现不同逻辑
#if defined(HAVE_LOG) && defined(HAVE_EXP)
double result = std::exp(std::log(x) * 0.5);
std::cout << "Computing sqrt of " << x << " to be " << result
<< " using log and exp" << std::endl;
#else
double result = x;

// do ten iterations
for (int i = 0; i < 10; ++i) {
if (result <= 0) {
result = 0.1;
}
double delta = x - (result * result);
result = result + 0.5 * delta / result;
std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
}
#endif

3.8 设置默认编译动态/静态库

1
2
3
4
5
6
7
8
9
10
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")

option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
...
# 开启 PIC 选项
set_target_properties(SqrtLibrary PROPERTIES
POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
)

☞ 参与评论