
简介面向 Windows 平台 C 开发者与构建工程师的 CMake 3.25 离线安装包适合需要在 Visual Studio、MinGW 等编译器环境下配置、生成和迁移工程的技术人员使用。压缩包内共 7090 个文件约 36.31MB以 txt、html、rst 文档和 cmake 模块脚本为主体辅以少量 exe 安装程序、json 配置、png 图示及 c、cxx、cpp 示例源码既包含可执行工具也保留较完整的命令、属性、变量与策略说明文档。已有 1337 人学习下载说明其在版本升级和本地环境搭建场景中具有一定参考价值。对于需要查阅 cmake、ctest、cpack、cmake-gui 等命令手册或希望理解 CMakeLists 编写、缓存管理、编译器适配与构建排错的读者可通过包内文档快速定位官方说明安装后亦可在命令行或图形界面中完成源码目录、构建目录和编译器选项设置减少从零摸索成本。1. 为什么我还在用 CMake 3.25 的 Windows 包一次装错版本的连环翻车上周有个读者把工程丢过来说 cmake c 这套流程在他机器上死活配不起来日志刷了一屏关于cmake_minimum_required版本过低的弃用告警而他本地cmake --version打出来是 3.31。这类问题九成不是代码写错是机器上并存着三四个 CMake 实例PATH 里第一个不是你以为的那个。CMake 3.25 的 Windows 免安装包就是为这种场景准备的解压即用、不写注册表、不抢系统目录一个工程一个版本切换成本接近零。它适合要同时维护几套老工程、又不想每台机器都跑安装程序的人也适合想把构建链固定在某个版本、避免换台机器就编译不过的团队。下面按我实际拆包、搭环境的顺序讲。2. 拆开这个压缩包bin、share、doc 三块分别管什么拿到的是一个.zip不是.msi。这决定了后面所有操作都围绕「解压到哪、怎么让它被找到」展开而不是「下一步、下一步、完成」。免安装包的本质是把一整套 CMake 运行时和模块库塞进一个目录树任何路径下都能跑删掉目录就等于卸载干净——这一点在需要来回切版本的机器上价值很大。2.1 目录树里真正会被用到的三个位置解压之后先别急着配 PATH把目录看一遍。顶层一般有bin、doc、man、share四个目录对日常构建来说前三个之外的东西才是重点。路径内容什么时候会用到bin/cmake.exe主程序配置与命令行入口所有cmake -S/-B/--build/--install操作bin/ctest.exe测试驱动跑add_test注册的用例bin/cpack.exe打包驱动生成安装包或归档share/cmake-3.25/ModulesFindXXX.cmake、平台与编译器探测脚本find_package找不到包时先来这里确认有没有对应模块share/cmake-3.25/Templates新建工程的模板文件基本不用手动碰doc/cmake-3.25离线手册断网环境查命令签名Modules目录是最容易被低估的一块。很多「find_package报 Could not find」的问题根因是模块名拼错或者这个版本压根没带对应模块而不是库没装。我习惯在排查前先Get-ChildItem share\cmake-3.25\Modules\Find*.cmake | Select-String 关键词过一遍确认模块存在再往下查路径。解压本身有两个硬约束路径不要带中文不要带空格。不是说一定崩而是带空格时某些老项目的自定义命令、外部脚本拼命令行会少引号报错信息还特别绕排查成本远高于换个目录。# 解压到短路径避免后续脚本拼命令行时被空格截断 Expand-Archive -Path .\cmake-3.25.x-windows-x86_64.zip -DestinationPath D:\tools\ # 确认可执行文件确实落在 bin 下而不是多套了一层目录 Get-ChildItem D:\tools\cmake-3.25.x-windows-x86_64\bin -Filter *.exeExpand-Archive在 Windows PowerShell 5.1 上对大压缩包偏慢几百 MB 的包建议直接用资源管理器右键解压行为一致但快不少。解压完要确认的是bin\cmake.exe的直接父目录是不是bin因为有些第三方重新打包的版本会多嵌一层同名目录导致后面配 PATH 全错。2.2 版本锁定的理由3.25 这条线的能力边界版本不是越新越好这是踩过才知道的。3.25 属于一个「够用且稳定」的中间点它已经带上了CMakePresets.json的 schema 6、block()/endblock()命令、add_subdirectory(... SYSTEM)、SYSTEM目标属性以及 workflow presets同时又没有后续版本里那些会改变默认行为的动作。对一套需要长期维护的工程来说这种「能力齐、行为稳」的组合比追新更有价值。具体到日常会用到的几个点Presets schema 6支持configurePresets、buildPresets、testPresets、packagePresets、workflowPresets五类团队里可以把生成器、架构、缓存变量、构建类型全部写进文件新人拉下来直接cmake --preset就行不用口头传参数。block()/endblock()给变量加作用域。以前写宏或者一段临时改CMAKE_CXX_FLAGS的逻辑改完得手动还原忘了就污染后续所有目标现在用block()包起来出块自动恢复。add_subdirectory(... SYSTEM)把第三方子目录当系统头处理编译器不再对它里面的头文件报警告。接老库时这个能省掉一大堆「第三方头文件警告淹没自己的警告」的噪音。最低版本策略3.25 对cmake_minimum_required写太低的工程会给弃用告警。这类告警本身无害但如果工程开了-Werror或者把告警当错误处理就会直接失败。老工程迁过来第一件事就是把cmake_minimum_required抬到 3.25 或至少 3.10 以上。反过来说如果你的工程依赖某个只有更高版本才有的命令硬钉 3.25 会得到一句Unknown CMake command这个报错很直白不会误导。真正麻烦的是相反的情况用了新版本才有的默认行为降回 3.25 后不报错但结果不对所以版本要么全组统一要么在预设里写死别靠个人机器上的默认值。2.3 让cmake --version只有一个答案PATH 冲突是 Windows 上最高频的翻车点没有之一。典型症状是命令行里cmake --version显示 3.25但某个 IDE 内部构建时报的命令不认识或者反过来。原因是不同进程继承的 PATH 不一样加上安装版会往系统目录和注册表写东西优先级很难靠肉眼判断。第一步永远是查全部候选而不是查第一个# 列出 PATH 中所有名为 cmake 的可执行文件顺序即优先级 where.exe cmake # 只在当前会话里前置先验证再决定要不要固化 $env:Path D:\tools\cmake-3.25.x-windows-x86_64\bin; $env:Path cmake --versionwhere.exe会按 PATH 顺序把所有匹配项都列出来看到两条以上就说明有冲突得先清理。$env:Path用前置而不是追加是为了让新版本压过旧版本只改当前会话的好处是关掉窗口就恢复试错零成本。验证通过之后再写进用户级环境变量别一上来就动系统级——系统级改坏了影响所有账号而且很多安装程序会往里插自己的路径你的修改过段时间就被挤到后面去了。更稳的做法是干脆不依赖 PATH。工程根目录放一份预设文件里面用绝对路径调用或者在 CI 脚本里用完整路径D:\tools\...\bin\cmake.exe。IDE 里对应的是cmake.cmakePath这类配置项指到具体文件而不是让它去 PATH 里找。多版本共存的机器上我一般会保留 PATH 里一个「默认版本」其余全部通过绝对路径或预设调用这样出问题时至少有一个已知的参照点。3. 从空目录到可执行文件一份最小 CMake 工程的四个动作先跑通一个最小工程再往上加东西。跳过这一步直接上真实项目一旦报错就分不清是环境问题还是工程配置问题。这一章的四步——写CMakeLists.txt、配置、构建、安装——每一步都有独立的失败模式拆开验证最省时间。3.1 三行起步再逐层加料最小可用的CMakeLists.txt只要三行。第一行声明最低版本第二行声明工程名和支持的语言第三行声明目标。# 最低版本必须写且不要低于 3.10写 3.25 表示这份工程按 3.25 的行为解析 cmake_minimum_required(VERSION 3.25) # LANGUAGES CXX 明确只启用 C避免在没装 C 编译器的环境里误报 project(hello_cmake LANGUAGES CXX) # 可执行目标名 hello源文件与 CMakeLists.txt 同目录 add_executable(hello main.cpp) # 语言标准用 target_compile_features 表达比全局 CMAKE_CXX_STANDARD 更精准 target_compile_features(hello PRIVATE cxx_std_17)这四行里最值得说的是最后一行。全局设CMAKE_CXX_STANDARD是常见写法但它会影响所有目标包括第三方子目录用target_compile_features挂在具体目标上作用域清晰而且当编译器不支持时会在配置阶段直接报错而不是等到编译阶段才抛一堆语法错误。对应的main.cpp写个最小可运行的#include iostream int main() { std::cout hello from cmake 3.25\n; return 0; }接着往上加库和包含目录。把业务代码拆成一个静态库、可执行文件只留main这是后续接依赖、写测试的基础结构add_library(greeter STATIC src/greeter.cpp) # PUBLIC 表示使用者自动继承这个包含目录PRIVATE 则不外传 target_include_directories(greeter PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) add_executable(hello main.cpp) target_link_libraries(hello PRIVATE greeter)PUBLIC和PRIVATE的区别是这套机制的核心头文件目录对使用者可见就用PUBLIC只在库内部用就PRIVATE。写反了不会立刻报错但依赖传播链会出错——下游目标编译时找不到头文件或者反过来把内部目录暴露出去污染别人的包含路径。这种错误在工程规模变大后极难定位一开始就写对最省事。3.2 生成器怎么选VS 2022、Ninja 和它们的适用面生成器决定了 CMake 最终产出什么。Windows 上主要是两个方向Visual Studio 生成器产出.sln/.vcxprojNinja 生成器产出一个build.ninja。生成器典型命令参数优点代价Visual Studio 17 2022-G Visual Studio 17 2022 -A x64自动定位 MSVC不用配环境能直接开 IDE 调试配置慢产物目录结构深Ninja-G Ninja -DCMAKE_BUILD_TYPERelease增量构建快命令行干净需要cl.exe已在环境里否则找不到编译器NMake Makefiles-G NMake Makefiles兼容老环境并行支持弱基本不推荐选择依据不是「哪个先进」而是「谁来构建」。如果日常是在 VS 里按 F5 调试就用 VS 生成器省掉配编译器的所有麻烦如果是脚本化、CI、或者每天要跑几十次构建Ninja 的增量速度优势很明显。我通常两套预设都留着调试用 VS跑验证用 Ninja产物目录分开互不干扰。Ninja 的第一个坑几乎人人都会遇到直接在普通 PowerShell 里cmake -G Ninja配置阶段报找不到cl。原因是 Ninja 不做编译器发现它要求编译器已经在环境中。解决办法是在 VS 的开发者命令行里执行或者先把环境变量拉进来# 加载 MSVC 环境变量路径按实际 VS 安装位置调整 C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\Launch-VsDevShell.ps1 -Arch amd64 # 验证编译器可见 cl cmake -S . -B build/ninja -G Ninja -DCMAKE_BUILD_TYPEReleaseLaunch-VsDevShell.ps1只影响当前 PowerShell 会话不会污染系统环境比手动拼INCLUDE/LIB可靠得多。执行完再cl一下能打出版本号说明环境就绪打不出来就是路径猜错了去 VS 安装目录下找VsDevCmd.bat那一套。3.3 配置、构建、安装三条命令各自的参数从 3.13 起支持-S/-B源码目录和构建目录彻底分离。这个习惯要养成构建目录是可以整个删掉重建的源码目录永远不产生中间文件。# 配置生成器、架构、缓存变量都在这一步定下来 cmake -S . -B build/vs2022 -G Visual Studio 17 2022 -A x64 # 构建多配置生成器必须显式给 --config不给就是 Debug cmake --build build/vs2022 --config Release --parallel # 安装--prefix 决定落地位置同样要跟 --config cmake --install build/vs2022 --config Release --prefix D:/dist/hello三条命令里最容易出问题的是--config。VS 这类多配置生成器在配置阶段不决定构建类型Debug/Release是在构建时选的而 Ninja 这类单配置生成器相反类型在配置阶段用CMAKE_BUILD_TYPE定死。混着用就会产生「我明明配了 Release产物却是 Debug」的困惑——去看build/vs2022/Release/和build/vs2022/Debug/两个目录大概率是构建时没带--config。--parallel不带数字时用 CPU 核数带数字则限流。老机器上盲目并行会把内存打满导致cl.exe被杀报错是fatal error C1060: compiler is out of heap space看到这个就把并行数降到 4 或 8。安装这一步需要工程里先写规则否则--install什么也不做# RUNTIME 对应 .exe 和 .dllLIBRARY 对应 .lib/.soARCHIVE 对应静态库 install(TARGETS hello RUNTIME DESTINATION bin) install(TARGETS greeter ARCHIVE DESTINATION lib) install(DIRECTORY include/ DESTINATION include)DESTINATION是相对--prefix的路径写绝对路径会被拼到前缀后面结果很怪。这三条规则写完--install才会真的把 exe、lib、头文件按目录结构铺到目标位置。工程里如果还链接了动态库别忘了把对应 DLL 也装进去否则交付到干净机器上运行时报的不是编译错误是「找不到 xxx.dll」排查方向完全不同。3.4 用预设文件把参数固化下来命令行参数一多靠记忆和复制粘贴必然出错。CMakePresets.json把生成器、架构、缓存变量、构建类型写成文件进仓库所有人共用一套。{ version: 6, configurePresets: [ { name: msvc-release, displayName: MSVC x64 Release, generator: Visual Studio 17 2022, architecture: x64, binaryDir: ${sourceDir}/build/msvc-release, cacheVariables: { CMAKE_CXX_STANDARD: 17 } } ], buildPresets: [ { name: msvc-release, configurePreset: msvc-release, configuration: Release, jobs: 8 } ] }version: 6对应 3.25 这一代的 schema往下兼容做得不错但不要跨大版本混用——把 3.25 生成的预设文件丢给 3.20 的 cmake 会直接拒绝解析报 schema 版本不支持。binaryDir里的${sourceDir}是内置变量展开成工程根目录jobs控制并行度团队里机器配置差异大时把它写死比让每个人自己加--parallel更可控。用起来就两条命令cmake --preset msvc-release cmake --build --preset msvc-release预设的另一个好处是它自带版本校验。文件里可以声明cmakeMinimumRequired版本不够时直接报错而不是等到某个命令不认识才失败。这一点在多版本并存的机器上特别有用等于把「必须用 3.25」这条约束写进了工程。4. 第三方依赖怎么接find_package、FetchContent 与 vcpkg 的分工依赖管理是 CMake 工程最容易失控的部分。三种主流方式各有明确的适用面系统里已经装好的库用find_package需要固定版本的源码依赖用FetchContent需要成套管理二进制依赖用包管理器加工具链文件。搞清楚边界比背命令重要。4.1 find_package 的两种模式与搜索路径find_package有 Module 和 Config 两种模式行为完全不同。Module 模式找的是share/cmake-3.25/Modules下的FindXXX.cmake由 CMake 自己维护覆盖一批常见库Config 模式找的是库自己安装时带出来的XXXConfig.cmake位置由库的安装前缀决定。# CONFIG 强制走 Config 模式避免找到同名的旧 Find 模块 find_package(SomeLib CONFIG REQUIRED) # 目标名一般是 包名::包名用这个而不是老的 ${SomeLib_LIBRARIES} target_link_libraries(hello PRIVATE SomeLib::SomeLib)显式写CONFIG是个好习惯。不写时 CMake 先试 Module 再试 Config找到哪个用哪个如果机器上恰好存在一个过时的FindSomeLib.cmake它可能指向一个完全不同的版本而报错信息不会告诉你是走错了模式。找不到包时先看报错里的搜索路径列表那是它实际找过的目录。要额外加路径用CMAKE_PREFIX_PATHcmake -S . -B build/vs2022 -G Visual Studio 17 2022 -A x64 -DCMAKE_PREFIX_PATHD:/libs/SomeLib;D:/libs/AnotherLibCMAKE_PREFIX_PATH是分号分隔的列表不是逗号也不是多次传参。每个条目会被展开成prefix/lib/cmake/name、prefix/share/name等若干候选位置。路径里有空格一定要加引号PowerShell 里用反引号续行时更要注意续行符后面不能有多余空格。4.2 FetchContent版本锁定与离线兜底FetchContent在配置阶段把外部源码拉下来并add_subdirectory进去适合还没进包管理、或者需要打补丁的依赖。include(FetchContent) FetchContent_Declare( mylib GIT_REPOSITORY https://example.invalid/mylib.git GIT_TAG v1.2.0 # 用 tag 或 commit别用分支名 GIT_SHALLOW TRUE # 只要最新一次提交克隆更快 SYSTEM # 3.25 支持把它的头文件当系统头抑制警告 ) # 3.24 起支持本机已装同版本时直接复用不再克隆 FetchContent_Declare( mylib FIND_PACKAGE_ARGS 1.2 CONFIG ) FetchContent_MakeAvailable(mylib)GIT_TAG写分支名是反复翻车的根源同一份 CMake 配置今天拉到的和下周拉到的可能不是同一份代码构建结果不可复现出问题也没法回滚到具体提交。用 tag 或 commit hash写进仓库这就是最便宜的后悔药。FIND_PACKAGE_ARGS是 3.24 之后的能力3.25 完整支持。它的逻辑是「先找本机已安装的找不到再拉源码」对 CI 和本地开发都友好——CI 上从缓存拿本地首次构建才克隆。SYSTEM参数在 3.25 生效把拉下来的目标标记为系统目标编译器的警告不会再从第三方代码里冒出来淹没自己的告警。离线环境要准备兜底FETCHCONTENT_SOURCE_DIR_NAME可以指定一个已经存在的源码目录跳过下载环节。# 大写包名横线换成下划线 cmake -S . -B build/vs2022 -G Visual Studio 17 2022 -A x64 -DFETCHCONTENT_SOURCE_DIR_MYLIBD:/vendor/mylib-src内网构建机没有外网时把这个变量写进预设的cacheVariables配合FETCHCONTENT_FULLY_DISCONNECTEDON配置阶段完全不尝试联网失败信息也从「网络超时」变成明确的「源码目录不存在」排查方向清晰得多。4.3 vcpkg 工具链文件的挂载方式需要管理的依赖一多逐个find_package加路径就不现实了这时候上包管理器。vcpkg 通过工具链文件接管编译器探测和依赖解析挂载方式是配置时传CMAKE_TOOLCHAIN_FILE。cmake -S . -B build/vcpkg -G Visual Studio 17 2022 -A x64 -DCMAKE_TOOLCHAIN_FILED:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLETx64-windows工具链文件必须在首次配置时传入。已经生成过CMakeCache.txt的构建目录再传这个参数会被忽略表现是「明明传了却完全没生效」——这是最常见的一个坑解决方法是删掉构建目录重新配置或者用--fresh。VCPKG_TARGET_TRIPLET决定链接静态库还是动态库x64-windows是动态x64-windows-static是静态。选错会得到链接期的一堆符号冲突而且报错信息指向的是系统库跟 vcpkg 毫无关系非常难联想。工程里如果有交付到干净机器的需求静态三元组能省掉打包 DLL 的麻烦代价是体积变大。较新的 vcpkg 工具链会读VCPKG_ROOT环境变量来自动定位自身所以另一种更省事的写法是只设环境变量不传参数$env:VCPKG_ROOT D:/tools/vcpkg cmake -S . -B build/vcpkg -G Visual Studio 17 2022 -A x64 -DCMAKE_TOOLCHAIN_FILE$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake环境变量方式适合个人机器团队协作还是写进预设更可靠。另外注意工具链文件和CMAKE_PREFIX_PATH可以共存vcpkg 会把自己的安装目录追加进搜索路径两者不冲突。5. 踩坑实录Windows 上这套包的五个高发故障下面五条都是我在真实工程里反复遇到的按「现象 → 原因 → 解决」记录。每条都附了判断依据照着对号入座就行不用从头试。5.1 配置阶段的三个坑坑一cmake --version显示的不是 3.25。现象是命令行里查到的版本对但构建时报某个命令不存在或者预设文件解析失败提示 schema 不支持。根因是进程继承的 PATH 与当前终端不一致IDE、CI agent、计划任务各自有一份环境安装版还会往系统目录写cmake.exe优先级排在前面。解决分三步where.exe cmake列出全部候选确认有几份、分别属于哪个目录把要用的那份前置到$env:Path最前面或者干脆用绝对路径调用。清完之后如果还不对删掉构建目录重新配置——CMakeCache.txt里缓存了CMAKE_COMMAND的绝对路径旧值会一直生效。坑二VS 生成器报找不到 Visual Studio 实例。现象是-G Visual Studio 17 2022配置阶段直接失败提示 could not find any instance。原因通常不是没装 VS而是没勾「使用 C 的桌面开发」工作负载只有 IDE 没有编译器另一种是装了更新版本的 VS生成器名字和实际版本对不上。先在 VS Installer 里确认工作负载再用vswhere查实际装了哪些实例和版本号按查到的版本改生成器名。实在不想动 VS就直接切 Ninja 加开发者命令行绕开实例发现这一步。坑三Ninja 下找不到cl.exe。现象是配置阶段报No CMAKE_CXX_COMPILER could be found。原因是 Ninja 不做编译器自动发现它只认环境里已有的编译器而普通 PowerShell 里没有 MSVC 的环境变量。解决是用Launch-VsDevShell.ps1或VsDevCmd.bat先把环境拉起来再执行配置。另一种写法是显式指定编译器全路径-DCMAKE_CXX_COMPILER.../cl.exe但不推荐——只指定了编译器INCLUDE和LIB还是缺的编译到一半才失败。5.2 构建与产出阶段的两个坑坑四改了CMakeLists.txt构建结果没变化。现象是新增了源文件或者改了编译选项重新构建却像什么都没发生。原因有两类一是多配置生成器下构建时没带--config实际构建的是另一个类型二是缓存里存着旧的变量值CMakeCache.txt的优先级高于你这次传的参数。先看构建日志里实际用的配置和编译命令确认类型对不对再确认缓存变量cmake -LA -N build/xxx能把缓存里所有变量列出来。3.25 上最省事的做法是cmake --preset xxx --fresh--fresh会清掉缓存重建但保留构建目录比整个删掉再配置快。要提醒的是--fresh之后所有手动传过的缓存变量都没了必须靠预设重新给全这正是把参数写进预设的价值。坑五安装完程序起不来报缺 DLL 或找不到头文件。现象是构建全绿--install也成功到了目标机器上双击就报错。原因是多配置生成器下--install默认拿 Debug 产物或者安装规则只写了 exe 没写依赖的 DLL再或者头文件目录没写进install(DIRECTORY ...)。先看--prefix目录里到底有什么缺什么补什么规则确认--install后面跟了--config Release动态链接的第三方库要用install(IMPORTED_RUNTIME_ARTIFACTS ...)或者包管理器的拷贝机制一起带上。交付前我一般会在干净环境里跑一遍宁可这里暴露也别让下游先发现。6. 把构建变成可验证的流水线workflow presets 与 CTest单机跑通只是及格线能一条命令从零到验证通过才算把工程交出去了。3.25 正好有 workflow presets可以把配置、构建、测试、打包串成一次调用配合 CTest 和 file API脚本层面能拿到结构化的构建结果不用再去 grep 日志。6.1 workflow presets 串起四个阶段在同一个CMakePresets.json里补上测试和 workflow 两个段落。workflowPresets的每一步引用的是对应类型的预设名顺序执行任一步失败就中断。{ version: 6, testPresets: [ { name: msvc-release, configurePreset: msvc-release, configuration: Release, output: { outputOnFailure: true } } ], workflowPresets: [ { name: ci, steps: [ { type: configure, name: msvc-release }, { type: build, name: msvc-release }, { type: test, name: msvc-release }, { type: package, name: msvc-release } ] } ] }调用只有一条cmake --workflow --preset cisteps的type只能是 configure、build、test、package 四种name必须指向对应类型下已定义的预设。outputOnFailure让测试失败时才打印输出日志不会淹没在几十个用例的输出里。第 4 步的 package 需要工程里有 CPack 配置没有的话删掉这一步前三步足够覆盖日常验证。这条命令的价值在于「零参数」。CI 脚本里不用维护一长串-D参数本地复现 CI 失败也是同一条命令环境差异被压到最小。我在几个工程里把它设成提交前必跑一次省掉了大量「本地好的、CI 挂的」扯皮。6.2 CTest 与 file API让脚本问出结果测试注册在CMakeLists.txt里# include(CTest) 会自动定义 BUILD_TESTING 选项并调用 enable_testing() include(CTest) if(BUILD_TESTING) add_executable(t_greeter tests/t_greeter.cpp) target_link_libraries(t_greeter PRIVATE greeter) # 用例名带模块前缀失败时一眼定位 add_test(NAME greeter.greet_returns_text COMMAND t_greeter) set_tests_properties(greeter.greet_returns_text PROPERTIES TIMEOUT 30) endif()TIMEOUT值得加Windows 上某些用例卡死时不会自己退出CI 会一直挂着直到整体超时。查用例可以用ctest --test-dir build/msvc-release -C Release --output-on-failure -R greeter-R按正则过滤本地调试单个用例时很好用。需要脚本层面消费构建结果时用 file API。它的机制很朴素在构建目录下放一个查询文件重新配置一次结果以 JSON 落在 reply 目录里。# 查询文件名即查询类型codemodel-v2 能拿到目标、源文件和产物路径 New-Item -ItemType Directory -Force .\build\msvc-release\.cmake\api\v1\query | Out-Null Set-Content .\build\msvc-release\.cmake\api\v1\query\codemodel-v2 cmake --preset msvc-release # index 文件里有指向具体回复文件的引用 Get-ChildItem .\build\msvc-release\.cmake\api\v1\reply | Select-Object -First 5 Name查询文件必须是空文件文件名就是查询类型除了codemodel-v2常用的还有cmakeFiles-v1构建系统文件清单和toolchains-v1编译器与工具链信息。reply 目录里的index-*.json是入口顺着里面的jsonFile字段找具体内容别直接去猜文件名。这套机制的好处是不依赖日志格式日志改了脚本不会崩适合把产物路径喂给后续的签名、打包、部署环节。一个实际习惯新工程接入时我会先跑一遍cmake --workflow --preset ci再用 file API 把 codemodel 拉出来核对目标名和产物路径确认脚本里写死的路径和实际产出对得上。有一次产物目录多了个配置子目录部署脚本一直拷的是空目录查了半天才发现是脚本里的路径写死了。从那以后我每接一个新工程配置、构建、测试、路径核对这四件事都强制走一遍再动手写业务代码。希望帮到你。本文还有配套的精品资源点击获取