必须用 -s 和 -b 分离源码与构建目录,因这是cmake官方推荐的out-of-source构建模式,可避免污染源码树、支持多配置并行、确保git干净及ide稳定;旧式cmake .会混入cmakecache.txt等文件,引发误提交、协作冲突与构建错误。

直接用 cmake -B 配置 + cmake --build 构建,是当前最干净、最可复现的流程;旧式 cmake . 或 cmake .. 容易污染源码目录、难以并行管理多配置。
为什么必须用 -B 和 -S 分开指定目录
源码目录(-S)和构建目录(-B)物理分离,是 CMake 官方推荐的 “out-of-source” 模式。不这么做,CMakeCache.txt、CMakeFiles/ 等中间文件会混进源码树,git 误提交、IDE 扫描卡顿、多人协作冲突都是常见后果。
常见错误现象:
- 执行
cmake .后发现源码目录里多了几十个CMake*文件和文件夹 - 切换
Debug/Release构建时反复rm -rf *,不敢保留缓存 - VS Code 的 CMake Tools 插件报 “cache not found”,实际是因为它默认依赖
-B行为
正确做法:
-
cmake -B build -S .:最简形式,生成到当前目录下的build/ -
cmake -B build-release -S . -DCMAKE_BUILD_TYPE=Release:专用于 Release 构建 -
cmake -B build-debug -S . -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON:带编译数据库,供 clangd 或 ccls 使用
cmake --build 为什么不能用 make 或 ninja 直接调用
cmake --build 是统一入口,它会自动读取构建目录里的生成器元信息(比如 build/CMakeCache.txt 中的 CMAKE_GENERATOR:INTERNAL=Ninja),再调用对应底层工具。硬写 ninja -C build 或 make -C build 会绕过 CMake 的构建状态检查,导致:
- 修改了
CMakeLists.txt后,ninja不触发重新配置,编译结果与配置不一致 - 跨平台脚本在 Windows 上跑
make失败(没装 GNU Make),但cmake --build在 VS 生成器下自动走msbuild - CI 流程中无法统一控制并发数(
--parallel是cmake --build原生支持的)
实操建议:
- 构建全部目标:
cmake --build build - 只构建某个 target:
cmake --build build --target mylib - 并行编译(推荐设为 CPU 核心数):
cmake --build build --parallel 8 - 跳过已构建项,仅构建变更部分:
cmake --build build --verbose(加--verbose可确认是否真跳过)
构建类型(CMAKE_BUILD_TYPE)在哪些生成器下才生效
CMAKE_BUILD_TYPE 只对单配置生成器(如 Unix Makefiles、Ninja)起作用;对多配置生成器(如 Visual Studio 17 2022、Xcode)无效——它们把 Debug/Release 当作 solution 内部的 configuration,靠 IDE 或 --config 指定。
容易踩的坑:
- 在 Windows 上用
cmake -G "Visual Studio 17 2022" -B build -DCMAKE_BUILD_TYPE=Release,结果构建时仍默认走Debug - Linux 下用 Ninja 但忘了设
-DCMAKE_BUILD_TYPE=Release,产出的是未优化的debug二进制
正确写法:
- Ninja / Makefile:
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release - Visual Studio:
cmake -B build -G "Visual Studio 17 2022",然后构建时显式加--config Release:cmake --build build --config Release - Xcode:
cmake -B build -G Xcode,同样需--config Release
配置失败时,CMakeCache.txt 为什么不能直接删了重来
删 CMakeCache.txt 看似清空配置,但 CMake 会从缓存残留的 CMakeFiles/ 中恢复部分旧值(尤其是路径类变量),导致新传入的 -D 参数被忽略,错误持续复现。
真正干净的重配方式只有两个:
- 删整个构建目录:
rm -rf build,再重新cmake -B build ... - 用
cmake -U清缓存(CMake 3.15+):cmake -B build -U "CMAKE_*" -S . -DCMAKE_BUILD_TYPE=Release(-U后跟 glob 模式,慎用*,避免清掉项目自定义变量)
另外注意:cmake -B build -S . 本身具备“增量重配置”能力——只要没删 build/,再次运行它会自动检测 CMakeLists.txt 变更并触发必要重建,无需手动干预。











