1. 为什么项目里突然绕不开 CMake
先说个我最近实际遇到的场景:接手一个老 C++ 项目,Windows 上用 Visual Studio 开发,Linux 上跑自动化编译,macOS 上还有同事在改 UI。原来那套 .sln 加 .vcxproj 的维护方式,在 Windows 本地用着还行,但一涉及命令行打包、CI 流水线、跨平台依赖,立刻乱成一片。后来花了一周把构建系统整体迁到 CMake,整个过程踩了不少坑,也积累了很多值得记录的经验。
CMake 是一个开源的、跨平台的构建系统生成器。它不直接编译代码,而是根据 CMakeLists.txt 里的描述,生成对应平台的原生构建文件——Windows 上生成 Visual Studio 工程,Linux 和 macOS 上生成 Makefile 或 Ninja 文件。这么一层抽象的“中间层”,让同一套构建逻辑可以在不同平台、不同编译器下复用。
这篇内容适合谁?三类人:第一类是刚接触 C++ 构建、想知道 CMake 到底怎么用的新手;第二类是已经在用 CMake 但总在路径、输出目录、预编译头这些细节上反复折腾的开发者;第三类是想把老项目迁移到 CMake、需要一套可落地方案的工程师。我尽量把每个操作背后的“为什么”也讲清楚,不然光抄命令,换个场景还是不会灵活用。
2. 下载安装与版本选择:别小看这一步
2.1 三大平台的安装方式
CMake 的安装在不同系统上差异不小,我用实际命令走一遍。
Windows 上最省事的方式是去官网下载安装包,选择Windows x64 Installer,装的时候务必勾选“Add CMake to the system PATH for all users”。这一步很多人漏掉,装完在命令行里敲cmake --version提示找不到命令,又回来折腾环境变量,纯属浪费时间。如果公司内网不方便访问官网,也可以用包管理器,比如用 winget 执行:
winget install Kitware.CMake这个命令会自动装最新稳定版并配置好 PATH,比手动下载清爽很多。
Linux 上根据发行版选择包管理器。Ubuntu 和 Debian 系:
sudo apt update sudo apt install cmake但这里有个坑,Ubuntu 官方源里的 CMake 版本往往偏老。比如 Ubuntu 20.04 默认源里是 3.16,而很多新特性(比如后面要讲的target_precompile_headers)在 3.16 里虽然能用但稳定性一般,3.20 以上才完善。如果项目依赖新特性,建议直接从官网下载预编译的二进制包,或者用 pip 方式安装:
pip install cmakepip 装的 CMake 版本很新,并且会自动进入 Python 环境的 bin 目录,适合在虚拟环境里管理。
macOS 上最简单:
brew install cmake安装完成后,在任何目录执行cmake --version,能看到类似cmake version 3.28.1的输出就算成功。这里强调一下,版本号并不是越大越好,但也不能太老。实际项目里我遇到过 CMake 3.10 无法解析某些新语法,而 3.20 以上则游刃有余的情况。强烈建议新项目至少使用 3.16 以上,最好 3.20 以上。
2.2 版本选择与升级避坑
CMake 版本策略上有个“最小心版本”习惯:在 CMakeLists.txt 开头写cmake_minimum_required(VERSION 3.20),如果本机 CMake 版本低于它,会直接报错并停止,避免运行到一半发现某些命令不支持。
升级 CMake 时注意一点:CMake 生成的缓存文件(CMakeCache.txt)与版本有一定耦合性。跨大版本升级后,最稳妥的做法是删掉整个 build 目录重新配置。我吃过一次亏,从 3.16 升到 3.24 后没删缓存,结果编译时用了旧的生成器路径,怎么都对不上,浪费了一个下午。后来养成习惯,升级 CMake 或更换编译器后,必删 build 目录。
3. 生成 VS 工程与相对路径的写法
3.1 最小 CMakeLists.txt 与生成器指定
先用一个最典型的结构讲解,假设项目目录如下:
project_root/ ├── CMakeLists.txt ├── src/ │ ├── main.cpp │ ├── utils.cpp │ └── utils.h └── build/根目录的 CMakeLists.txt 至少需要这些内容:
cmake_minimum_required(VERSION 3.20) project(MyProject LANGUAGES CXX) add_executable(my_app src/main.cpp src/utils.cpp ) target_include_directories(my_app PRIVATE src)然后执行配置命令。在项目根目录下:
cmake -G "Visual Studio 17 2022" -A x64 -S . -B build这段话解释一下,-S .指定源码根目录为当前目录,-B build指定构建目录,-G指定生成器,-A指定平台架构。执行后,CMake 会在 build 目录下生成MyProject.sln和一堆.vcxproj文件,直接用 Visual Studio 打开这个 sln 就能编译。
有人想生成其他版本 VS 工程,需要先查一下本机装了哪些生成器。命令行执行:
cmake --help输出的列表里会有Visual Studio 17 2022、Visual Studio 16 2019、Unix Makefiles、Ninja等,根据实际安装选择即可。
3.2 工程里使用相对路径的两种关键写法
“cmake 生成的 VS 工程使用相对路径的写法”是很多人搜索的高频问题。这里有一个核心认知,CMake 生成的.vcxproj内部,绝大多数字符串已经尽量用相对路径表达,但默认策略并不总是符合预期。真正需要手动干预的,是两类场景。
第一类,外部依赖的路径。比如把第三方库放在项目根目录之外的某个公共位置,这时 CMakeLists.txt 里如果写成:
target_include_directories(my_app PRIVATE C:/dev/libs/opencv/include)生成的 VS 工程里会把这段绝对路径写死,换一台机器或者目录结构改变,VS 打开工程就会报找不到头文件。正确做法是把外部路径定义为变量,相对源码根目录拼接:
set(THIRD_PARTY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../libs) target_include_directories(my_app PRIVATE ${THIRD_PARTY_DIR}/opencv/include)此时生成的工程文件里会以..\..\libs\opencv\include的形式相对引用,整个工程拷到任意目录,只要相对结构不变,就能直接编译。
第二类,调试工作目录。默认生成的 VS 工程,调试时的“工作目录”是$(ProjectDir),也就是工程文件所在目录。如果你希望运行程序时的工作目录在项目根目录或某个资源目录,在 CMakeLists.txt 里可以设置:
set_target_properties(my_app PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" )这里用${CMAKE_CURRENT_SOURCE_DIR}而不是硬编码路径,就是为了保证工程即使被复制到别处,调试工作目录也会跟着源码位置走。
另外还有一个很隐蔽但很实用的点:CMake 在生成 VS 工程时,默认会按“相对路径”引用项目内的源文件。但如果你通过file(GLOB ...)方式收集源文件,CMake 有时会因为缓存变量里的路径格式问题,在 vcxproj 中出现混合风格的路径。解决方式也很简单,统一用cmake_path或file(REAL_PATH ...)做一次规范化:
file(GLOB_RECURSE MY_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")CONFIGURE_DEPENDS这个参数值得加上,它能让 CMake 在重新构建时自动检测新增源文件,不需要手动重新执行 cmake 命令。
3.3 实际体会
相对路径问题说起来不难,但踩坑的人特别多。核心原因在于,很多人觉得“只要我本地能编过就行”,忽略了工程文件会流动到其他人手里。我现在的习惯是:CMakeLists.txt 里禁止出现任何硬编码绝对路径,所有除系统路径之外的地址,一律通过源码根目录的变量拼接。这条原则坚持下来,项目交付后别人拉下来配一下就编,省了很多沟通成本。
4. 输出路径去掉 Debug 的配置思路
4.1 为什么 VS 默认输出目录带 Debug
用 Visual Studio 生成器时,CMake 默认的输出目录策略与 VS 原生工程一致,即区分配置类型:Debug 版本输出到build/Debug,Release 输出到build/Release。这个行为对开发调试是友好的,因为不同配置的产物互不干扰。
但问题也随之而来。有些场景,比如需要统一打包脚本,希望所有可执行文件都输出到同一个bin目录,不再按 Debug 或 Release 分文件夹。还有的场景,项目里集成了外部后处理工具,它硬编码了输出路径,必须让可执行程序放到指定位置。这时候就需要修改输出路径。
4.2 三条关键变量的设置
CMake 提供了三个核心变量,分别控制可执行文件、静态库/导入库、动态库的输出目录:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)解释一下各自管什么:
CMAKE_RUNTIME_OUTPUT_DIRECTORY:可执行文件(.exe、.dll)的输出目录。Windows 上动态库的 .dll 也归它管。CMAKE_LIBRARY_OUTPUT_DIRECTORY:非 Windows 平台上的动态库(.so、.dylib)输出目录。CMAKE_ARCHIVE_OUTPUT_DIRECTORY:静态库(.lib、.a)及 Windows 上 DLL 配套的导入库(.lib)的输出目录。
设置之后,Debug 和 Release 的产物都会直接输出到build/bin和build/lib,不会再自动添加配置子目录。如果你希望连中间文件(.obj)也不放 Debug/Release 子目录,那通常不建议这么做,因为多配置生成器在并行编译时容易发生目标文件冲突。我一般只改最终产物目录,中间文件目录保持默认分配置结构,安全第一。
4.3 按配置区分但又统一前缀的写法
有些项目需要不同配置仍然是不同目录,但目录名不要叫 Debug 和 Release,比如叫 dev 和 prod。这时可以用生成器表达式:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/$<CONFIG>)$<CONFIG>是 CMake 的生成器表达式,在编译时会展开为实际配置名的小写形式。这可以让你既保持分目录结构,又能自定义目录命名。同理,如果你想统一到bin/dev、bin/prod,可以先判断配置再映射:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/$<IF:$<CONFIG:Debug>,dev,prod>)这种写法在 CI 流水线里比较常用,因为打包脚本可以只关注bin/dev这种固定路径,不用管当前是哪个配置。
4.4 一个完整的示例
把前面讲的串起来,给一个实际的 CMakeLists.txt 片段:
cmake_minimum_required(VERSION 3.20) project(MyApp LANGUAGES CXX) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) add_executable(my_app src/main.cpp) add_library(my_core STATIC src/core.cpp) target_link_libraries(my_app PRIVATE my_core)构建完成后,my_app.exe一定在build/bin/my_app.exe,my_core.lib在build/lib/my_core.lib。我在多个项目里验证过这个写法,Windows、Linux、macOS 三个平台行为一致。
5. 预编译头(PCH)的正确打开方式
5.1 为什么需要预编译头
C++ 项目一旦上了规模,头文件的反复解析是一种巨大的性能损耗。一个 main.cpp 可能间接包含了数万行头文件,每次编译都要重新解析一遍,耗时蹭蹭上涨。预编译头(Precompiled Header)的思路是,把一组不会变动的公共头文件(比如标准库、第三方库的头文件)预先编译成中间格式,之后每个源文件编译时直接复用,不用再逐个头文件解析一遍。
Visual Studio 里的默认实践是stdafx.h或pch.h加pch.cpp的组合。CMake 3.16 之后正式引入了跨 IDE 的target_precompile_headers命令,我们不再需要手动创建 pch.cpp 并配置编译选项,CMake 会自动处理。
5.2 基础用法与实际效果
假设项目里有一个pch.h文件,内容如下:
#pragma once #include <string> #include <vector> #include <memory> #include <iostream>在 CMakeLists.txt 中启用预编译头:
add_executable(my_app src/main.cpp src/utils.cpp) target_precompile_headers(my_app PRIVATE [["pch.h"]] <string> <vector> )这里有个语法细节:[["pch.h"]]表示项目内自定义头文件,<string>和<vector>表示系统头文件。CMake 会根据编译器自动处理这两者的引入方式:MSVC 用/FI,GCC 和 Clang 用-include。
实际编译提速效果非常可观。我之前一个项目,公共头文件很多,没开 PCH 前全量编译需要 7 分钟,开启后直接降到 2 分 40 秒左右,增量编译更是从 2 分钟降到 30 秒。这个优化在模块多的项目里尤其明显。
5.3 跨 target 共享预编译头
如果项目里有多个可执行文件或动态库,它们如果包含相同的公共头文件,每个 target 各自维护一份 PCH 是浪费的。CMake 允许通过target_precompile_headers的 INTERFACE 传播机制实现共享。
做法是创建一个接口库:
add_library(common_pch INTERFACE) target_precompile_headers(common_pch INTERFACE [["pch.h"]] <string> <vector> ) target_link_libraries(my_app PRIVATE common_pch) target_link_libraries(my_tool PRIVATE common_pch)任何链接了common_pch的目标,都会自动应用相同的预编译头配置。注意这里 INTERFACE 库本身不参与编译,只是一个配置传播点。这个写法避免了在每个 target 里重复写一大串头文件列表,后续想往公共 PCH 加一个头文件,只需改一处。
5.4 常见坑与注意事项
预编译头虽然省时,但用不好会带来隐蔽的编译问题。
最大的坑是“头文件变更后编译结果不更新”。有人改了pch.h里的某个头文件,重新编译时发现部分源文件没重新编译,链接后行为异常。原因是 CMake 依赖头文件依赖扫描逻辑,而target_precompile_headers里用[["pch.h"]]定义的项目头文件,如果它又被其他源文件以不同形式 include,可能不会触发关联重建。解决方法是保证 pch.h 没有被条件 include 或宏改变内容,同时养成改 PCH 后全量重建的习惯。
第二个坑是 MSVC 与 GCC 对 PCH 的支持方式不同。MSVC 的/Yu和/Yc组合要求所有源文件都统一包含同一个 PCH 文件,如果有某个源文件写的是#include <string>而不是#include "pch.h",在 MSVC 上会报 C1010 错误。解决方法是设置编译选项强制所有文件先包含 PCH:
if(MSVC) target_compile_options(my_app PRIVATE /FI"pch.h") endif()第三个坑,CMake 的target_precompile_headers在 GCC 上依赖-include机制,但如果源文件中有宏定义影响了头文件内容,PCH 可能会编译生成两个不同版本的中间文件,导致 “PCH 使用冲突”。遇到这种问题,最直接的排查方法是临时关闭 PCH,确认代码本身没有宏污染,再逐步开启。
6. 在 CMake 中执行 bash 命令的正确姿势
6.1 execute_process 与 add_custom_command 的区别
很多人想在 CMake 构建过程中执行外部命令,比如调用脚本生成版本信息,或是在编译前拉取一些资源。CMake 提供了两个主要入口,但它们执行的时机完全不同,用错场景会导致命令不执行或执行时机不对。
execute_process在“配置阶段”执行,也就是说运行cmake -B build的那一刻它就会运行,之后编译过程再也不会触发。适合做代码生成、环境探测、版本号获取这类只需要执行一次的工作。
add_custom_command则在“构建阶段”执行,也就是每次执行cmake --build build时,根据设定的依赖条件决定是否运行。适合做编译前、编译后需要反复触发的工作。
举一个实际的场景:我需要在编译前执行一个 bash 脚本,生成version.h文件,内容根据 git 提交号动态变化。这个需求必须用add_custom_command,因为每次代码提交后需要重新生成。
6.2 在 Windows 上找到 bash
“cmake 执行 bash 命令”这个热搜词背后,反映的是很多人在 Windows 环境下用 CMake 调 bash 脚本时找不到 bash 的尴尬。Windows 本身没有原生的 bash,除非装了 Git Bash、MSYS2 或 WSL。我在项目里的处理方式是先探测 bash 路径,再传给 CMake:
find_program(BASH_EXECUTABLE bash PATHS "C:/Program Files/Git/bin" "C:/msys64/usr/bin") if(NOT BASH_EXECUTABLE) message(FATAL_ERROR "bash not found") endif()find_program会在 PATH 和列出的额外路径中查找 bash.exe,找到后赋值给BASH_EXECUTABLE变量。如果用户装的是 Git Bash,那么路径通常是C:/Program Files/Git/bin/bash.exe,CMake 用这个路径执行命令时要注意,脚本内部如果包含 Linux 路径格式,bash 自己会处理,但 Windows 风格路径在脚本里要注意转义。
6.3 完整示例:编译前生成版本头文件
项目结构:
project_root/ ├── CMakeLists.txt ├── scripts/ │ └── gen_version.sh └── src/ └── main.cppscripts/gen_version.sh内容:
#!/bin/bash VERSION_STR=$(git describe --tags --always 2>/dev/null || echo "unknown") echo "#define APP_VERSION \"${VERSION_STR}\"" > "$1"CMakeLists.txt 中:
find_program(BASH_EXECUTABLE bash PATHS "C:/Program Files/Git/bin") set(VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/generated/version.h) add_custom_command( OUTPUT ${VERSION_HEADER} COMMAND ${BASH_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/gen_version.sh ${VERSION_HEADER} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/scripts/gen_version.sh COMMENT "Generating version.h" ) add_executable(my_app src/main.cpp ${VERSION_HEADER}) target_include_directories(my_app PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/generated)这段 CMake 的核心逻辑:add_custom_command声明了version.h由脚本生成,OUTPUT指定生成文件,COMMAND指定执行命令,DEPENDS说明只要脚本有改动就要重新生成。把它加到add_executable的源文件里,CMake 会自动建立依赖关系,编译前先运行脚本。
这个模式有很强的扩展性,它可以用来生成协议代码、拉取子模块、打包资源等。我自己在多个项目里都用这个模式,基本能解决 90% 的“构建前要跑脚本”需求。
6.4 配置阶段执行命令的场景
如果你确实需要在执行cmake -B build时就探测环境并输出结果,这才用execute_process。常见的用例是获取系统信息:
execute_process( COMMAND ${BASH_EXECUTABLE} -c "echo hello" OUTPUT_VARIABLE BASH_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE ) message(STATUS "bash output: ${BASH_OUTPUT}")注意execute_process的COMMAND不会经过 shell 解析,如果命令里要写管道、重定向这些,必须显式通过 bash 的-c参数来执行。这一点很关键,很多人在 Windows 上写:
execute_process(COMMAND echo hello | grep h)然后莫名其妙得到错误结果,就是因为 CMake 不会把|当成 shell 管道。
7. 常见问题与排查技巧实录
7.1 典型问题速查表
我整理了实际项目里高频出现的 CMake 问题,按症状-原因-解决方式的格式列出,方便大家直接对号入座。
| 问题现象 | 根本原因 | 解决方案 |
|---|---|---|
cmake --version提示找不到命令 | 安装时未添加 PATH | 重新安装并勾选“Add to PATH”,或手动追加系统环境变量 |
| 生成的 VS 工程引用绝对路径,换目录失效 | CMakeLists 中硬编码了路径 | 用${CMAKE_CURRENT_SOURCE_DIR}等变量拼接相对路径 |
| 可执行文件总输出到 Debug/Release 子目录 | 未设置输出目录变量 | 设置CMAKE_RUNTIME_OUTPUT_DIRECTORY、CMAKE_LIBRARY_OUTPUT_DIRECTORY、CMAKE_ARCHIVE_OUTPUT_DIRECTORY |
| PCH 开启后部分文件报 C1010 | MSVC 要求所有源文件都包含 PCH | 加编译选项/FI"pch.h"强制包含 |
execute_process中的管道命令无效 | CMake 不解析 shell 语法 | 用 bash 的-c参数传递完整命令 |
| 修改 CMakeLists.txt 后重新构建,部分配置不生效 | 缓存未刷新 | 删除 build 目录重新配置,或删除 CMakeCache.txt 后重跑 cmake |
| 新增源文件后没有参与编译 | file(GLOB)未加CONFIGURE_DEPENDS | 在file(GLOB)加CONFIGURE_DEPENDS参数,或改为显式列出源文件 |
7.2 排查思路与个人避坑经验
遇到 CMake 相关问题时,我建议按三层思路排查。
第一层,看配置日志。执行cmake -B build时输出的 message 信息是最直接线索,如果配置阶段就报错,CMake 会非常明确地指出哪一行 CMakeLists.txt 出了问题。养成在关键分支加message(STATUS "...")的习惯,能大大缩短排查时间。
第二层,看生成文件。如果配置成功但编译出问题,去 build 目录下打开.vcxproj或 Makefile,搜索关键路径,确认 CMake 最终生成了什么。很多时候问题在于变量展开和转义,生成文件里一看便知。
第三层,用--trace追踪。CMake 3.25 后支持--trace参数:
cmake -B build --trace它会打印所有 CMakeLists.txt 中的执行细节和变量值。我排查过一个诡异问题:某个变量在 A 处设置了值,到 B 处却变成空字符串,用--trace一眼就看到是作用域的问题——变量在子目录的 CMakeLists.txt 里被set(... CACHE)覆盖了。这种问题靠肉眼看是看不出来的。
7.3 关于路径中有空格的大坑
Windows 上项目路径如果包含空格,比如C:/My Projects/App,CMake 生成 VS 工程一般没问题,但add_custom_command里直接写带空格路径就会出问题。因为 CMake 会把COMMAND里的参数按空格拆分成多个参数,传给外部程序后路径被截断。
解决办法是给路径加引号,但 CMake 里的引号处理也有讲究。最稳的方式是用变量把路径包起来,再通过COMMAND_EXPAND_LISTS或直接合并成一个参数:
set(SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/scripts/my script.sh") add_custom_command( OUTPUT ${VERSION_HEADER} COMMAND ${BASH_EXECUTABLE} "${SCRIPT_PATH}" ${VERSION_HEADER} ... )这里${SCRIPT_PATH}两边的双引号是关键,它能让 CMake 把整个路径当作一个参数传给 bash。如果是 Linux 和 macOS,路径分隔符是/,问题不明显,但 Windows 上空格太常见,这个习惯建议从一开始就养成。
7.4 从 VS 原生工程迁移到 CMake 时的兼容性
最后讲一个迁移场景里的典型问题。从.vcxproj迁移到 CMake 后,原来工程的一些全局宏定义、预处理器设置如果没同步到 CMakeLists,编译时会报一堆莫名其妙的错误。
常见的缺失项包括:
add_definitions(-D_WIN32_WINNT=0x0601) add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_compile_options(/EHsc) add_compile_options(/utf-8)_WIN32_WINNT控制 Windows SDK 版本,不设可能会让某些系统 API 不可用;_CRT_SECURE_NO_WARNINGS关掉 MSVC 对strcpy这些函数的弃用警告;/EHsc启用 C++ 异常处理;/utf-8解决源码文件编码问题,这个在中文项目里尤其重要,不设的话源文件里的中文字符串可能乱码。
迁移后建议全量编译一次,逐个补齐这些定义。注意_WIN32_WINNT的值要按目标系统的版本设置,乱设也会出问题。
8. 写在最后:把 CMake 当“唯一入口”来维护
我在多个项目里实践下来的体会是,CMake 最核心的价值不是“生成一个能编译的工程”,而是让它成为整个项目构建行为的唯一事实来源。所有源文件、编译选项、依赖关系、生成步骤都集中写在 CMakeLists.txt 里,平台相关的差异通过条件判断和生成器表达式处理。这样无论是本地开发、CI 流水线,还是同事之间的协作,看到的是同一套逻辑,不会出现“我这能编你那儿编不过”的扯皮。
最后分享一个小技巧:在项目根目录放一个CMakePresets.json,把常用的生成器、构建类型、缓存变量都固化下来,团队成员可以共用同一套配置,而不需要在命令行里敲一长串参数:
{ "version": 3, "configurePresets": [ { "name": "default", "generator": "Visual Studio 17 2022", "architecture": "x64", "binaryDir": "${sourceDir}/build" } ] }配置好后,成员只需要执行cmake --preset default,然后cmake --build build就可以完成构建。这个玩法能省下大量解释“怎么配”的口舌,也减少因为个人配置差异导致的低级错误。至于更多进阶用法,比如用 CPack 打包、用 CTest 跑测试、用 CMake 的调试器等等,后续可以再单独写一篇展开,先把上面这些基本功夯实,项目构建就已经能打扫得很干净了。