%%
# 纲要
> 主干纲要、Hint/线索/路标
# Q&A
#### 已明确
#### 待明确
> 当下仍存有的疑惑
**❓<font color="#c0504d"> 有什么问题?</font>**
# Buffer
## 闪念
> sudden idea
## 候选资料
> Read it later
%%
# CMake 介绍
> ❓ <font color="#c0504d">什么是 CMake?</font>
CMake 是一个开源、跨平台的 **==构建工具==**,用于**自动生成平台特定的==标准构建文件==**,**供对应的构建系统使用**,例如:
- **Makefile 文件**——对应 make 工具
- **Visual Studio 解决方案文件(`.sln`)**——对应 Visual Studio IDE
- **Ninja 构建文件**——对应 Ninjia
> [!important] 关于 CMake
>
> 相较于 Make、VS 等特定构建工具, **CMake 处在更高抽象层**,提供了**统一的方法**来处理**不同平台和编译器的构建需求**。
>
> CMake 的**构建说明文件 `CMakeLists.txt` 采用==独立于平台、编译器、构建系统==的描述语法**,
> 而 CMake 据此**自动生成 "==平台特定的标准构建文件=="**:
>
> - 支持不同机器平台:Linux、Windows、macOS 等
> - 支持不同编译器:gcc/clang/vs 等
> - 支持不同构建系统:Make、Visual Studio、Ninja
>
> 生成构建文件之后,**实际的项目构建过程由 CMake ==调用==相对应的==构建工具/系统==(make、VS、Ninja)完成**。
>
<br><br>
## CMake 的特点
> ❓ <font color="#c0504d"> CMake 相较于 Make 工具有什么更好的优点?</font>
除了上文提到的 **"更高抽象层所带来的==跨平台、跨编译器、跨构建系统==的构建能力**" 之外,CMake 的还具有以下优点:
- (1)**配置依赖项管理**:
- **Make**:`Makefile` 中需要**手动指定和管理依赖项**,对于大型项目或有许多依赖的项目可能很麻烦。
- **CMake**:
- 提供了强大的模块和脚本,可以**自动发现和配置项目依赖项**,如库和工具。
- 提供了一套机制来**自动查找和使用系统上的库和工具**
- (2)**更高级的语言特性**
- **Make**:`Makefile` 语法相对简单,对于复杂项目可能难以管理和维护。
- **CMake**:提供了更高级的语言特性,支持**条件编译、用户定义的函数和宏**等
- (3)**集成测试和打包**
- **CMake**:除了构建外,还提供了测试(CTest)和打包(CPack)的集成支持
- **Make**:不具备
- (4)**用户界面**
- **CMake**:提供了图形界面工具(如 ccmake 或 CMake GUI),使得配置构建过程更加用户友好。
<br><br>
# CMake 的工作原理
CMake 的工作过程如下:
1. **生成构建系统文件**:CMake 读取 `CMakeLists.txt` 文件并生成**适合当前平台和构建工具的构建文件**。
2. **调用构建工具完成构建**:生成了构建系统文件后,当执行 CMake 构建命令(如 `cmake --build .`)时,CMake 将根据生成的构建文件调用相应的构建工具,如 Make、Ninja 或 Visual Studio 等,**构建生成可执行文件或库**。

