CMake 入门

官方教程

构建基础 CMake 项目

01 CMake 最基本组成

一个基础项目由 CMakeLists.txt 文件包含三句命令组成

目录结构

1
2
3
- Help/guide/tutorial/Step1
- tutorial.cxx
- CMakeLists.txt

CMakelists.txt

1
2
3
4
5
6
# 1(必须)- 项目顶部指定最低可用CMake版本
cmake_minimum_required(VERSION 3.10)
# 2(必须)- 指定项目名、语言及版本号等,必须在CMake版本声明之后
project(Tutorial)
# 3(必须)- 告知CMake用于生成可执行程序的源代码文件
add_executable(Tutorial tutorial.cxx)

02 CMAKE_开头变量

通常以 CMAKE_开头的变量在 CMake 中有特殊含义,如CMAKE_CXX_STANDARDCMAKE_CXX_STANDARD_REQUIRED配合使用可以用于指定 C++标准,可以通过set()命令定义变量

CMakelists.txt

1
2
3
# 指定使用 C++11 标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

03 使用配置头文件

当我们需要 CMakelists.txt 中定义的变量在源代码中可见,可以通过配置头文件实现 通过configure_file()命令替换输入文件中的由 CMakelists.txt 定义的变量值,然后复制到输出文件中

CMakelists.txt

1
2
3
4
5
6
7
8
# 执行 project() 命令时,CMake 自动定义 Tutorial_VERSION_MAJOR 变量 和 Tutorial_VERSION_MINOR 变量
project(Tutorial VERSION 1.0)
# TutorialConfig.h.in 作为输入配置头文件,变量 @Tutorial_VERSION_MAJOR@ 和 @Tutorial_VERSION_MINOR@ 在 TutorialConfig.h 中将会被替换
configure_file(TutorialConfig.h.in TutorialConfig.h)
# 配置文件将输出到${PROJECT_BINARY_DIR}目录,添加该目录用于让CMake搜寻需要include的文件
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)

TutorialConfig.h.in

1
2
3
// Tutorial 项目配置
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

tutorial.cxx

1
2
3
4
5
6
7
8
9
#include "TutorialConfig.h"

if (argc < 2) {
// 输出项目版本
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
<< Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}

添加库文件

01 创建一个库

  • 通过add_library()命令添加库,并指定组成该库的源文件
  • 通过add_subdirectory()命令添加子目录用于构建项目
  • 通过target_include_directories()target_link_libraries()命令链接到可执行目标

目录结构

1
2
3
4
5
6
7
8
9
10
11
- Help/guide/tutorial/Step2
- CMakeLists.txt
- tutorial.cxx
- MathFunctions
- CMakeLists.txt
- MathFunctions.h
- mysqrt.h
- MathFunctions.cxx
[function] sqrt
- mysqrt.cxx
[function] mysqrt

MathFunctions/CMakeLists.txt

1
2
# 创建 MathFunctions 库
add_library(MathFunctions MathFunctions.cxx mysqrt.cxx)

CMakeLists.txt

1
2
3
4
5
6
7
8
9
# 使用 MathFunctions 库
add_subdirectory(MathFunctions)
# 链接库到可执行目标
target_link_libraries(Tutorial PUBLIC MathFunctions)
# 指定库头文件位置,使得 MathFunctions.h 头文件可见
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/MathFunctions"
)

tutorial.cxx

1
2
#include "MathFunctions.h"
const double outputValue = mathfunctions::sqrt(inputValue);

02 添加 Option

通过 option() 命令为用户提供变量用于配置构建,该配置将会保存在 cache,因此用户不需要每次都设置

MathFunctions/CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 相比于之前的配置移除了 mysqrt.cxx 文件,变更为随着 USE_MYMATH 的设置动态链接,减少资源消耗
add_library(MathFunctions MathFunctions.cxx)

# 为用户提供选项 USE_MYMATH,默认为 ON
option(USE_MYMATH "Use tutorial provided math implementation" ON)
# 创建 if() 语句检查 USE_MYMATH 的值
if (USE_MYMATH)
# 设置编译定义 USE_MYMATH,可用于源代码中段的启用和废用
target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
# 创建额外的库 SqrtLibrary 负责 mysqrt.cxx 的编译
add_library(SqrtLibrary STATIC
mysqrt.cxx
)
# 链接 SqrtLibrary 库到 MathFunctions
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()

MathFunctions/MathFunctions.cxx

1
2
3
4
5
6
7
8
9
10
11
12
// 通过 USE_MYMATH 变量判断是否引入头文件
#ifdef USE_MYMATH
# include "mysqrt.h"
#endif
#include <cmath>

// 通过 USE_MYMATH 变量选择使用的 sqrt 方法
#ifdef USE_MYMATH
return detail::mysqrt(x);
#else
return std::sqrt(x);
#endif
Author

derolol

Posted on

2024-11-13

Updated on

2024-11-13

Licensed under

p