现代cmake推荐使用cmake -b构建目录 -s源码目录配置,再用cmake --build构建目录编译,明确分离源码与构建路径,避免路径错误和缓存污染,提升跨平台可靠性。

直接用 cmake -B 配置、cmake --build 编译,是当前最干净可靠的方式;旧式 cmake . 或 cmake .. 容易因工作目录混乱导致路径错误或缓存污染。
cmake -B 构建目录必须显式指定
不推荐在源码目录下直接运行 cmake .,也不建议进 build 目录再执行 cmake ..。现代 CMake 要求明确分离源码与构建路径:
-
cmake -B build会自动创建build/目录(若不存在),并在其中生成CMakeCache.txt和构建系统文件 -
-S必须显式指定源码位置,哪怕就在当前目录:例如cmake -B build -S . - 省略
-S时,CMake 可能从当前目录向上查找CMakeLists.txt,行为不可控;尤其在嵌套项目中极易误读顶层CMakeLists.txt - 路径全部以
-S指向的目录为基准,add_executable(myapp src/main.cpp)中的src/main.cpp就是相对于该目录的路径
cmake --build 要指向构建目录,不能加参数乱传
cmake --build 的第一个参数必须是构建目录路径,不是源码目录,也不是任意子目录:
- 正确:
cmake --build build(假设你用cmake -B build配置的) - 错误:
cmake --build .—— 如果当前是源码根目录,会报No CMakeCache.txt或找不到构建系统 - 错误:
cmake --build build --target install——--target是 Ninja/Make 的概念,但 CMake 3.15+ 已统一用--target支持所有生成器;不过 Windows 上 VS 生成器不认这个参数,得用/target:INSTALL(MSVC 场景下要特别注意) - 并行编译写法统一:
cmake --build build --parallel(等价于-j或/m),无需区分平台
常见错误:CMakeLists.txt 找不到或命令报错
现象包括 Unknown CMake command "target_compile_features"、Cannot find source file、Could not find a package configuration file,根本原因往往不是语法错:
- CMake 版本太低:检查
cmake --version,低于 3.15 时很多现代特性(如find_package(... CONFIG)、target_link_libraries(... PRIVATE))直接失效;macOS Homebrew 默认装的是 3.10,需手动brew upgrade cmake -
cmake_minimum_required(VERSION ...)必须写,且版本不能低于实际使用的最低能力;写成3.10却用了3.21的MSVC_RUNTIME_LIBRARY,CMake 不会报错但会静默忽略 - 中文路径或空格路径会导致
find_package失败或生成器崩溃,Windows 尤其敏感;一律改用英文纯 ASCII 路径 -
add_executable漏掉源文件名,或用了file(GLOB ...)却没加set(CMAKE_SUPPRESS_REGENERATION ON),会导致新增源文件不触发重配置
调试配置失败:看 CMakeCache.txt 和 -Wdev
配置失败时,别只盯着终端最后一行红字,关键信息常藏在中间或缓存里:
-
build/CMakeCache.txt是真实生效的配置快照,搜索CMAKE_BUILD_TYPE、CMAKE_INSTALL_PREFIX等变量,确认是否被你传的-D覆盖成功 - CMake 会输出两类警告:“此警告适用于项目开发人员”是给库作者的,普通用户基本可忽略;加
-Wno-dev可屏蔽,例如cmake -B build -S . -Wno-dev - 想看完整检测逻辑,加
--debug-output(不是--debug);但日志极长,建议先用--trace-source=CMakeLists.txt定点跟踪某文件执行流 - 如果
find_package(Threads)总失败,试试加-DCMAKE_THREAD_LIBS_INIT="-lpthread"手动兜底,Linux 下常见
最容易被忽略的是:每次换生成器(比如从 Unix Makefiles 切到 Ninja)或换工具链(比如 Clang vs MSVC),都必须删掉整个构建目录重建;缓存不会自动适配,硬留着只会让错误更隐蔽。