CMake 进行处理的 **==顶层入口点==** 是**顶层源码目录中的`CMakeLists.txt` 文件**。
当在该文件中使用 **`add_subdirectory()` 命令**添加了**子目录**时,
这些被添加的**每个子目录下也都必须包含一个`CMakeLists.txt`文件**,作为 **==子目录的入口点==**。
对于 `CMakeLists.txt` 文件被处理的每个源码目录,**CMake 都会在构建树中生成一个相应的目录**,作为其**默认的工作和输出目录**。
<br>
## CMake 的工作阶段
几个不同阶段:
- **配置阶段**(**Configure** Stage)
- 执行 `cmake [-S] <source_dir> [-B <build_dir>]`,在构建目录(`build`目录)中**生成==构建系统文件==**(Build System)。
- **构建阶段**(**Build** Stage)
- 执行 `cmake --build <build_dir>`,对**构建目录中的相关文件、源码进行编译链接**,生成**可执行文件或库文件**。
- **安装阶段**(**Install** Stage)
- 执行 `cmake --install <build_dir>`,将构建的可执行文件或库文件**复制**到**系统的指定路径(通常设置为系统的标准目录,例如`/usr/local/bin`、`/usr/local/lib`等)**,使得可执行文件或库文件在系统范围内可用。
<br><br><br>
# CMake 基本概念
CMake 中的一些基本概念定义及含义:
- **构建系统**(Build Systems)
- **生成器**(Generator)
- **构建目标**(Binary Target)
- **源代码树**(Source Tree)
- **构建树**(Build Tree),也称 **二进制树**(Binary Tree)
###### 构建系统(Build Systems)
**构建系统**包括**用于实际执行编译链接等构建任务的工具集合**以及**相关文件**:
1. **构建工具**:实际执行编译和链接操作的工具,如 Make、Ninja、Visual Studio 等。
2. **构建文件**:由 CMake 生成并**由对应构建工具读取和执行的文件**,如 Makefile、Visual Studio 项目文件(`.vcxproj`)、Ninja 构建文件等。
3. **构建配置**:指定如何构建项目的配置选项,包括编译器选项、链接器选项、目标平台等。
###### 生成器(Generator)
生成器是 CMake 用以**产生特定构建文件**的工具。
**不同的生成器用以创建不同的构建系统文件**——Makefile、Visual Studio 解决方案、或是 Ninja 构建文件等。
在 Unix-like 系统上,默认生成器为 `"Unix Makefiles"`,可使用 `cmake --help` 命令**查看可用的所有生成器**。
###### 源代码树(Source Tree)
CMake 项目中的整个 **源代码目录** 构成了一棵 **源代码树**,包括 **顶层源码目录** 和 **其中的子目录**。
**顶层源码目录** 即包含**项目源文件**的**顶层目录**,顶层目录下需要包括:
- 顶层 `CMakeLists.txt` 构建说明文件
- 预设配置文件 `CMakePresets.json` 或 `CMakeUserPresets.json` 。
顶层源码目录由变量 **`CMAKE_SOURCE_DIR`** 指定,即 CMake 命令中的`<source_dir>`。
###### 构建树 (Build Tree)
CMake 项目中的整个 **构建目录** 构成了一棵 **构建树**,包括 **顶层构建目录** 和 **其中的子目录**。
构建目录是用于**生成构建系统文件**和**构建输出工件**(编译生成的可执行文件或库文件)的**目录**。
顶层构建目录由变量 `CMAKE_BINARY_DIR` 指定,通常即 `build` 目录,即 CMake 命令中的 `<build_dir>`。
###### 构建目标(Binary Target)
`CMakeLists.txt` 文件中通过 `add_executable()` 或 `add_library()` 描述的每个**可执行文件** 或 **库文件** 都是一个构建目标。
此外,还有一系列 **CMake 内置的特殊目标**,用以实现特定功能。
<br><br><br>
# CMake 项目构建步骤说明
#### CMake 项目中的目录组织—— "构建目录" 与 "源代码目录"
- 「**源代码目录**」即**项目根目录**,也即顶层 `CMakeLists.txt` 文件以及预设配置文件 `CMakePresets.json` 所在的目录
- 「**构建目录**」是用于**存放 ==CMake 生成的所有相关文件==的目录**,包括其生成的**构建系统文件**以及**最终构建生成的可执行文件**等。
通常在一个 CMake 项目中,会在**项目根目录**下创建一个名为 ==`build`== 的子目录作为 "**构建目录**"。
#### 预备过程
- **编写 `CMakeLists.txt` 配置文件**,通常放置于项目根目录。
- **创建 `build` 构建目录**:在项目根目录中创建一个名为 `build` 的子目录(`cmake` 默认识别该名称,但也可以指定其他名称)
#### 项目构建过程
- (1)**==生成"构建系统文件"==**——Makefile、Ninja 构建文件、或 VS 解决方案等
- 在 `build` 构建目录下**执行 `cmake ..` 命令** (`..` 指定的是**项目源文件根目录**)<br>=> CMake在当前工作目录中生成相应的构建文件。
- (2)**==构建项目==**——编译项目源代码,产出可执行文件或库文件
- 在 `build` 构建目录下**执行 `cmake --build .` 命令** <br>=> CMake 根据生成的构建文件 (如 Makefile) 调用对应的构建工具(如 Make 工具),完成项目构建
> [!NOTE] 单目标构建
>
> 在 CMake 项目中,若想要**构建和运行单个 c/cpp 文件**,需要在 **CMakeLists. txt 需要配置声明 `add_executable()`** 。
> 在 CLion 中,使用`C/C++ Single File Execution` 插件可以自动化上述过程,快捷构建和运行单个文件。
>
> [!example]
>
> 
>
> [!example]
>
> 
>
> 
>
>
>
<br>
### 不同平台下 CMake 使用说明
###### 在 windows 平台下使用 CMake 生成 **VS 项目**并编译的流程
1. 编写 CMake 配置文件 CMakeLists. txt 。
2. 源码目录下面创建一个构建目录 `build` ,用于生成 cmake 的临时文件和构建文件。
3. 进入`build` 目录,执行命令 `cmake PATH` 生成构建系统( **Visual Studio 解决方案** )
- 其中,PATH 是 `CMakeLists.txt` 所在的目录。
4. 编译构建项目:
- **方式一**:**进入构建目录`build` 下运行 `cmake --build .` 命令**
- 方式二(不推荐):直接进入`build`目录,打开 vs 解决方案进行编译;
###### 在 linux 平台下使用 CMake 生成 **Makefile** 并编译的流程
1. 编写 CMake 配置文件 CMakeLists. txt 。
2. 源码目录下面创建一个构建目录 `build` ,用于生成 cmake 的临时文件和构建文件。
3. 进入`build` 目录,执行命令 `cmake PATH` 或 `ccmake PATH` 生成构建系统(**Makefile**)
- 其中,PATH 是 `CMakeLists.txt` 所在的目录。
4. 编译构建项目:
- **方式一**:**进入构建目录`build` 下运行 `cmake --build .` 命令**
- 方式二(不推荐):直接进入`build`目录,使用 make 命令进行编译(编译器为 gcc 或 clang)
<br><br><br>
# CMake 语言源文件
**CMake 语言源文件** [^1] 是指使用 **CMake 规定的语法**进行编写,可被 CMake 解析后据此执行的文件,包括
| 文件类型 | 文件名 |
| ---------------------- | ---------------- |
| CMake 目录文件,Directories | `CMakeLists.txt` |
| CMake 脚本,Scripts | `<script>.cmake` |
| CMake 模块,Modules | `<module>.cmake` |
# CMake 构建描述文件——`CMakeLists.txt`
`CMakeLists.txt` 文件描述了如何构建项目,**定义了整个项目的构建规则,包括源文件、目标文件、依赖关系、编译选项**等。
#### CMakeLists. txt 示例
示例一:CLion 项目中初始`CMakeLists.txt` 的内容
```cmake title=CMakelists.txt
cmake_minimum_required(VERSION 3.26)
project(cmake_demo)
set(CMAKE_CXX_STANDARD 14)
add_executable(cmake_demo
main.cpp)
```
示例二:**为指定目录下的每个 `.cpp` 源文件分别生成独立的可执行文件**
```cmake
file(GLOB PROJECT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}} *.cxx)
foreach(testsourcefile IN LISTS ${PROJECT_SOURCE})
# 使用如下语句提前文件名(`NAME_WE`模式: 不带目录, 不带扩展)
# get_filename_component(<var> <FileName> <mode> [CACHE])
get_filename_component(EXECUTABLE_NAME ${testsourcefile} NAME_WE)
# 添加可执行目标
add_executable(${testname} ${testsourcefile})
# 为每个目标链接到测试库
target_link_libraries(${testname} lib_dir)
# Copy required DLLs to the target folder
add_custom_command(
TARGET ${EXECUTABLE_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/Resources/Libraries/glew/bin/glew32.dll" "${CMAKE_BINARY_DIR}/glew32.dll")
endforeach(testsourcefile ${PROJECT_SOURCE})
```
示例三:杂乱项 ❌
```cmake title=CMakelists.txt
# 声明构建项目所需的最低cmake版本要求. 项目最顶层的CMakeLists.txt必须以该句命令作为起始内容.
cmake_minimum_required (VERSION 3.26)
# 设置当前项目名称. 该语句应当紧随上一句之后.
project(MyProject)
project(MyProject VERSION 1.0) # 可在设置项目名的同时指定版本号.
# 指定构建项目所需的c++标准. 该语句必须放在add_executable()之前.
set(CMAKE_CXX_STANDARD 14)
# 该语句确保必须采用指定C++标准. 若编译器不支持指定的 C++ 标准, 则CMake 配置过程将会失败。
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 设置c++编译器
set(CMAKE_CXX_COMPILER "g++")
# 设置编译标志(应当以追加的形式, 设置时引用${CMAKE_CXX_FLAGS}变量本身, 再设置追加项)
# 如下所示, 启用了额外的警告信息、调试信息,并定义了一个宏, 同时设置编译器优化级别为`-02`.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -g -DMY_MACRO -02")
# 添加子目录到构建中
# 该命令会将指定的子目录添加到CMake"源码树"或"构建树".
# `source_dir`指定"源码子目录", CMake将进入并处理该子目录中的`CMakeLists.txt`文件.
# `binary_dir`指定"构建子目录", CMake根据`source_dir`中的配置文件进行配置或构建时产出的相关文件(构建系统、编译生成的二进制文件等)将存放在该`binary_dir`中.
# - 如果为相对路径, 则是"相对于"当前构建目录". 也可指定为绝对路径.
# - 未指定时, 默认同`source_dir`.
add_subdirectory(<source_dir> [binary_dir])
# 添加头文件的搜索路径(对整个项目中该语句后的所有构建目标有效, 而target_include_directories针对单个目标)
include_directories(${PROJECT_SOURCE_DIR}/header)
# 添加库文件的搜索路径(对整个项目中该语句后的所有构建目标有效, 而target_linke_directories针对单个目标)
link_directories(<lib_dir>)
# 添加所需链接的依赖库(对整个项目中该语句后的所有构建目标有效, 而target_link_libraries针对单个目标)
link_libraries(<libName>)
# 查找指定目录下的所有源文件(不会递归查找子目录), 并将文件列表存储在一个变量VARIABLE中.
# 该命令常用于自动收集一个目录中的源文件, 从而减少手动指定.
aux_source_directory(dir VARIABLE)
add_executable(MyExecutable ${VARIABLE})
# 该命令将复制"输入配置文件",并使用当前变量值"替换掉文件内容中的变量引用"(`@VAR@`、`${VAR}`、`$CACHE{VAR}` 或`$ENV{CAR}` ),然后"输出为指定文件"。
configure_file(TutorialConfig.h.in TutorialConfig.h)
# 设置编译给定目标时使用的包含目录(#include文件查找目录) 相当于gcc命令中`-I`选项.
# 命名的<target>必须是由add_executable()或add_library()等命令创建的,并且不能是ALIAS目标。
target_include_directories(<target> PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/MathFunctions"
)
# 设置指定链接器在链接给定目标时搜索库的路径. 相当于gcc命令中`-L`选项.
target_link_directories(<target> [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...]
)
# 设置编译给定目标时所需链接的依赖库. 相当于gcc命令中的`-l`选项.
# 构建目标(Binary Targets)之间的依赖关系由该命令指定.
# ITEM可以是库文件名, 包含库文件名的绝对路径, 或者库目标名libary target name.
target_link_libraries(<target> PUBLIC <item>)
# 示例:
# Use target_link_libraries to link the library to our executable
target_link_libraries(MyTarget PUBLIC MathFunctions)
# 为指定构建目标添加"编译时定义的宏".
# 在编译特定目标时传递预处理器宏定义,用以控制代码中的条件编译或传递编译时配置信息.
target_compile_definition(<target> <PRIVATE|PUBLIC|INTERFACE> [items1...])
# 示例: 为 mylib 添加宏定义
target_compile_definitions(mylib PRIVATE MYLIB_DEFINE)
# 示例: 为 myapp 添加宏定义
target_compile_definitions(myapp PRIVATE MYAPP_DEFINE=5)
# 为构建目标指定"所需的编译器特性". 例如,特定版本的C++标准等.
# 其中<feature>只能是CMAKE_C_COMPILE_FEATURES, CMAKE_CUDA_COMPILE_FEATURES, 或
# CMAKE_CXX_COMPILE_FEATURES中包含的变量.
target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature>[...])
# 示例: 为构建目标添加"cxx_std_11"特性.
target_compile_features(<target> INTERFACE cxx_std_11)
# 为构建目标添加"编译器选项"(编译标志)
# 该命令为特定的构建目标设置编译器选项(编译标志),从而优化和调整不同目标的编译行为.
target_compile_options(<target> <PRIVATE|PUBLIC|INTERFACE> [items...])
# 设置可执行文件输出路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
# 定义一个所需生成的可执行文件,并指定所涉及的源代码文件.
add_executable(MyProgram
main.cpp)
# 定义一个所需生成的库文件(默认为静态库), 并指定所涉及的源代码文件.
# 可通过`BUILD_SHARED_LIBS`变量来指定`add_library()`的默认行为
add_library(MyLibrary
libmain.cpp)
# 通过`STATIC`关键字显式指定生成静态库(默认).
add_library(archive STATIC archive.cpp zip.cpp lzma.cpp)
# 通过`SHARED`关键字指定生成动态库
add_library(archive SHARED archive.cpp zip.cpp lzma.cpp)
# 通过`MODUEL`关键字指定生成模块库
add_library(archive MODULE archive.cpp zip.cpp lzma.cpp)
# 定义一个`OBJECT`库
add_library(archive OBJECT archive.cpp zip.cpp lzma.cpp)
# 定义一个`INTERFACE`库并设置相关编译属性
add_library(my_interface_lib INTERFACE)
target_include_directories(my_interface_lib INTERFACE include/)
target_compile_definitions(my_interface_lib INTERFACE SOME_DEFINITION)
# 将子目录添加到构建中.
# `source_dir`指定源代码文件以及次级`CMakeLists.txt`所在的子目录.
# `binary_dir`可选, 指定"放置输出文件的目录". 未设置时, 同source_dir.
add_subdirectory(source_dir [binary_dir])
# 设置一个布尔选项. `[value]`可以是ON或OFF, 未指定时默认为OFF.
option(<variable> "<help_text>" [value])
# 示例: Create a variable USE_MYMATH using option and set default to ON
option(USE_MYMATH "Use tutorial provided math implementation" ON)
# 条件语句
if()
#...
endif()
# 示例:
# If USE_MYMATH is ON, use target_compile_definitions to pass
# USE_MYMATH as a precompiled definition to our source files
if (USE_MYMATH)
target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
endif()
# 函数
function(func_name arg1 arg2 arg3)
#...
#do something with ${arg1}, ${arg2}, ${arg3}
endfunction()
# 使用列表变量(本质上是由分号作为分隔符的字符串序列)
# 示例:
set(installable_libs MathFunctions tutorial_compiler_flags)
if(TARGET SqrtLibrary)
list(APPEND installable_libs SqrtLibrary)
endif()
install(TARGETS ${installable_libs} DESTINATION lib)
# 使用FetchContent模块
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
# 该语句确保Google Test使用与主项目相同的运行时库配置构建. 无论是多线程 DLL (/MD) 还是多线程调试 DLL (/MDd)
# `gtest_force_shared_crt ON` 表示Google Test使用与主项目相同的动态链接的CRT
# `CACHE BOOL` 表示将变量设置为一个持久的布尔类型的缓存变量.
# `FORCE` 表示强制应用该设置, 无论缓存中是否已存在该变量.
# 这条语句确保在构建 Google Test 时使用的 CRT 设置与项目中的其他部分相匹配,特别是当使用 Microsoft Visual Studio 时。不匹配的 CRT 设置可能会导致运行时错误,特别是在处理 CRT 资源(如内存分配)时。
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
```
<br><br><br>
# CMake 预设配置文件——`CMakePresets.json`
> [!NOTE] 关于 CMake Presets
>
> CMake Presets 是 CMake 3.19 版本起引入的功能,通过**项目根目录下的一个 JSON 文件**(通常命名为 `CMakePresets.json`) 来定义**该项目的构建配置**,指定**编译工具、构建模式**等,CMake 将**使用该文件指定的编译工具集进行构建**。
>
> [!NOTE]
>
> - `CMakeLists.txt` 是 "**项目构建说明文件**",指定**项目构建目标、依赖关系**等。
> - `CMakePresets.json` 是**定义 "==cmake 行为=="** 的文件,例如指定**生成器**、**`cache`变量**等,
`CMakePresets.json` 文件中**定义了该 CMake 项目的==预设配置项==**(Presets),
供 `cmake` / `cmake --build`/`ctest` 等命令**通过 `--preset` 选项使用**,
配置项中**指定了 cmake 的配置/构建/测试时的行为**,例如指定**生成器**、**`cache`变量** 等。
#### 作用
通过在 `CMakePresets.json` 文件中定义预设,可以**标准化项目配置的过程**:
- (1)**减少在命令行上输入长串 CMake 参数的需要**;
- (2)可为**不同构建环境(如不同的操作系统、编译器、构建类型等)定义不同的预设**,便于在多种环境中切换和使用。
- (3)`CMakePresets.json` 文件可以被添加到版本控制系统如 git 中,供团队成员之间共享配置。
> [!example] `CMakePresets.json` 文件示例:
>
> ![[_attachment/05-工具/CMake 构建工具/CMake 说明.assets/IMG-CMake 说明-918CA6062D6C97FDBAF78081F128C657.png|591]]
>
<br>
### 两种配置预设文件
> 这**两个文件通常放在项目根目录**中,与`CMakeLists.txt` 同级,从而被 CMake 识别读取
CMake 支持名为 **`CMakePresets.json ` 与 `CMakeUserPresets.json`** 两个预设配置文件。
两个文件的差异主要在于**用途**和**目标用户**不同:
- `CMakePresets.json ` :
- 由**项目维护者创建和维护**,用于为**整个项目**定义一系列标准的构建和测试配置。
- 该文件**通常被包含在项目的源代码版本控制**中,为所有项目贡献者共享,确保所有人在统一环境下工作。
- 该文件通常会包含多个不同的构建预设,**涵盖了项目支持的各种构建环境和配置**。
- `CMakeUserPresets.json`:
- 用于**个别用户的自定义配置**。
- 允许用户根据个人的开发环境和偏好自定义构建和测试配置,而**不影响其他用户或项目的默认设置**。
- 这个文件通常**不被包含**在项目的源代码版本控制中,是**用户个人本地的配置文件**。
(在 `.gitignore` 里加入,从而不进行追踪)
> [!NOTE] 当两个文件同时存在时,`CMakeUserPresets.json` 将**默认隐式地 `include` 包含`CMakePresets.json`**。
<br>
### 查看所有可用的预设配置
`cmake -S <source_sir> --list-presets`
该命令将列出 `<source_dir>/CMakePresets.json` 与 `<source_dir>/CMakeUserPresets.json` 文件中**所有可用的预设参数定义**。
### 文件内容说明
`CMakePresets.json` 中包含的各字段如下,各字段内的具体参数参见官方文档[^2]。
字段:
- `version`:指定**文件格式的版本**。用于指示 CMake 如何解析和理解该文件中的内容。
- 例如设置`"version": 6` 表示该 `CMakePresets.json` 文件遵循第 6 版的文件格式规范。
- `cmakeMinimumRequired`:指定所需的最低 CMake 版本,包括`major`、`minor`、`patch` 三个字段版本号。
- `include`:引入**其它 `.json` 预设配置文件**。(**版本 4** 以上有效)
- 被引入文件的命名可以自定义,这些文件需要被 `CMakePresets.json` 或 `CMakeUserPresets.json` 通过该字段引入后才能被 CMake 识别并生效。
- `configurePresets`:定义 **==配置==阶段** 的预设参数,**每个预设包含了用于配置项目的一组参数**。
- 该字段定义的预设参数用于`cmake <source_dir>` 命令。
- `buildPresets`:定义 **==构建==阶段** 的预设参数,包括**构建目标、构建配置**等。
- 该字段定义的预设参数用于 `cmake --build <build_dir>` 命令
- `testPresets`:定义**测试运行**的预设参数,包括测试配置、环境变量、额外参数等
- 该字段定义的预设参数用于 `ctest` 命令。
- `packagePresets`:定义**打包阶段**的预设参数,即定义如何生成安装包或分发文件。
- 用于构建包或分发物,如使用 `CPack`。
- `workflowPresets`:定义 "**一个完整的从配置到构建、测试、打包的工作流**" 的预设参数。
- 可以结合上述几个阶段的预设,创建完整的工作流配置。
- `vendor`: 可选的字段,主要用于提供额外的、**特定于供应商或工具链的配置和扩展**。
- 该字段可以被用来定义**特定于供应商(比如 IDE 或构建系统供应商)的特殊配置选项**,例如对于一些集成了 CMake 支持的 IDE(如 VS、CLion 等),可以用来设置 IDE 特定的配置选项,从而增强特定环境或工具链的兼容性和集成度。
> [!NOTE] 预设配置文件中**可以为各个阶段定义预设参数**,配置各阶段的具体参数和行为。
>
> `configurePresets`、`buildPresets`、`testPresets`、`packagePresets`、`workflowPresets` 字段分别在版本 1、2、2、6、6 及以上的预设配置文件中有效。
### 文件示例
`CMakePresets.json` 文件示例:
```json
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 23,
"patch": 0
},
"include": [
"otherThings.json",
"moreThings.json"
],
// 定义配置预设
"configurePresets": [
{
"name": "default",
"displayName": "Default Config",
"description": "Default build using Ninja generator",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/default",
"cacheVariables": {
"FIRST_CACHE_VARIABLE": {
"type": "BOOL",
"value": "OFF"
},
"SECOND_CACHE_VARIABLE": "ON"
},
"environment": {
"MY_ENVIRONMENT_VARIABLE": "Test",
"PATH": "$env{HOME}/ninja/bin:$penv{PATH}"
},
"vendor": {
"example.com/ExampleIDE/1.0": {
"autoFormat": true
}
}
},
{
"name": "ninja-multi",
"inherits": "default",
"displayName": "Ninja Multi-Config",
"description": "Default build using Ninja Multi-Config generator",
"generator": "Ninja Multi-Config"
},
{
"name": "windows-only",
"inherits": "default",
"displayName": "Windows-only configuration",
"description": "This build is only available on Windows",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
}
],
// 定义构建预设
"buildPresets": [
{
"name": "default",
"configurePreset": "default"
}
],
// 定义测试预设
"testPresets": [
{
"name": "default",
"configurePreset": "default",
"output": {"outputOnFailure": true},
"execution": {"noTestsAction": "error", "stopOnFailure": true}
}
],
// 定义打包预设
"packagePresets": [
{
"name": "default",
"configurePreset": "default",
"generators": [
"TGZ"
]
}
],
// 定义工作流预设
// "steps"中每一项"name"对应上面已定义的预设.
"workflowPresets": [
{
"name": "default",
"steps": [
{
"type": "configure",
"name": "default"
},
{
"type": "build",
"name": "default"
},
{
"type": "test",
"name": "default"
},
{
"type": "package",
"name": "default"
}
]
}
],
"vendor": {
"example.com/ExampleIDE/1.0": {
"autoFormat": false
}
}
}
```
### 使用说明
###### (1)定义 CMakePresets.json 文件
```json
{
"version": 1,
"cmakeMinimumRequired": {
"major": 3,
"minor": 19,
"patch": 0
},
"configurePresets": [
{
"name": "default",
"description": "Default build with gcc",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++"
}
},
{
"name": "ninja-release",
"description": "build with Ninja generator and Release type",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
]
}
```
该文件中定义了两个分别名为 `"default"` 和 `"ninja-release" ` 的 Preset 项:
- `default`: 使用了 Unix Makefiles 生成器和 gcc 编译器。
- `ninja-release`:使用 ninja 生成器并构建 Release 类型。
###### (2)在运行 `cmake` 命令时通过 `--preset` 选项指定 Preset 配置项
cmake 会在 `-S` 指定的源代码目录下自动寻找 `CMakePresets.json` 或 `CMakeUserPresets.json` 文件,**`--preset` 选项参数为文件中 Preset 项的 `"name"`**。
```shell
# 使用`ninja-release`预设中定义的参数来进行配置
cmake -S <source_dir> --preset=ninja-release
```
<br><br>
# 使用 CMake-GUI

<br><br>
# 参考资料
##### CMake 使用示例
- [cmake多文件多目录工程模板](https://www.cnblogs.com/tla001/p/6827808.html)
- [CMakeLists常用模版](https://github.com/ganleiboy/CMakeTutorial)
# Footnotes
[^1]: [cmake-language(7)](https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#id9)
[^2]: [cmake-presets(7)](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html#id2)