%% # 纲要 > 主干纲要、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 等,**构建生成可执行文件或库**。 ![img|649](_attachment/05-工具/CMake%20构建工具/CMake%20说明.assets/IMG-CMake%20说明-18158A95B2F022C3D938B75138EBB75E.webp) 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] > > ![image-20230911170902669|579](_attachment/05-工具/CMake%20构建工具/CMake%20说明.assets/IMG-CMake%20说明-B3A8680E2343432C698D4C874466F426.png) > > [!example] > > ![image-20231207102610551|682](_attachment/05-工具/CMake%20构建工具/CMake%20说明.assets/IMG-CMake%20说明-F0A4530FC1557B9DC5EE4F7CD42E32FC.png) > > ![image-20231207102747194|549](_attachment/05-工具/CMake%20构建工具/CMake%20说明.assets/IMG-CMake%20说明-EC000F4A432FA037CB60420DD4A54E1F.png) > > > <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 ![image-20231209102222974|610](_attachment/05-工具/CMake%20构建工具/CMake.assets/IMG-CMake-A55062643CDE2E5C86D6E1C0A25EF913.png) <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)