
简介面向 Windows x86_64 平台 CMake 使用者的 3.26.6 版本文档压缩包内含约两千个文件其中一千一百九十四个为文本文件八百零六个为网页文档整体大小约四十兆字节。内容围绕 CMake 构建生态的核心主题展开涵盖命令行工具用法、ctest 测试框架、生成器表达式、file-api、构建系统定义以及预设配置等离线说明便于开发者在无网络环境下查阅参考文档。文档以网页文件为主体文本文件多用于辅助阅读、检索或记录目录结构清晰可快速定位所需命令与变量。已有二百九十七人学习/下载具备一定实用参考价值。借助该压缩包可系统浏览 CMake 3.26.6 的文档体系理解构建变量与预设配置如何影响编译过程也能在编写 CMakeLists.txt 时迅速查询语法与执行逻辑减少在线文档翻找时间提升项目构建配置效率。1. Windows 下的 CMake 3.26.6这个 x86_64 绿色包解决了什么下载 cmake-3.26.6-windows-x86_64.zip 只要几秒但不少人解压后对着 bin 目录问“哪个才是主程序”。CMake 3.26.6 是官方为 Windows x86_64 发布的二进制版zip 里同时打包了 cmake.exe、cmake-gui.exe、ctest.exe、cpack.exe 和整套 HTML 手册解压即用不写注册表也不依赖额外安装器。它的价值在于一份资源同时给了三条入口命令行配置、图形界面、离线文档正好覆盖从第一次运行 cmake 命令到排查生成器表达式为什么没生效的全过程。适合刚转到 Windows 或刚开始学 CMake 的 C/C 开发者也适合需要多版本隔离的维护场景。2. 落地安装目录结构、PATH 配置与版本隔离2.1 解压与目录结构bin、share、doc 各自管什么我习惯先把 zip 解压到一个短路径比如 D:\cmake-3.26.6而不是保留默认的长目录名。原因很实在后面所有 PATH、脚本、IDE 工具链配置都要引用这个目录短路径能少打一串字符也避免部分旧工具对带空格的路径解析出错。解压后第一时间把目录结构过一遍比直接双击 exe 有用得多路径内容作用bin/cmake.exe命令行主程序负责 configure、build、install 全流程bin/cmake-gui.exe图形界面查看缓存变量、首次配置、重置缓存bin/ctest.exe测试命令读取 CTestTestfile.cmake 并执行测试用例bin/cpack.exe打包命令按 CPack 配置生成 zip/nsis/wix 安装包share/cmake-3.26/Modules内置模块FindXXX.cmake 与各类 CMake helper 脚本share/doc/cmake-3.26/html官方 HTML 手册cmake.1.html、cmake-presets.7.html、cmake-file-api.7.html 等doc 目录里的文件名沿用 Unix man page 的命名习惯例如 cmake-generator-expressions.7.html数字 7 表示杂项手册区段cmake.1.html 的 1 是用户命令区段。这个命名不影响阅读但知道之后在文档里定位会快很多。genindex.html 是文档总索引所有命令、变量、模块都能从它一站搜到我一般把它设成浏览器书签遇到拿不准的 CMake 语法直接进去查。拿到 zip 之后我一般先算一遍哈希再解压。网络下载的压缩包可能半路截断解压到一半报错更浪费时间Get-FileHash .\cmake-3.26.6-windows-x86_64.zip -Algorithm SHA256 Expand-Archive .\cmake-3.26.6-windows-x86_64.zip -DestinationPath D:\cmake-3.26.6第一行算 SHA256和官网发布的校验值比对确认文件完整、没被中间环节改动。第二行用 PowerShell 自带的 Expand-Archive 解压不需要额外装 7-Zip。这里专门说一下 -DestinationPath目标目录不存在时会自动创建我使用短路径 D:\cmake-3.26.6解压结果就是这个目录本身。如果你解压时遇到“zip 已经损坏”的提示多数情况不是压缩包写坏了而是浏览器下载线程中断导致的截断文件重新下载一次通常能解决。2.2 PATH 配置让 cmd 和 PowerShell 都能直接敲 cmake解压完成只是拿到了可执行文件距离“随手敲 cmake”还差一步把 bin 目录写进系统 PATH。图形界面方式是右键“此电脑” → “属性” → “高级系统设置” → “环境变量”在系统变量的 Path 里新建一条 D:\cmake-3.26.6\bin。如果你的系统 Path 还是那种一整条分号分隔的形式记得在末尾补上英文分号再追加别把两段路径粘到一块。批量装机场景下我使用管理员 PowerShell 执行 setx 命令setx /M PATH $env:Path;D:\cmake-3.26.6\bin/M 表示修改系统级变量需要管理员权限。$env:Path 先展开当前进程的 PATH 快照再追加新目录。这条命令有个众所周知的坑当原有 PATH 超过 1024 字符时setx 可能截断后面的内容导致系统里部分已有工具失效。所以我更推荐图形界面一条条编辑至少每次改动都能看到完整清单。改完 PATH 之后所有已经打开的终端窗口都不会自动响应必须重新开一个新窗口测试。验证是否生效新终端里执行两条命令cmake --version where.exe cmakecmake --version 输出 “cmake version 3.26.6” 说明当前命中的就是新装的版本。where.exe cmake 会把所有候选路径按查找顺序列出来如果系统里同时装有 Visual Studio 自带组件或 Qt 自带的 CMake这里会输出多行从上到下的顺序就是最终生效顺序。我遇到不少“明明装了新版却显示旧版”的情况根因就是旧版目录排在新版前面命令解析器先找到了它。2.3 版本验证与多版本隔离一台机器存放多个 CMake 的正确姿势Windows 上的 CMake 版本冲突几乎是必然事件Visual Studio 装 C 桌面开发时会带一份 CMakeQt 安装器会往 PATH 塞一份自己手动再装一份三份并存是常态。这时候不要急着互相删旧版本可能是某个老项目的既定环境删了反而导致旧项目无法回归。更稳的做法是项目内显式声明最低版本同时用完整路径区分调用cmake_minimum_required(VERSION 3.20)这段写在 CMakeLists.txt 第一行作用是告知 CMake 用哪套策略处理后续命令。如果手滑调用了旧版本CMake 会在配置阶段直接报错 “CMake 3.20 or higher is required”而不是留到编译期给一个莫名其妙的错误。需要手动指定版本时直接在脚本里写全路径 D:\cmake-3.26.6\bin\cmake.exe -S . -B build -G NinjaPowerShell 里用 调用带路径的 exe效果等同于命令行输入完整绝对路径。这个方法看着笨却是 Windows 多版本环境中最确定性最强的手段它绕开了 PATH 顺序和符号链接的所有不确定性。补充一点3.26.6 解读老项目时有个容易忽略的变化——CMake 会按 cmake_minimum_required 声明的版本自动启用对应策略兼容层。同一个 3.26.6 可以构建声明了 3.5 的老项目也能使用新版本语法关键就在第一行的策略版本。老项目不要直接把 cmake_minimum_required 改成新版除非你已经排查过新旧策略差异否则会出现诸如 Qt 路径变化、in-source build 被禁用这类行为改变。3. CMake 与 Makefile 的本质区别它不是构建工具而是构建系统的生成器3.1 生成器机制CMake 为什么要分 configure 和 build 两阶段很多新手第一次听到“cmake 和 makefile 区别”时会把 CMake 当成比 Make 更高级的构建工具这个理解偏差会直接导致使用上的误操作。CMake 自己不编译代码它读取 CMakeLists.txt生成一层真正的构建脚本——可能是 Makefile可能是 build.ninja也可能是 .sln——然后由对应的后端工具完成编译。这个区分是理解全部 CMake 行为的基础。同一份 CMakeLists.txt 在不同平台可以选择不同后端这就是“生成器”的概念。Windows 上常用生成器的选型差异生成器产物适用场景Visual Studio 17 2022.sln / .vcxproj需要 VS IDE 调试、远程部署Ninjabuild.ninja命令行快速构建、CI 环境MinGW MakefilesMakefile搭配 MinGW-w64 的 g 工具链NMake MakefilesMakefile搭配 MSVC 的 nmake老项目常见选生成器的经验是日常开发调试首选 VS 生成器它把 target 信息全部映射到解决方案里断点、内存、调用栈集成完整CI 或纯命令行场景优先 Ninja构建速度快、输出简洁、跨平台行为一致。不要用 VS 生成器做“纯命令行编译”虽然它也能跑但每次 --build 都要带 --config 指定构建类型繁琐且容易漏。configure 和 build 分离不是 CMake 故意设计的繁琐而是元构建系统的必然要求。configure 阶段要探测编译器、解析指令、确认依赖路径是否存在这些结果会被写进 CMakeCache.txt。build 阶段只读缓存和生成的构建文件基本不做环境探测。所以你切换了编译器、修改了系统环境变量、新增了依赖目录之后必须重新 configure 一次否则 build 阶段读到的还是旧配置。很多“我改了头文件路径为什么还报错”的案例根因就是忘了重新运行 cmake -S . -B build。3.2 一个最小 CMakeLists.txt 长什么样三行跑通一个 exe把一个 cpp 文件编译成可执行文件最小配置只需要三行cmake_minimum_required(VERSION 3.20) project(hello VERSION 1.0.0 LANGUAGES CXX) add_executable(hello main.cpp)cmake_minimum_required 必须出现在所有命令之前它决定 CMake 使用哪一版策略集合解释后续指令。project 声明项目名 helloVERSION 记录项目版本LANGUAGES CXX 会触发 C 编译器探测流程也就是把 MSVC 的 cl.exe 或 MinGW 的 g.exe 找出来。add_executable 定义构建目标 hello源文件是 main.cpp。如果这个 cpp 里用了第三方头文件补一行target_include_directories(hello PRIVATE include)PRIVATE 表示 include 目录只影响 hello 这个目标本身不会传播到依赖 hello 的其他目标。这个修饰符不是随便写的在大型项目里它决定头文件搜索路径的可见边界用错就会出现“别人能编过、我这个 target 编不过”的诡异现象。target 作用域规则属于 cmake-buildsystem.7.html 文档里最核心的内容新手阶段先把 PRIVATE / PUBLIC / INTERFACE 的差异记牢比背一堆变量有用。接着执行 configure 和 buildcmake -S . -B build -G Ninja cmake --build build -j 8-S 指定源码目录-B 指定构建目录构建目录是 CMake 的临时工作区生成文件、缓存、编译产物全部隔离在里面。删除 build 目录等于彻底重置这句代码在排障时经常被用到因为它比一条条清理 CMakeCache.txt 可靠得多。-G 指定 Ninja-j 8 控制并行任务数Ninja 本身就是为并行优化的在这个后端下 -j 的意义比 Makefile 更明显。3.3 构建类型为什么总是默认 Debug单配置与多配置生成器的区别Windows 新手最容易踩的一个认知盲区是 CMAKE_BUILD_TYPE。Ninja、MinGW Makefiles 这类生成器是“单配置”的CMAKE_BUILD_TYPE 作为缓存变量写死在配置阶段默认值是空或 Debug。Visual Studio 是“多配置”的它不依赖这个变量而是在构建时用 --config 参数切换四套配置。单配置生成器指定 Release 的方式是cmake -S . -B build -DCMAKE_BUILD_TYPERelease-D 临时覆盖缓存变量等号两侧不要留空格留了空格会被解析成多个命令行参数CMake 直接报错。配置阶段忘记指定的话Ninja 构建产出的默认就是未优化、带调试符号的 Debug 版本体积大、运行慢发布时拷到别的机器还可能因为依赖 Debug 运行库直接起不来。多配置生成器的示例cmake --build build --config Release这里不需要给 CMAKE_BUILD_TYPE 赋值不同配置的编译选项已经在配置阶段写入 .vcxproj构建时只需要选一套。理解了单配置和多配置的区别你就不会再困惑“为什么我在 CMakeLists 里写了 set(CMAKE_BUILD_TYPE Release) 却对 VS 生成器无效”这类的经典问题。3.4 ctest 与 cpackzip 里另两个被忽视的命令行工具打开 zip 的 bin 目录除了 cmake.exe 和 cmake-gui.exe还有 ctest.exe 和 cpack.exe。它们分别是测试驱动和打包工具。ctest 读取构建目录里的 CTestTestfile.cmake执行所有已经注册的测试用例。最小用法是在 CMakeLists.txt 里include(CTest) add_test(NAME smoke COMMAND hello --smoke-test)include(CTest) 会引入 CTest 模块并注册构建目录的测试入口。add_test 注册一个名为 smoke 的测试执行命令是 hello --smoke-test。之后在构建目录跑 ctest --output-on-failure测试失败时终端会直接打印子进程输出定位问题比手动运行快不少。cpack 则是打包环节配置 CPACK_GENERATOR 为 ZIP 或 NSIS运行 cpack 就能产出分发包。Windows 下最常用的是 ZIP 和 NSIS前者适合内部分发后者适合做带向导的安装程序。cpack 的配置项一般放在独立分支里例如针对不同打包格式设置不同元数据如果打包出来的 zip 打开后 exe 直接启动失败先看一下是不是漏了运行时 DLL这一步排查比反复重打包更有效。4. 命令行与 GUI 双线实操从 configure 到 install 的完整动作4.1 三步构建流程configure、build、install 的边界划分拿到一个已有 CMakeLists.txt 的项目第一步不是点开 IDE 而是跑通命令行流程。命令行的逻辑固定为三步configure 生成构建脚本build 产出目标文件install 把产物复制到安装前缀。一个带安装规则的最小项目cmake_minimum_required(VERSION 3.20) project(cli_tool VERSION 0.1.0 LANGUAGES CXX) add_executable(cli_tool src/main.cpp) install(TARGETS cli_tool RUNTIME DESTINATION bin)install(TARGETS cli_tool RUNTIME DESTINATION bin) 表示安装阶段把 cli_tool.exe 放到安装前缀的 bin 子目录。执行完整流程cmake -S . -B build -G Visual Studio 17 2022 -A x64 cmake --build build --config Release cmake --install build --prefix D:\app\cli_tool第一条命令中 -G 指定 VS 2022 生成器-A x64 指定目标架构第二条 --build 必须带 --config Release否则 VS 多配置生成器默认编 Debug第三条 --prefix 覆盖默认安装路径不带时 Windows 默认是 C:\Program Files\cli_tool非管理员会因为权限不足直接失败。这里经常有人问build 的时候用了 --configinstall 为什么不带原因在于 install 阶段执行的是构建目录里已经生成的 cmake_install.cmake 脚本它按配置阶段预设的规则复制文件不重新编译所以不用重复指定 --config。但有一个容易忽略的细节如果你修改了 CMakeLists.txt 里的 install 规则却没有重新 configure--install 可能还是按旧规则执行。碰到“我加了新文件怎么没装进去”的案例先重新 configure再 install十次有八次能解决。4.2 cmake-gui 实操查看缓存变量、重置配置与处理红条命令行固然高效但 cmake-gui 在几个场景里不可替代第一次看陌生项目的缓存变量、排查某个变量为什么没生效、配置彻底混乱时一键重置重来。cmake-gui 顶部是源码目录和构建目录选择框点击 Configure 弹出生成器选择选完开始首次配置。配置过程中界面会刷出大量变量条目红色条目代表 CMake 未能找到或读取失败的项比如找不到的依赖、没有默认值的路径。处理手法是按红色条目逐项排查把缺失的路径补上再点 Configure 重新计算。变量清干净后点 Generate构建文件才会生成。这个“红条清零”的过程就是配置完成的直观标志。GUI 的另一个价值是变量查看。命令行 cmake -LA -N build 只能静默列出全部缓存变量GUI 里输入 CMAKE_ 前缀、BUILD_ 前缀能立刻过滤出相关组这个在数千行的大型项目里特别省力。遇到“这个变量是哪里来的”疑问时在 GUI 里点击变量能在右侧帮助栏看到定义它的模块和文档链接追溯效率比读源码更高。另外注意如果之前用命令行配置过构建目录生成器选择和 GUI 里选的不一致GUI 会提示缓存冲突。这时直接 File → Delete Cache从头走一遍 Configure别尝试保留缓存和生成器混用。4.3 用 CMakePresets 固化构建配置把一长串参数存成 json从 CMake 3.19 开始官方推荐用 CMakePresets.json 替代手写命令3.26.6 对预设的支持已经非常完善。预设文件放在源码根目录把生成器、架构、缓存变量、构建类型全部固化下来。一个 Windows VS2022 的预设示例{ version: 3, cmakeMinimumRequired: { major: 3, minor: 21, patch: 0 }, configurePresets: [ { name: win-vs2022, displayName: Windows VS2022 x64, generator: Visual Studio 17 2022, architecture: x64, binaryDir: ${sourceDir}/build/vs2022, cacheVariables: { CMAKE_BUILD_TYPE: Release } } ], buildPresets: [ { name: win-vs2022-release, configurePreset: win-vs2022, configuration: Release } ] }version 字段表示预设 schema 版本3 对应 CMake 3.21 之后支持的格式。cmakeMinimumRequired 指定解析这个文件需要的最低 CMake 版本。configurePresets 数组里每一项描述一次配置动作name 是调用时的标识architecture 只有 VS 生成器才识别binaryDir 支持 ${sourceDir} 这种预设变量。buildPresets 引用 configurePreset 并指定 configuration。写好后执行cmake --preset win-vs2022 cmake --build --preset win-vs2022-release新同事 clone 项目后跑这两条命令就完成配置和构建不再需要对着 README 逐字复制一长串 cmake 参数。预设文件可以提交到版本库但不要把和具体机器绑定的绝对路径写进去否则换个开发机就要改文件。cmake-presets.7.html 文档里对每个字段都有详细说明拿不准时先翻它比自己试错快。5. 避坑排查Windows 上 CMake 实战最常见的五个坑5.1 配置阶段报 “The C compiler identification is unknown”现象执行 cmake -S . -B build 后CMake 在探测编译器时中断日志里出现 “The C compiler identification is unknown” 或 “CMAKE_CXX_COMPILER not found”。原因CMake 本身不是编译器它需要在系统里找到 C/C 编译器。最常见的情况是只装了 CMake 没装编译工具链或者装了 Visual Studio 但当前终端没有继承 VS 的环境变量。解决先把编译工具装好。Visual Studio 的“使用 C 的桌面开发”工作负载包含 MSVCMinGW-w64 是另一条路线。确认工具链存在后Ninja 生成器场景下可以显式指定编译器地址cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILERD:/mingw64/bin/g.exe注意 D:/mingw64/bin/g.exe 用的是正斜杠Windows 下 CMake 对反斜杠转义处理容易出问题正斜杠兼容性更好。如果你是 VS 生成器记得从开始菜单的 Developer PowerShell 启动终端普通 cmd 拿不到 cl.exe 的环境变量同样会触发编译器探测失败。5.2 cmake-gui.exe 双击闪退或提示缺少 VCRUNTIME140.dll现象解压 zip 后双击 bin/cmake-gui.exe弹窗提示缺少 VCRUNTIME140.dll或者窗口一闪而过直接关闭。原因CMake 官方 zip 版运行依赖 VC 可再发行运行库Windows 10/11 的纯净系统不一定预装完整。解决安装 “Visual C Redistributable for Visual Studio 2015-2022”x64 版本即可。装完重新打开 cmake-gui.exe 就没问题。这个坑是安装版和 zip 版的差异点安装版内置了运行库依赖绿色包不带。如果你的目标机器不允许联网装运行库可以把 VC_redist.x64.exe 放到同目录装机脚本里静默安装一步到位。5.3 配了 PATH 但新终端的 cmake 还是旧版本现象刚把 D:\cmake-3.26.6\bin 加到系统 PATH重开终端执行 cmake --version显示的依然是旧版本。原因命令解析器按 PATH 顺序查找旧 CMake 目录排在新版本前面被优先命中。另一个可能是终端没有真正重建环境变量不会推送给已经运行的进程。解决先看 where.exe cmake 的完整输出确认到底找到哪些路径然后调整 PATH 排序。如果不想动系统环境变量临时会话可以手动覆盖$env:Path D:\cmake-3.26.6\bin; $env:Path cmake --version这段命令把新目录插到 PATH 头部只对当前 PowerShell 会话生效适合快速验证新版是否能正常工作。验证完再回图形界面调整系统 PATH 排序既不影响当前工作也不会出现改坏了没法回退的情况。5.4 构建成功但 exe 双击没反应或提示缺少 DLL现象cmake --build 顺利结束生成目录里确实有 app.exe但双击运行黑窗一闪而过或者弹窗提示缺少某个 DLL。原因最常见的是用 VS 多配置生成器构建了默认 DebugDebug exe 依赖 Debug 版运行时。其次是动态链接的第三方库 DLL 没有复制到 exe 旁边。解决显式构建 Release再补齐运行时依赖。Qt 项目会用 windeployqt 自动收集依赖cmake --build build --config Release windeployqt build/Release/app.exewindeployqt 是 Qt 自带的部署工具把 Qt 相关的 DLL、插件、翻译文件复制到 app.exe 所在目录。非 Qt 项目可以查一下构建目录里生成的中间输出目录看看运行时依赖是否已被拷贝没有的话在 CMakeLists 里用 add_custom_command 加一条构建后复制 DLL 的指令。5.5 include_directories 写在 add_executable 之后导致头文件找不到现象CMakeLists.txt 里明明写了 include_directories(include)编译仍然报 “No such file or directory”。原因include_directories 是一个目录属性指令只影响“其调用之后定义的目标”。把 include_directories 放到 add_executable 之后这个目标就吃不到头文件路径。解决把 include_directories 移到 add_executable 之前或者改用 target_include_directories 把包含路径和具体目标绑定add_executable(app src/main.cpp) target_include_directories(app PRIVATE include)这个改法更推荐因为 target_include_directories 明确限定路径属于 app 这个目标不会像 include_directories 那样把路径塞给后续所有目标导致目标间耦合加深。大型项目里正确定义包含目录的边界是减少“A 目标能用、B 目标不能用”这类奇怪报错的关键。6. 进阶用法生成器表达式与文件 API 的实战价值6.1 生成器表达式让编译选项按配置自动切换cmake-generator-expressions.7.html 这份文档一开始被我忽略后来才知道它是诊断配置问题的核心工具。生成器表达式在生成阶段求值区别于普通变量的配置阶段求值最典型的用法是按构建类型调整编译选项。同一个机制也能用来按配置选择链接库、设置预处理宏甚至控制是否添加 strip 指令target_compile_options(app PRIVATE $$CONFIG:Release:/O2 $$CONFIG:Debug:/Od;/Zi ) target_link_options(app PRIVATE $$CONFIG:Release:/OPT:REF )$ CONFIG:Release 判断当前配置是否是 Release为真时后面的 /O2 才进入编译命令行。这样 Debug 和 Release 共用一份 CMakeLists不用写两套 if 分支。链接选项里的 /OPT:REF 相当于在 MSVC 下做一次裁剪处理掉未引用的代码段效果类似 Linux 下的 strip 加瘦身。6.2 文件 API让 IDE 和脚本能读懂构建系统cmake-file-api.7.html 描述了一种构建系统自省机制CMake 配置阶段会把 target、依赖关系、编译命令导出为 JSON 文件IDE 和脚本可以读取这些 JSON 来掌握项目结构。使用方式是在构建目录创建 .cmake/api/v1/query 目录重新运行 cmake 配置就会在 .cmake/api/v1/reply 下生成 codemodel-v2.json。除了 codemodel还有 compile_commands.json 对 clangd、CLion 这类编辑器特别有用。只要在 CMakeLists 里设置 set(CMAKE_EXPORT_COMPILE_COMMANDS ON)CMake 就会为每个源文件导出完整编译命令行编辑器拿着它就能跳转和补全比手动配 include 路径可靠得多。我拿到新项目时的习惯动作是先跑一次配置然后读取 codemodel 里的 target 依赖列表检查有没有循环依赖。循环依赖在 CMakeLists 里肉眼经常看不出来但 JSON 数据结构里一目了然。从那以后我每次接手新项目都强制走一遍这个检查流程再开始写构建脚本省下了不少排查低层问题的冤枉路希望帮到你。本文还有配套的精品资源点击获取