简介:CMake 3.29.7 官方 Windows 免安装压缩包,专为 C++ 项目开发者与需要固定版本构建工具的技术团队设计。解压后只需将 bin 目录加入系统环境变量,即可在命令行或 PowerShell 中直接调用 cmake、ctest 等命令,无需运行安装向导,也不会写入注册表,适合多版本并行与离线部署。包内共包含 2000 个文件,整体大小仅 43.63MB,其中 html 文档有 843 个,涵盖命令行参考、生成器表达式、文件 API、构建系统、预设与变量说明等官方权威手册,便于阅读和排错。txt 文件有 1157 个,主要存放组件说明、版本更新记录与辅助注释,能帮助理解新特性和常用参数,已有 604 人学习下载。该套文件体量轻、文档完整,适合从零学习 CMake 的初学者、需要统一构建环境的项目团队,以及希望随时查阅官方文档的 Windows 用户。
1. 便携版 CMake:Windows 上最容易被低估的版本管理方式
不少人在 Windows 上装 CMake,习惯性下载 .msi 一路 Next,直到某天项目 A 要 3.27、项目 B 又必须 3.29,才意识到C:\Program Files\CMake里那个全局版本根本不够用。cmake-3.29.7-windows-x86-64.zip 是官方发布的绿色压缩包,解压后 bin 目录下就是完整的 cmake.exe、ctest.exe、cpack.exe,不写注册表,也不触发 UAC。把它放在C:\tools\cmake-3.29.7-windows-x86-64下,再把 bin 加进 PATH,安装就完成了。听起来简单,但真正值钱的是后面的版本切换、与 VS 生成器的配合、以及用 CMakePresets.json 锁定版本这一整套方法论。这篇文章从 PATH 开始,把一个 Windows 上的 C++ 构建链路完整拆开。
2. 解压、PATH 与版本探测:让 cmake 命令走到你指定的那个 bin
2.1 解压后先看清目录结构
把 zip 解压到C:\tools后,不要急着写 PATH,先用 tree 看一下整体布局:
tree C:\tools\cmake-3.29.7-windows-x86-64 /F目录结构大致是:
C:\tools\cmake-3.29.7-windows-x86-64 ├─ bin │ ├─ cmake.exe │ ├─ ctest.exe │ └─ cpack.exe ├─ doc │ ├─ cmake.1.html │ ├─ cmake-buildsystem.7.html │ ├─ cmake-file-api.7.html │ ├─ cmake-generator-expressions.7.html │ ├─ cmake-presets.7.html │ └─ cmake-variables.7.html └─ sharebin 下三个可执行文件是核心工具;doc 下的 HTML 是 3.29.7 自带的官方手册。后面要讲的生成器表达式、构建系统、Presets、File API,都能在这几个文档里找到原始定义。share 目录放的是 Find 模块和工具链模板,比如share/cmake-3.29/Modules/CMakeRCInformation.cmake,平时不用动,但自定义工具链时找不到内建宏,可以去这里翻。
提示:建议把整个目录放在无空格的纯英文路径下,比如
C:\tools,避免 CMake 内嵌脚本和后端构建工具处理空格时出现兼容性问题。
2.2 把 bin 加入 PATH:临时、永久两条路
临时生效只需要当前终端,适合快速验证某个版本:
set "PATH=C:\tools\cmake-3.29.7-windows-x86-64\bin;%PATH%"这段命令把目标 bin 目录加到 PATH 最前面,保证当前会话里输入 cmake 时优先匹配这个目录。注意引号只包住了路径部分,没有包整条 set,避免和现有路径里的特殊符号冲突。
永久生效我更推荐 PowerShell,因为 setx 会在旧值过长时截断环境变量:
[Environment]::SetEnvironmentVariable( "Path", [Environment]::GetEnvironmentVariable("Path", "User") + ";C:\tools\cmake-3.29.7-windows-x86-64\bin", "User" )这里重新读取 User 域的环境变量再追加,不会撞上系统级的 Path。命令执行后需要重新打开终端,让进程读取新的环境变量值。如果只是想让某一个项目用这个版本,第 5 章会用 CMakePresets.json 配合cmake.cmakePath处理,不必改系统 PATH。
2.3 版本探测:where cmake 比 cmake --version 更重要
配好 PATH 后,先做两步验证:
where cmake cmake --versionwhere cmake会输出所有匹配路径,顺序就是 Windows 的 PATH 查找顺序。如果第一条仍然是C:\Program Files\CMake\bin\cmake.exe,说明老版本还拦在前面,后面的cmake --version显示的也一定是老版本。最常见的问题不是没装上,而是装完之后 PATH 里旧条目靠前,看起来像“升级没生效”。遇到这种情况不要重复安装,直接把较旧版本从 PATH 里移除,或者当前会话里用 2.2 节的临时命令强制覆盖。
注意:
cmake --version输出cmake version 3.29.7不代表 where 的结果可信。若 where 显示还指向其他路径,说明命令被 cmake-gui 或 Qt 工具链自带的版本截胡了。
2.4 三种安装方式横向对比
| 方式 | 注册表 | PATH 控制 | 多版本切换 | 卸载 | CI 集成 |
|---|---|---|---|---|---|
| 官方 .msi 安装器 | 写入 | 自动写入系统 PATH | 需要逐个覆盖 | 控制面板卸载,残留多 | 镜像内模板固定 |
| chocolatey / scoop | 视底层包而定 | 包管理器自动处理 | 相对麻烦 | 命令卸载 | 依赖包源网络 |
| 官方 zip 绿色包 | 不写 | 手动/脚本导入 | 改 PATH 即切换 | 删目录和 PATH 条目 | 解压即用,最可控 |
zip 包的优势在 CI 里最明显。不需要管理员权限,不用等安装器交互,下载解压后把 bin 目录设置进当前构建任务的 PATH,版本就锁定住了。旧版本也不碍事,可以把 3.28 和 3.29 并排放,脚本里按项目切换。
2.5 升级与卸载:永远不必动 PATH 的做法
升级时下载新版本 zip,解压后把 PATH 里的版本号改掉即可。但改 PATH 会引起其他依赖该路径的工具连锁反应。我一般会在C:\tools下做一个 junction 固定入口:
mklink /J C:\tools\cmake C:\tools\cmake-3.29.7-windows-x86-64之后 PATH 里永远写C:\tools\cmake\bin。升级时删除 junction 再重新指向新目录,PATH 条目完全不需要改。卸载则是三步:删除解压目录、删除 junction、清理 PATH 里的旧条目。整个过程零注册表写入,也不会像 .msi 那样留下几十条卸载记录。
3. 从零构建 C++ 项目:生成器、构建参数与 Windows 路径雷区
3.1 一次最小配置需要的三个文件
先创建一个最简单的工程:
hello/ ├─ CMakeLists.txt └─ main.cppCMakeLists.txt 二十行以内就够了:
cmake_minimum_required(VERSION 3.29) project(hello LANGUAGES CXX) add_executable(hello main.cpp) target_compile_features(hello PRIVATE cxx_std_17) if(MSVC) target_compile_options(hello PRIVATE /W4) else() target_compile_options(hello PRIVATE -Wall -Wextra) endif() install(TARGETS hello RUNTIME DESTINATION bin)cmake_minimum_required(VERSION 3.29)除了校验版本,还确定了策略版本,直接用 zip 包对应的 3.29 分支行为,避免继承旧版本编译策略。target_compile_features(hello PRIVATE cxx_std_17)是推荐的 C++ 标准声明方式,它比写CMAKE_CXX_STANDARD更局部化,只影响 hello 这一个目标。install 规则在后面执行--target install时会生效。
3.2 生成器选型:Visual Studio 还是 Ninja
Windows 上第一个分叉点就是生成器。兼容性最好的是 Visual Studio 生成器:
cmake -S hello -B build-vs -G "Visual Studio 17 2022" -A x64-S指定源码目录,-B指定构建目录,-G选择生成器,-A x64给 VS 生成器指定平台。Visual Studio 生成器是“多配置”生成器,一份构建目录里同时保留 Debug/Release/MinSizeRel/RelWithDebInfo 四套中间产物,所以不需要在配置阶段设置 CMAKE_BUILD_TYPE,而是在构建阶段用--config Release选择配置。
Ninja 是另一派,构建速度快,输出干净,配合 VSCode 和 CMake Tools 非常顺:
cmake -S hello -B build-ninja -G Ninja -DCMAKE_BUILD_TYPE=ReleaseNinja 是“单配置”生成器,必须在配置阶段把 CMAKE_BUILD_TYPE 定死,之后每次构建都是同一个配置。只是反复跑 Release 的个人项目,Ninja 够用;需要 Debug 和 Release 频繁切换的库项目,VS 生成器更方便。MinGW Makefiles 生成器需要额外安装 mingw32-make,实际项目里用得越来越少。
3.3 构建参数表与一条完整链路
| 参数 | 作用 | 示例 |
|---|---|---|
-S <dir> | 指定源码目录 | -S hello |
-B <dir> | 指定构建目录,不存在自动创建 | -B build |
-G <gen> | 指定生成器 | -G "Visual Studio 17 2022" |
-A <arch> | VS 生成器指定平台 | -A x64 |
-D CMAKE_BUILD_TYPE=<type> | 单配置生成器设置构建类型 | -D CMAKE_BUILD_TYPE=Release |
--build <dir> | 对已有构建目录执行构建 | cmake --build build |
--config <cfg> | 多配置生成器选择配置 | cmake --build build --config Release |
--target <tgt> | 只构建指定目标 | --target hello |
以 VS 生成器为例的完整链路:
cmake -S hello -B build -G "Visual Studio 17 2022" -A x64 cmake --build build --config Release --target hello build\Release\hello.exe第一行完成配置,第二行调用 MSBuild 编译,第三行从输出目录运行 exe。如果换 Ninja,第二行会调用 ninja,第三行路径变成build\hello.exe。cmake --build会根据生成器自动选择对应的构建程序,这是比直接敲cmake .. && make更通用的方式——后者在 Linux 上很常见,在 Windows 上依赖 make 环境,移植性差。
提示:
cmake --build build --verbose能展开实际执行的编译命令,排查头文件路径和宏定义时非常有用。
3.4 Windows 路径雷区
构建目录千万不要放进带空格或中文的路径。遇到过C:\Users\张三\My Project\build这样的路径,Ninja 有时能过,MSBuild 有时会挂,最后底层 cl.exe 报找不到文件。最稳定的组合是源码目录和构建目录都放在纯 ASCII 无空格路径下。
另一个坑来自 Windows SDK。如果在普通 PowerShell 窗口里运行 cmake,VS 生成器可能找不到 rc.exe 或 mt.exe,报 “RC Pass 1 failed”。原因是资源编译器需要 SDK 的环境变量。这时要么打开 “x64 Native Tools Command Prompt for VS 2022” 再执行 cmake,要么在 CMakeLists.txt 里显式指定CMAKE_RC_COMPILER。实践中更推荐直接用开发人员命令提示符,不要在环境变量上做无谓消耗。
出现 “Unable to find a build program corresponding to 'MinGW Makefiles'” 时,说明系统里有 gcc 但没有 make。要么把 MinGW 的 bin 放进 PATH,要么换成 Ninja + gcc,Ninja 不依赖 make。3.29.7 对 Ninja 的探测已经很可靠,只要ninja --version能输出,CMake 就能直接调用。
3.5 一次 Debug 的日志线索
构建报错时不要只看最后三行。cmake --build build --verbose会输出 cl.exe 的完整命令行,先确认有没有/std:c++17。如果 main.cpp 里用了 C++17 语法而编译命令没有出现对应选项,说明target_compile_features没有生效,或工具链版本太旧。再看/D_DEBUG和/MTd是否合理,Debug 和 Release 混用 /MT 与 /MD 是 Windows 常见崩溃源头。日志里的 C4251 警告也可以留意,导出 STL 成员时经常出现,不是致命问题,但值得知道来源。
4. 3.29 的进阶能力:Generator Expressions、PDB 与构建系统边界
4.1 生成器表达式不只是语法糖
doc 目录里cmake-generator-expressions.7.html是理解现代 CMake 的核心。生成器表达式在生成阶段才求值,因此能感知配置类型、目标属性、工具链信息。Windows 上最常见的场景是把 DLL 复制到可执行文件旁边。假定 myapp 依赖 mylib,而 mylib 是 shared 库,构建后 DLL 不一定出现在 myapp 的运行目录,于是这样写:
add_library(mylib SHARED mylib.cpp) add_executable(myapp main.cpp) target_link_libraries(myapp PRIVATE mylib) add_custom_command(TARGET myapp POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:mylib> $<TARGET_FILE_DIR:myapp> )$<TARGET_FILE:mylib>展开成 mylib 的实际文件路径,包括 .dll 后缀和构建目录前缀;$<TARGET_FILE_DIR:myapp>展开成 myapp 所在目录。这样 Debug/Release 两种配置下,复制位置都会自动跟随,避免了手写 bin/Debug 和 bin/Release 分叉逻辑。
4.2 Release 模式下保留 PDB 文件
很多团队只在 Debug 开 PDB,线上崩溃时才发现 Release 没有符号文件。CMake 里可以针对 Release 单独开启。MSVC 下 PDB 需要编译端/Zi和链接端/DEBUG配合:
if(MSVC) target_compile_options(myapp PRIVATE $<$<CONFIG:Release>:/Zi>) target_link_options(myapp PRIVATE $<$<CONFIG:Release>:/DEBUG>) set_target_properties(myapp PROPERTIES PDB_NAME myapp PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/pdb" ) endif()$<$<CONFIG:Release>:/Zi>是生成器表达式加配置判断的典型用法,只有 Release 配置才追加 /Zi,Debug 使用默认设置。PDB_OUTPUT_DIRECTORY 把 pdb 统一收集到 build/pdb 目录,后续归档符号文件时只需打包这个目录。注意 /Zi 会让 cl.exe 为每个 obj 生成独立 pdb,链接器最后收集成最终 pdb;增量构建时中间 pdb 文件会增大磁盘占用,但换来 Release 崩溃时可解析的栈,值得保留。
4.3 CTest 与 File API:集成层的信息通道
cmake-file-api.7.html介绍的是 CMake 与 IDE 之间的协议。VSCode 的 CMake Tools、CLion、Visual Studio 都通过 File API 读取构建目录里的 codemodel,拿到 target 列表、编译命令和生成器信息。使用 zip 绿色包时,这些信息不需要额外服务,CMake 3.29.7 配置完成后,会在build/.cmake/api/v1/下生成响应文件。第三方工具读取这些 JSON 即可实现代码跳转和调试配置。明白这一点,就知道便携版 CMake 为什么能被 VSCode 完整支持。
ctest.1.html 对应的可执行文件就在 bin 目录。配置了测试后,用一条命令跑完所有测试并展示失败输出:
ctest --test-dir build-vs -C Release --output-on-failure--test-dir指定构建目录,-C对多配置生成器选择配置,--output-on-failure只在失败时打印测试输出,避免成功用例刷屏。
4.4 构建系统边界:include() 与第三方 SDK
很多嵌入式 SDK,比如 ESP-IDF,要求在自己的工程 CMakeLists.txt 里写一行:
include($ENV{IDF_PATH}/tools/cmake/project.cmake)这行指令看起来只是引入了一个文件,实际上是让 SDK 接管整个构建流程:它内部定义了大量函数和自定义目标,再通过 include 注入当前工程。CMake 的 include() 是构建系统的边界,适合导入 SDK 的逻辑;add_subdirectory() 是目标级边界,适合把子项目编译进同一个构建图。在 Windows 项目里,两者混用时要注意目录属性隔离,特别是需要严格控制编译器 flags 的场景,过早使用 add_subdirectory 会失去全局统一性。
5. 用 CMakePresets.json 固化参数:远程开发与本地构建的统一入口
5.1 从命令行参数到 preset
把前面所有配置参数写进源目录下的 CMakePresets.json,3.29.7 已经完整支持:
{ "version": 6, "cmakeMinimumRequired": { "major": 3, "minor": 29, "patch": 0 }, "configurePresets": [ { "name": "win-dev", "displayName": "Windows Ninja x64", "generator": "Ninja", "binaryDir": "${sourceDir}/build/dev", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release", "CMAKE_CXX_STANDARD": "17" } } ], "buildPresets": [ { "name": "win-dev", "configurePreset": "win-dev", "jobs": 8 } ] }${sourceDir}是 preset 自动展开的源目录宏,不需要写死绝对路径,天然适配本地和虚拟机的不同目录。之后配置、构建、测试变成三条固定命令:
cmake --list-presets cmake --preset win-dev cmake --build --preset win-devcmake --list-presets验证文件格式和可用项,后面两条完成配置和构建。第 3 章里那一长串-G和-D被固化进了版本库。
5.2 VSCode 远程开发中的版本锁定
在虚拟机里编译 C++ 项目时,VSCode 的 CMake Tools 扩展默认会在远程端搜索 cmake 可执行文件,容易受到多个版本干扰。更稳妥的方法是让扩展显式绑定便携版路径:
"cmake.cmakePath": "C:\\tools\\cmake-3.29.7-windows-x86-64\\bin\\cmake.exe", "cmake.configurePreset": "win-dev", "cmake.buildPreset": "win-dev"这一步把 CMakePresets.json 里定义的生成器全部交给扩展,VSCode 右下角不再需要手动选择。首次配置时如果报 “CMake executable not found”,检查 cmake.cmakePath 里反斜杠是否写成了双反斜杠,以及 JSON 文件是否被 BOM 头干扰。
5.3 验证版本一致性的最后一步
本地与流水线版本是否一致,可以用一条命令同时打印版本和生效路径:
cmake --version && where cmake如果输出版本为 3.29.7,且路径指向绿色目录,说明环境锁定成功。配合 CMakePresets.json 里的cmakeMinimumRequired,即使有人用旧版本打开工程,也会在配置阶段得到明确的版本异常提示,而不是等编译失败后才开始查原因。
本文还有配套的精品资源,点击获取