%%
# 纲要
> 主干纲要、Hint/线索/路标
# Q&A
#### 已明确
#### 待明确
> 当下仍存有的疑惑
**❓<font color="#c0504d"> 有什么问题?</font>**
# Buffer
## 闪念
> sudden idea
## 候选资料
> Read it later
%%
# CMake 命令总览
> [!NOTE] 命令一览
>
> 参见 [^1]
>
> 
>
> ^j44vzu
# cmake 命令
`cmake [<options>] <path-to-source>`: 在**指定目录查找 `CMakeLists.txt` 文件**,而后在 "**当前工作目录**" 下生成**构建系统**。
选项参数:
- `-S <path-to-source>` 指定**源代码目录的路径**,`-S `可省略。
- CMake 将在该路径中寻找`CMakeLists.txt` 文件。
- `-B <path-to-build>` 指定**构建目录**。
- `-G <generator>` 指定**生成器**(Generator)。
- 在 Unix-like 系统上,默认生成器为 `"Unix Makefiles"`;可使用 `cmake --help` 命令**查看可用的所有生成器**。
- 对于**VS 生成器**,可使用以下选项:
- `-A`: 指定架构类型,包括 `x64`, `ARM`, `ARM64`, `Win32`。默认为`x64`。
- `-T`: 指定使用的工具链,例如`ClangCL`,`host=64` 等。
- `-D <var>=<value>` ,`-D <var>:<type>=<value>` :**创建或更新 CMake 的缓存项(`CACHE` entry)**
- 该选项用以指定"**缓存变量的初始值**",此处指定的缓存初始值优先级高于 `CMakeCache.txt` 中的值。
- 该选项可在命令中多次使用,为多个 CACHE 条目设置初始值。
- `--preset <preset>`, `--preset=<preset>` :使用**预设的配置相关参数**。
- `-C <initial-cache>`:预加载一个 CMake 脚本来**设置缓存变量的初始值**
- `--install-prefix <directory>`:指定安装目录,由`CMAKE_INSTALL_PREFIX`变量使用。必须是绝对路径。
- `--no-warn-unused-cli`:不要对命令行选项发出警告。不要查找在命令行中声明但没有使用的变量。
#### 常用构建变量
> 参见[^2]
> 
- `CMAKE_C_COMPILER` , `CMAKE_CXX_COMPILER`:指定编译器路径
- `CMAKE_BUILD_TYPE`:指定构建类型,`Debug` 或`Release`,仅对单配置构建系统有用
- `CMAKE_PREFIX_PATH`:指定搜索依赖包的路径
- `CMAKE_MODUEL_PATH`:指定搜索 CMake 模块的额外路径
- `CMAKE_EXPORT_COMPILE_COMMANDS`:是否在构建目录下生成 `compile_commands.json` 文件
- `BUILD_SHARED_LIBS`:指定 `add_library()` 命令的默认行为为构建共享库。
#### 关于 `-DCMAKE_BUILD_TYPE` 与 `--config` 选项的差异
两个选项都用于**指定构建类型为 Debug 模式**,但作用阶段不同,且分别适用于单配置生成器和多配置生成器。
- `cmake` 命令中的 **`-DCMAKE_BUILD_TYPE` 选项**——针对 **==单配置==生成器**:在 **==配置==阶段**使用;
- 使用示例:`cmake <source_dir> -DCMAKE_BUILD_TYPE=Debug`
- `cmake --build` 命令中的 **`--config` 选项**—— 针对 **==多配置==生成器**,在 **==构建==阶段**使用;
- 使用示例: `cmake --build <build_dir> --config Debug`
> [!quote]
> The [--config](https://cmake.org/cmake/help/latest/manual/cmake.1.html#cmdoption-cmake-build-config) option has no effect if the generator generates a buildsystem specific to a configuration which is chosen when invoking cmake with the [CMAKE_BUILD_TYPE](https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html#variable:CMAKE_BUILD_TYPE) variable.
> [!info] 关于 「**单配置生成器**」与「 **多配置生成器**」:
>
> - **单配置生成器**:如 `Unix Makefiles` 或 `MinGW Makefiles`,**这类生成器一次只能构建一种配置类型**,因此需要在配置阶段指定整个构建的配置类型为 `Debug `或 `Release`,这决定了编译器的调试/优化标志。
>
> >
>
> - **多配置生成器**:如 Visual Studio 解决方案,能够**在单个构建目录中同时支持多种配置类型**(Debug、Release 等),
> 因此需要在构建阶段通过 `--config` **选择其中一种** 进行构建。
> - 对于多配置生成器,如果在配置阶段已通过 `-DCMAKE_BUILD_TYPE` 指定了特定构建类型,则 `--config` 选项将不再生效。
> [!summary] 总结
>
> - 在使用 Unix Makefiles 这样的**单配置生成器**时,通常**只需要在配置阶段设置** `CMAKE_BUILD_TYPE` 变量。
> - 而在使用 Visual Studio 解决方案这样的**多配置生成器**时,则需要**在构建阶段指定 `--config` 选项来选择特定的配置类型**。
>
>
#### 使用示例
示例:配置 CMake 项目
```shell
# 假设当前目录为项目根目录(源代码和CMakeLists.txt所在目录), 希望在其子目录`build`中进行构建
# 执行下述命令,CMake将在`build`目录中生成"构建系统"。
cmake -S . -B build
# 上述命令等价于
cd build
cmake ..
```
示例:指定生成器
```shell
# 生成标准的Unix Makefile.
cmake source_dir -G "Unix Makefiles"
# 生成适用于MinGW的Makefiles. (for use with mingw32-make)
cmake source_dir -G "MinGW Makefiles"
# 生成Visual Studio项目文件. 需要指定特定的VS版本
cmake source_dir -G "Visual Studio 17 2022"
# VS生成器可以使用`-A`选项指定架构类型(x64, ARM, ARM64, Win32; 默认为x64)
cmake source_dir -G "Visual Studio 17 2022" -A x64
cmake source_dir -G "Visual Studio 17 2022" -A ARM
# VS生成器可使用`-T`指定所用的工具链.
# Build with the clang-cl toolset
cmake source_dir -G "Visual Studio 17 2022" -A x64 -T ClangCL
# select the 64-bit version of the host tools.
cmake source_dir -G "Visual Studio 17 2022" -A x64 -Thost=x64
```
示例:设置 CMake 变量或选项的值
```cmake
# CMakeLists.txt中
option(
gtest_force_shared_crt
"Use shared (DLL) run-time lib even when Google Test is built as static lib."
OFF)
```
```shell
# 生成构建系统时, 指定`gtest_force_shared_crt=ON`.
cmake -S . -B build -D gtest_force_shared_crt=ON
```
示例:设置 CMake 变量时指明 type
```shell
cmake -S . -B build
-DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE
-DCMAKE_BUILD_TYPE:STRING=Debug
-DCMAKE_C_COMPILER:FILEPATH="D:\Program Files\MinGW\mingw64\bin\gcc.exe"
-DCMAKE_CPP_COMPILER:FILEPATH="D:\Program Files\MinGW\mingw64\bin\g++.exe"
```
示例:指定构建类型(Debug 或 Release)
```shell
cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug
cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release
```
# cmake --build 命令
`cmake --build` 命令用以**完成==项目构建==**,其将会根据 `cmake` 生成的构建系统,
**自动调用相对应的==具体构建工具==(make、VS 的 msbuild 等)进行项目构建,编译生成可执行文件或库**。
命令: `cmake --build <dir> [<options>] [-- <build-tool-options>]`
选项:
- `--config <cfg>` :**指定配置类型**
- 对于支持**多配置生成器**(如 Visual Studio),可使用该选项来指定配置类型(Debug、Release 等)。
- 未指定时可能**默认为 Debug**。
- 示例:`cmake --build . --config Release`
- `--clean-first`: 先构建`clean`目标(即**清理之前的构建结果**),然后再开始新的构建。
- 如果仅需清理,可使用 `--target clean`。
- `--target <tgt>` , `-t <tg>`:指定**构建的目标**,而不是构建整个项目。
- 默认为 `--target all`,即构建项目中的所有目标。
- `--preset <preset>` :使用预设的构建相关参数。
- `-j<jobs>`, `--parallel <jobs>`: 按给定数量的作业**并行运行测试**。
- `--`:传递给 **构建工具**(如 `make` 工具)的选项参数
#### 示例
```shell
cmake --build . --config Release --target MyTarget -j4 --
```
这个命令在当前目录下构建名为 `MyTarget` 的目标,使用 `Release` 配置,并且进行并行编译
(**`-j4` 表示同时运行 4 个编译任务**)。
### 构建目标
`CMakeLists.txt` 文件中描述的**每个可执行文件 or 库**都是一个构建目标。
除此之外,CMake 提供了一些内置目标,提供特别的功能:
- `all` 目标:
- Makefile 和 Ninja 生成器使用的默认目标。**构建 buildsystem 中的所有目标**,**除了被 `EXCLUDE_FROM_ALL` 目标属性或 `EXCLUDE_FROM_ALL` 目录属性排除的目标**。名称`ALL_BUILD`用于 Xcode 和 Visual Studio 生成器。
- `help` 目标:
- 列出**可用于构建的目标**。当使用 Unix Makefiles 或 Ninja 生成器时,可以使用该目标。
- `clean` 目标:
- 用于清理构建:**删除构建目录下已构建的目标文件和其他输出文件**。
- 基于 Makefile 的生成器会为每个目录**创建一个`clean`目标**,这样就可以清理单个目录。
- Ninja 工具则提供了自己的细粒度 `-t clean` 系统。
- 使用示例:`cmake --build . --target clean`
- `test` 目标:
- 用于运行**所有可用测试**。仅当 CMake 文件**提供了基于 ctest 的测试**时,该目标才自动可用。
- `install` 目标:
- 用于安装项目。仅当 CMake 文件**通过`install()`命令定义了安装规则**时,该目标才自动可用。
- 该命令将根据 `CMakeLists.txt` 中声明的 `install()` 命令**构建并安装该命令所指定的目标**。
- **构建 `install` 目标** 等效于 **执行 `cmake --install` 命令**。
- 使用示例:`cmake --build . --target install`。
- `package` 目标:
- 用于创建一个二进制包。仅当 CMake 文件**提供了基于 cpack 的包**时,该目标才会自动可用。
- `package_source` 目标:
- 用于创建一个源代码包。仅当 CMake 文件**提供了基于 cpack 的包**时,该目标才会自动可用。
![[05-工具/CMake 构建工具/CMake 命令说明#^bepx1x]]
### 生成器对应使用的构建工具
根据**配置阶段**所使用的生成器,构建阶段执行`cmake --build <build_dir>` 命令时,CMake 将调用**对应的构建工具**完成项目构建,编译生成可执行文件或库文件。
CMake 所调用的构建工具(**由 `CMAKE_MAKE_PROGRAM` 变量指定**)与生成器的对应关系如下[^3]:
> 
# cmake --install 命令
**该命令将根据 `CMakeLists.txt` 中定义的`install()` 规则执行项目安装,
将构建目标(如可执行文件、库文件、头文件等)复制到指定的安装目录**(通常是系统标准目录)。
命令:`cmake --install <build-directory> `
- `<build-directory>` :指定**构建目录**(包含构建产物如 Makefile 的目录),即 `build` 目录。
- `--prefix <install-prefix>` :指定 **自定义的安装前缀**,用于**覆盖`CMAKE_INSTALL_PREFIX`**。
- 在 Windows 上,该变量值默认为`c:/Program Files/${PROJECT_NAME}`
- 在 Unix-like 系统上,该变量值默认为`/usr/local`。
- `--preset <preset>` :使用预设的安装相关参数。
> [!caution] 确保在执行`cmake --install` 之前,项目已通过`cmake --build`**成功构建**。
#### 关于 "安装目录" 与 "目录前缀"
- **安装目录**:在 `CMakeLists.txt` 中由 `install()` 规则里的 `DESTINATION <dir>` 指定,
- **安装目录的 "路径前缀"**: 由 **`CMAKE_INSTALL_PREFIX` 变量** 指定
当指定的 "安装目录" 为**相对路径**时,将会为该路径加上由 `CMAKE_INSTALL_PREFIX`指定的**路径前缀**,
即完整的安装路径即为:"**路径前缀**" + "**相对路径**"
> [!quote]
> The CMake variable [`CMAKE_INSTALL_PREFIX`](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html#variable:CMAKE_INSTALL_PREFIX) is used to determine the root of where the files will be installed.
> If using the [`cmake --install`](https://cmake.org/cmake/help/latest/manual/cmake.1.html#cmdoption-cmake-install) command, the installation prefix can be overridden via the [`--prefix`](https://cmake.org/cmake/help/latest/manual/cmake.1.html#cmdoption-cmake--install-0) argument.
> [!NOTE] `CMAKE_INSTALL_PREFIX` 变量设置
>
> - (1)在配置阶段设置:
>
> ```shell
> cmake .. -DCMAKE_INSTALL_PREFIX="/usr/local"
> cmake --build .
> cmake --build . --target install
> ```
>
> - (2)在安装阶段可通过 `--prefix ` 选项指定并覆盖:`cmake --install . --prefix "/usr/local"`
>
>
#### 使用示例
`CMakeLists.txt` 中通过 `install()` 指定安装规则:
```cmake
# 指定安装规则
# `TARGETS <target>...` 指定要安装的目标(们)
# `DESTINATION <dir>` 指定要将文件安装到的磁盘目录。参数可以是相对路径或绝对路径。
# 为相对路径时, 是相对于安装前缀(由`CMAKE_INSTALL_PREFIX`变量定义)
install(TARGETS my_library my_executable DESTINATION bin)
install(FILES my_lib.h DESTINATION include) # 可以是文件, 由"FILES"关键字指定
```
在命令行中完成构建,然后通过`cmake --install <build_dir>` 命令进行安装:
```shell
# 创建build目录并进入
mkdir build
cd build
# 在build目录下生成"构建系统".
cmake .. # CMakeLists.txt在build目录的父目录中
# 构建项目
cmake --build . # 当前位于`build`目录
# 安装项目(将构建的项目安装到install()指令指定的目录去)
cmake --install . --prefix "home/myuser/installdir" # 当前即位于构建目录`build`目录
```
> [!example] 构建 `install` 目标等效于执行 `cmake --install` 命令。
>
> ```cmake
> cmake .. -DCMAKE_INSTALL_PREFIX="/usr/local"
> cmake --build . # 构建项目
> cmake --build . --target install # 安装项目
> ```
>
> 
>
> ^bepx1x
# 参考资料
- [cmake tutorial: 官方教程](https://cmake.org/cmake/help/latest/guide/tutorial/index.html)
# Footnotes
[^1]: [cmake(1)](https://cmake.org/cmake/help/latest/manual/cmake.1.html)
[^2]: [User Interaction Guide](https://cmake.org/cmake/help/latest/guide/user-interaction/index.html#id2)
[^3]: [cmake命令](https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html)