简介:面向 Windows 64 位平台 C++ 开发者的 CMake 3.30.3 配套资料包,适合需要离线查阅构建系统文档、核对命令用法或排查 CMakeLists 配置问题的初中级开发者。压缩包共 2000 个文件,以 1147 个 txt 文本和 853 个 html 页面为主,整体约 43.34MB,可按主题快速检索命令行手册、构建系统说明、生成器表达式、预设、变量及 CTest 等内容。已有 512 人学习下载,说明其在 Windows 平台 CMake 使用场景中具有一定参考价值。读者可借助这套资料理解 CMake 的配置与生成流程,对照查找编译选项、依赖管理、测试命令和常见构建报错思路,也可作为项目迁移到 64 位 Windows 环境时的离线参考手册。
1. 新机器上第一个cmake --version就翻车
新配的开发机,编译器装好了,编辑器装好了,随手敲一句cmake --version,出来个 3.20,后面配工程直接被cmake_minimum_required(VERSION 3.30)顶回来。Windows 上装 C++ 构建环境,翻车点几乎从来不在安装包本身,而在装完之后那几步:PATH 里有几个 cmake、生成器默认给了哪个架构、构建目录里躺着谁的旧缓存。cmake-3.30.3-windows-x86-64 这个包解压下来只有几十兆,双击下一步下一步三分钟能装完,可它后面要接的是 MSVC、MinGW、Ninja 这一整条 C++ 工具链,任何一环对不上,报错信息都不会告诉你真实原因。这套环境适合刚在 Windows 上搭 C++ 构建链的人,也适合手上同时维护新老工程、需要让 3.30.3 和旧版本共存的人。
2. 版本与安装包选型:cmake-3.30.3-windows-x86-64 的三个文件怎么挑
2.1 先确认你的机器要的是 x86-64 还是 arm64
名字里的windows-x86-64说的是宿主机的 CPU 架构,不是你要编译出来的目标程序架构。这两件事在 CMake 里是完全分开的:宿主架构决定你下哪个安装包,目标架构由生成器参数(比如-A x64)决定。很多人第一次接触会下意识觉得"我要编 32 位程序,是不是得下个 x86 的包",结果跑去找一个并不存在的 32 位安装包。
判断方法很简单,开一个终端敲:
# cmd 或 PowerShell 里都可以执行 echo %PROCESSOR_ARCHITECTURE% # 输出 AMD64 → 用 x86-64 包 # 输出 ARM64 → 用 arm64 包AMD64和x86_64是同一个东西的两种叫法,看到它就用 x86-64 包,不用犹豫。ARM64 的机器(部分轻薄本、部分开发板)才需要另一个包。装错架构的典型现象不是装不上,而是装上了但调用时提示"不是有效的 Win32 应用程序",或者干脆一闪而过。
这套包一般会给出三种形态,选型上我按用途分:
| 包形态 | 适用场景 | 后续维护成本 |
|---|---|---|
.msi安装包 | 个人开发机、单版本常驻 | 低,卸载走控制面板 |
.zip便携版 | 多版本共存、CI 机器、无管理员权限 | 中,自己管 PATH |
| 源码包 | 需要自己编 CMake 本身 | 高,Windows 上不建议新手碰 |
绝大多数人用.msi。只有当你要在同一台机器上同时留 3.20、3.30.3、3.31 三个版本,或者公司的机器不给你管理员权限时,才值得走.zip。
2.2 3.30.3 这个补丁号在版本链上的位置
CMake 的版本号是主.次.补丁。3.30是特性版本,.3是这一条线上的第三个补丁。补丁版本只修 bug、不引入新行为,所以 3.30.3 相对 3.30.1 是安全的替换关系,不会让你昨天能编的工程今天编不过。
真正会影响兼容性的是3.30这个次版本号,因为 CMake 每升一个次版本就会引入新的策略(policy)。3.30 里有两个策略值得提前知道:
CMP0167:FindBoost模块被移除。cmake_minimum_required写到 3.30 之后,老工程里那句find_package(Boost)不再走 CMake 自带的查找模块,改为要求 Boost 自己提供BoostConfig.cmake。CMP0169:FetchContent_Populate的单参数形式被标记为弃用。
这两条不是让你不用 3.30,而是提醒你:给老工程升 CMake 之前,先看一眼它cmake_minimum_required写的是多少。写3.20的工程在 3.30.3 下照样按 3.20 的策略跑,不会因为换了 CMake 就炸;只有把最低版本也一起提到 3.30 才会触发新策略。
常见做法是:新工程直接写cmake_minimum_required(VERSION 3.30),老工程保持原样,除非你确实要用 3.30 的新特性。补丁号我一般会在 README 里写死到3.30.3,因为团队里每个人的 CMake 版本不一致时,"最低 3.30"和"实际 3.30.3"之间的差异足够制造一次排查。
2.3 装之前的机器前置检查
装 CMake 本身没有任何运行时依赖,不需要额外的运行库,也不需要预先装编译器——CMake 只负责生成构建文件,编译器是后面配置阶段才去找的。但为了少走回头路,装之前把下面三件事确认掉:
# 1. 看现在系统里到底有几个 cmake Get-Command cmake -All -ErrorAction SilentlyContinue | Select-Object Source # 2. 看 PATH 里有没有残留的旧版本目录 $env:Path -split ';' | Where-Object { $_ -match 'cmake|CMake' } # 3. 确认当前终端是不是管理员权限(决定用 Machine 还是 User 级 PATH) ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole('Administrators')第一条最关键。Get-Command cmake -All会把 PATH 里所有叫cmake的可执行文件全列出来,按 PATH 顺序排列。如果这里已经出现两条以上,说明你机器上至少有两个 CMake,装完新的之后必须处理顺序问题,否则你装的是 3.30.3,敲出来还是旧的。第三条决定后面改环境变量时用 Machine 级还是 User 级——没有管理员权限就老老实实改 User 级,别硬改 Machine 级,改坏了整个系统环境变量都得重建。
提示:这三条查完再动手装。我自己吃过一次亏,装完发现 PATH 里排在前面的是某个 IDE 自带的 cmake,白折腾了半小时。
3. 安装落地:MSI 与 ZIP 两条路径的完整操作
3.1 MSI 安装包的逐项勾选
双击cmake-3.30.3-windows-x86_64.msi,前面两页是许可和欢迎页,真正需要动脑的只有一页:安装选项。
- Add CMake to the system PATH for all users:写机器级 PATH,所有用户都能用。个人开发机选这个。
- Add CMake to the system PATH for the current user:只写当前用户的 PATH。公司机器没有管理员权限时选这个。
- Do not add CMake to the system PATH:什么都不写。只有你打算自己管理 PATH(比如多版本共存)时才选。
目标目录默认是C:\Program Files\CMake。我一般不改这个默认值,原因是很多脚本和文档里默认路径就是它,改了以后每次排查还要多问一句"你装哪儿了"。真要多版本共存,走 ZIP 版,别把 MSI 装到奇奇怪怪的目录里。
如果你要在多台机器上批量铺开,可以走静默安装:
# 静默安装,并写入机器级 PATH msiexec /i cmake-3.30.3-windows-x86_64.msi /qn ADD_CMAKE_TO_PATH=System # 只装不写 PATH(留给后面的脚本统一处理) msiexec /i cmake-3.30.3-windows-x86_64.msi /qn ADD_CMAKE_TO_PATH=""/qn表示无界面,ADD_CMAKE_TO_PATH控制 PATH 写入行为,System对应机器级,留空对应不写。这两条命令适合放在部署脚本里,但要注意:静默安装不会给你任何中间反馈,装完必须自己验证一遍。如果某台机器上参数没生效(版本不同的 MSI 对这个属性的支持有差异),不要跟它较劲,装完手动补 PATH 更省时间。
装完立刻开一个全新的终端窗口——已经开着的终端不会重新读环境变量,这一步漏掉的人非常多。
cmake --version # 期望输出:cmake version 3.30.3 where cmake # 期望只输出一行:C:\Program Files\CMake\bin\cmake.exe3.2 ZIP 便携版的手动部署
ZIP 版解压出来的目录结构是这样的:
cmake-3.30.3-windows-x86_64/ ├── bin/ │ ├── cmake.exe │ ├── cmake-gui.exe │ ├── ctest.exe │ └── cpack.exe ├── doc/ └── share/ └── cmake-3.30/ └── Modules/ # 所有 find_package 用的查找脚本都在这我会把它放到一个统一的工具目录,比如C:\Tools\cmake-3.30.3,然后把C:\Tools\cmake-3.30.3\bin加进 PATH。之所以不用C:\Program Files,是因为多版本共存时你会需要同时放 3.29、3.30.3、3.31 三个目录,Program Files下面堆一堆带版本号的文件夹看着很乱,而且 ZIP 版放在Program Files下还会牵扯 UAC 权限问题。
加 PATH 的 PowerShell 写法,带重复检查:
$newPath = 'C:\Tools\cmake-3.30.3\bin' $current = [Environment]::GetEnvironmentVariable('Path', 'User') # 先判断是否已经存在,避免反复执行把 PATH 撑爆 if ($current -notlike "*$newPath*") { [Environment]::SetEnvironmentVariable('Path', "$newPath;$current", 'User') Write-Host "已追加: $newPath" } else { Write-Host "已存在,跳过" }第二个参数'User'表示写用户级环境变量,不需要管理员权限。字符串拼接时把$newPath放在前面,是因为 Windows 的 PATH 是从左到右查找的,放前面才能保证新的 3.30.3 优先于任何旧的 cmake。这一段里的重复检查不是洁癖:PATH 被反复追加同一个目录,会撑过 2047 字符的长度限制,然后整个用户级 PATH 被截断,那才是真正的灾难。
ZIP 版还有一个隐性好处:你可以直接不写 PATH,用绝对路径调用。CI 脚本里我经常这么干,C:\Tools\cmake-3.30.3\bin\cmake.exe -S . -B build,完全不依赖环境变量,机器上装了几个 CMake 都跟我无关。
3.3 PATH 与多版本共存的实际取舍
多版本共存的核心不是"能不能装上",而是"调用的时候能不能确定用的是哪一个"。三种做法,按可靠程度排序:
第一种,绝对路径调用。最笨但最可靠,写死在脚本里,谁也干扰不了。缺点是命令行难敲,适合 CI 不适合日常。
第二种,PATH 顺序控制。新版放前面,旧版放后面,cmake --version出来的就是新版。缺点是 IDE 里启动的进程可能继承的不是你终端里的 PATH,比如某些编辑器会注入自己带的工具链目录。
第三种,每个版本配一个批次文件,起不同名字:
:: 保存为 cmake330.cmd,放在 PATH 里的某个目录下 @echo off "C:\Tools\cmake-3.30.3\bin\cmake.exe" %*%*会把所有参数原样透传,所以cmake330 --version、cmake330 -S . -B build都能用,而且完全不受 PATH 顺序影响。我在这台需要同时维护三个年代工程的机器上就是靠这个活下来的——新工程用cmake,老工程固定用cmake320,互不干扰。
注意:不管用哪种方式,验证的时候一定要开新终端。在旧终端里
set PATH=...只对当前会话有效,关掉就没了,很容易误以为配置没生效。
4. 配置 C++ 工具链:让 CMake 3.30.3 找到编译器
4.1 生成器怎么选:先把街上的选项看清楚
CMake 本身不编译代码,它只负责把CMakeLists.txt翻译成某个构建系统能读的文件。这个"翻译成什么"就是生成器(generator)。Windows 上常见的三类:
# 列出本机可用的所有生成器 cmake --help # 只看生成器段落,输出更清爽 cmake --help | Select-String -Pattern "Generators" -Context 0,30- Visual Studio 17 2022:装了对应版本的 VS 就能用,默认是 Win32 架构,必须显式加
-A x64,这是最高频的一个坑。它产出.sln,支持多配置(Debug/Release 共用一套构建目录)。 - Ninja:单配置,快,需要
ninja.exe在 PATH 里,还需要一个能找到的编译器(MSVC 或 clang)。日常迭代我首选它。 - MinGW Makefiles:需要 MinGW-w64 工具链在 PATH 里。装了 MSYS2 或者独立 MinGW 的人用这个。
选择的判断标准很简单:只装了 Visual Studio 就用 VS 生成器;装了 VS 又想要更快的增量编译,装个 Ninja 用 Ninja 生成器,编译器仍然指向 MSVC;完全不想装 VS,用 MinGW + MinGW Makefiles。
生成器也可以不写在命令行里,改用环境变量固化:
# 当前会话有效,适合写进 CI 的 step 里 set CMAKE_GENERATOR=Ninja set CMAKE_BUILD_TYPE=ReleaseCMAKE_GENERATOR一旦设了,所有不显式带-G的cmake调用都用它。这在 CI 里很省事,但也制造过一个很难查的问题:本地设过一次忘了清,后来所有工程都悄悄用了 Ninja,某天换了个没装 Ninja 的机器,报错信息是"CMAKE_MAKE_PROGRAM 未设置",跟生成器本身没关系似的。
4.2 最小工程骨架:从 CMakeLists.txt 到可执行文件
先建一个能跑通的最小工程,别一上来就拿大项目试。目录结构:
demo/ ├── CMakeLists.txt └── src/ └── main.cppCMakeLists.txt内容:
# 最低版本写 3.30,触发 3.30 的策略集 cmake_minimum_required(VERSION 3.30) # 工程名和语言,CXX 表示只启用 C++ project(demo LANGUAGES CXX) # 要求编译器至少支持 C++17 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # 把 src/main.cpp 编成可执行文件 demo add_executable(demo src/main.cpp)src/main.cpp随便写个打印就行。四个参数里,CMAKE_CXX_STANDARD_REQUIRED ON表示编译器不支持 17 就报错而不是悄悄降级,CMAKE_CXX_EXTENSIONS OFF表示不用-std=gnu++17这类扩展语法,保证代码在 MSVC 和 MinGW 下行为一致。这两行在跨编译器项目里我从来不放。
配置和构建:
# 配置:-S 源码目录,-B 构建目录,-G 生成器,-A 目标架构 cmake -S . -B build -G "Visual Studio 17 2022" -A x64 # 构建:--config 指定配置类型,只对多配置生成器有意义 cmake --build build --config Release # 运行产物 .\build\Release\demo.exe-S和-B分开写的好处是源码目录永远干净,所有中间产物都在build/里,删掉重建不心疼。-A x64只在 VS 生成器下有效,用了 Ninja 再加这个参数会直接报"不支持的参数"。
用 Ninja 的话是另一套写法:
# Ninja 是单配置生成器,配置类型在配置阶段就要定 cmake -S . -B build-ninja -G Ninja -DCMAKE_BUILD_TYPE=Release cmake --build build-ninja单配置生成器的CMAKE_BUILD_TYPE必须在这里给,构建阶段再给没用。这是从 VS 生成器切过来最容易忘的一点。
4.3 Presets 与缓存变量:把参数固化下来
每次都敲一长串-G "Visual Studio 17 2022" -A x64 -DCMAKE_...,迟早会敲错一个字符。CMakePresets 就是为这个场景设计的。在工程根目录建CMakePresets.json:
{ "version": 6, "configurePresets": [ { "name": "vs2022-x64", "displayName": "VS2022 x64 Release", "generator": "Visual Studio 17 2022", "architecture": "x64", "binaryDir": "${sourceDir}/build/vs2022", "cacheVariables": { "CMAKE_CXX_STANDARD": "17" } }, { "name": "ninja-release", "displayName": "Ninja Release", "generator": "Ninja", "binaryDir": "${sourceDir}/build/ninja", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } } ] }这里version我故意写6而不是更高的值。Presets 的 schema 版本和 CMake 版本是绑定的,写高了会导致低版本的 CMake 直接拒绝读取整个文件。团队里有人还用 3.25 的时候,version: 6是兼容下限,够用就好。
用法:
# 列出所有可用的 preset cmake --list-presets # 用指定的 preset 配置 cmake --preset vs2022-x64 # 构建(自动对上同名 preset 的构建目录) cmake --build --preset vs2022-x64个人特有的路径(比如本机编译器位置)不该提交到仓库,放到CMakeUserPresets.json里,这个文件加进.gitignore,它会覆盖同名的公共 preset。
另一种固化方式是缓存变量。配置阶段用-D传进去的值会写进CMakeCache.txt,下次配置直接复用。查明当前缓存里有什么:
# -L 列出缓存变量,-N 只看不配置 cmake -LA -N build这个命令在接手别人构建目录时特别好用——不用问人,直接能看出他当时用的是哪个编译器、哪个架构、开了什么开关。-N的作用是只看现有结果不重新跑配置,避免因为环境变量缺失又引入新问题。
5. 避坑与排查:五条 Windows 上装 CMake 的翻车记录
5.1 敲出来的版本号不是 3.30.3
现象:装完 MSI,PATH 选项也勾了,新开终端敲cmake --version出来还是 3.20.x。
原因:where cmake能查出多条时,Windows 只取 PATH 最左边那一条。某个 IDE 安装时把自己的 cmake 目录写进了系统 PATH 的前半段,MSI 追加的C:\Program Files\CMake\bin排在了后面。
解决:先定位所有实例,再调整顺序,别直接删——那个 IDE 可能依赖它自带的版本。
# 找出所有 cmake.exe 及其所在目录 Get-Command cmake -All | Select-Object -ExpandProperty Source # 把 CMake 官方目录提到用户级 PATH 的最前面 $p = [Environment]::GetEnvironmentVariable('Path','User') $target = 'C:\Program Files\CMake\bin' $rest = ($p -split ';' | Where-Object { $_ -and $_ -ne $target }) -join ';' [Environment]::SetEnvironmentVariable('Path', "$target;$rest", 'User')重开终端再验。用户级 PATH 的优先级在系统级之后、但同一个变量内部是有序的,所以显式提到用户级最前面,就能压过系统级里那些排在后面的条目。
5.2 管理员终端能用,普通终端找不到
现象:以管理员身份开的终端里cmake正常,普通双击打开的 cmd 里提示"不是内部或外部命令"。
原因:MSI 安装时选了"for all users",写的是机器级 PATH;或者反过来,装的时候用了管理员身份但选的是当前用户,而后续测试用的是另一个账户。两种情况都会造成"有的终端找得到、有的找不到"。
解决:分别检查两个作用域的 PATH,别只看其中一个。
# 机器级和用户级分别打印 [Environment]::GetEnvironmentVariable('Path','Machine') -split ';' | Select-String cmake [Environment]::GetEnvironmentVariable('Path','User') -split ';' | Select-String cmake两处都没有就补上,只有一处有就说明权限模型不一致,统一到一处再验。改完必须重开终端,refreshenv这类工具不一定可靠,重开最稳。
5.3 生成器没指定架构,编出来是 32 位
现象:VS 生成器配置成功,构建也成功,但产出的 exe 在某些机器上跑不起来,或者链接第三方库时报 "模块计算机类型 x64 与目标计算机类型 x86 冲突"。
原因:Visual Studio 17 2022生成器的默认目标架构是 Win32(x86),不加-A x64就是编 32 位。而绝大多数第三方 C++ 库的 Windows 预编译包都是 x64。
解决:所有 VS 生成器的调用都显式带上架构参数,同时清掉已经生成的错误缓存。
# 删掉旧的构建目录,缓存里的架构信息不会自己更新 rmdir /s /q build cmake -S . -B build -G "Visual Studio 17 2022" -A x64已经生成的CMakeCache.txt里存着CMAKE_GENERATOR_PLATFORM,改命令行参数不会覆盖它,只会报错或者被忽略,所以必须删目录重来。
5.4 换了编译器,缓存还在指旧路径
现象:之前用 MinGW 配过,现在改用 MSVC,cmake -S . -B build报 "The C compiler identification is unknown",或者提示找不到gcc.exe。
原因:CMakeCache.txt里记着上一次的CMAKE_C_COMPILER和CMAKE_CXX_COMPILER绝对路径。CMake 一旦发现缓存里已经有编译器记录,就不会重新探测,直接用旧的。
解决:换工具链就等于换构建目录,别想着在原目录上修补。
# 干净重建,3.24 之后的版本支持 --fresh cmake --preset ninja-release --fresh # 老版本 CMake 只能手动删 rmdir /s /q build--fresh会删掉CMakeCache.txt和CMakeFiles/但保留构建目录本身,比整个删掉再建稍微快一点。我给所有构建目录都加了进.gitignore,就是为了随时能无脑删。
5.5 老工程升级后find_package(Boost)直接失败
现象:把工程的cmake_minimum_required从3.20提到3.30,配置阶段报找不到 Boost,但 Boost 明明装在原来的位置。
原因:CMP0167策略。3.30 起 CMake 自带的FindBoost模块被移除,find_package(Boost)改为走 config 模式,要求 Boost 安装目录里有BoostConfig.cmake。用旧方式编译安装的 Boost 往往没有这个文件。
解决:两个方向,选一个。
# 方案一:不动最低版本,继续用旧策略(工程本身的写法不用改) cmake_minimum_required(VERSION 3.20) # 方案二:保留 3.30,但显式指定 Boost 的查找路径 set(BOOST_ROOT "C:/libs/boost-1.86.0") find_package(Boost 1.86 REQUIRED CONFIG)方案一最快,代价是拿不到新策略。方案二更彻底,前提是你得有一个带BoostConfig.cmake的 Boost 安装。实际操作里我会先看工程到底用没用 Boost 的高级特性,没用的话直接换成一个最小依赖,比在这上面耗着划算。
注意:这五条里前四条都跟"缓存"有关。CMake 的缓存机制很省事,但也很容易变成黑匣子——配置出问题,第一反应应该是看
CMakeCache.txt,而不是改CMakeLists.txt。
6. 验证跑通:用 capabilities 和 --fresh 做一次干净自检
装完东西我最怕的不是装不上,是"看起来装上了"。所以每次装完 CMake,我都会跑一遍固定动作,一分钟内确认三件事:版本对、生成器全、工程能从头配到尾。
第一步,版本和路径必须是同一个。
cmake --version where cmake两行输出里的版本号和路径要对得上。如果where出了两行,说明 5.1 那个坑还在,先回去处理。
第二步,看 CMake 自己报告的能力清单:
cmake -E capabilities这个命令输出一段 JSON,里面有几个字段值得扫一眼:
| 字段 | 看什么 |
|---|---|
version | 应该是3.30.3,确认实际加载的版本 |
generators | 里面应该有你打算用的生成器,比如Visual Studio 17 2022、Ninja |
fileApi | 有值说明文件 API 可用,编辑器插件靠它做补全 |
如果generators里没有你想要的生成器,问题不在 CMake,在工具链——比如没有ninja.exe的时候,Ninja 生成器可能就不在列表里。这一步等于把"CMake 装好了没"和"编译环境配好了没"两个问题拆开了。
第三步,拿 4.2 那个最小工程从头配一遍,并且刻意用--fresh排除缓存干扰:
# --fresh 会丢弃已有缓存,模拟一次全新的配置 cmake -S . -B build -G "Visual Studio 17 2022" -A x64 --fresh # 构建并运行 cmake --build build --config Release .\build\Release\demo.exe能出结果,说明 CMake 3.30.3、生成器、编译器这三者串起来了。要再加一层保险,给工程补一个enable_testing()和add_test(),然后跑ctest --test-dir build -C Release,能过就基本可以放心把这条链交给团队其他人复现了。
从那以后我每次装完 CMake,都会强制走一遍cmake -E capabilities加一次--fresh配置,不管这台机器是新的还是重装的。血泪经验是:省下这一分钟,后面可能要在"为什么我这里能编你那里不能编"上耗掉一整个下午。希望帮到你。
本文还有配套的精品资源,点击获取