%% # 纲要 > 主干纲要、Hint/线索/路标 # Q&A #### 已明确 #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** # Buffer ## 闪念 > sudden idea ## 候选资料 > Read it later %% # CMake 命令总览 > [!NOTE] 命令一览 > > 参见 [^1] > > ![image-20231216115543097|839](_attachment/05-工具/CMake%20构建工具/CMake.assets/IMG-CMake-37159C140265336E4C137FA4113A52F9.png) > > ^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] > ![image-20231211105211401|826](_attachment/05-工具/CMake%20构建工具/CMake.assets/IMG-CMake-A98B677E988217090FFBE6A89C654B12.png) - `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]: > ![image-20231211135802278|560](_attachment/05-工具/CMake%20构建工具/CMake.assets/IMG-CMake-6BA4A91D53903C889F5689D8041ED7B2.png) # 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 # 安装项目 > ``` > > ![image-20231207170806483|567](_attachment/05-工具/CMake%20构建工具/CMake.assets/IMG-CMake-B869F3F5415A6C57C82AE5141AB06972.png) > > ^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)