add_subdirectory 必须放在 project() 之后,因为 project() 初始化关键变量(如 PROJECT_SOURCE_DIR、CMAKE_BINARY_DIR),add_subdirectory 依赖这些变量定位子目录路径;提前调用会触发“Cannot add subdirectory before project() is called”错误。

为什么 add_subdirectory 必须放在 project() 之后
因为 project() 会初始化 CMake 内部变量(如 PROJECT_SOURCE_DIR、CMAKE_BINARY_DIR),而 add_subdirectory 依赖这些变量定位子目录路径。如果提前调用,CMake 会报错:Cannot add subdirectory before project() is called。
常见错误现象:执行 cmake .. 时直接失败,提示 “Parse error in command add_subdirectory” 或类似未定义行为。
- 即使子目录存在且有
CMakeLists.txt,前置调用也无效 -
cmake_minimum_required可以在最前,但project()是所有项目级指令的分水岭 - CLion 自动创建的模板里若出现该错误,通常是因为手动调整了顺序
target_include_directories 和 include_directories 到底该用哪个
target_include_directories 是现代写法,作用范围精确到目标(如可执行文件或库);include_directories 是全局作用域,影响后续所有 add_executable 或 add_library,容易引发头文件污染或路径冲突。
使用场景差异:
- 当你只希望
mylib能访问src/include,而测试程序test_main不需要——必须用target_include_directories(mylib PUBLIC ${CMAKE_SOURCE_DIR}/src/include) - 若误用
include_directories,可能导致test_main编译时意外包含不该暴露的内部头文件 - 在 CMake 3.10+ 中,
include_directories已被标记为 legacy,官方文档明确推荐前者
为什么 file(GLOB) 不推荐用于源文件收集
因为 file(GLOB) 在配置阶段一次性展开路径,不会自动感知新增/删除的 .cpp 文件;修改源码后不重新运行 cmake,make 就不会重新编译新文件,极易导致构建结果陈旧、行为不一致。
实操建议:
- 显式列出源文件更可靠:
set(SRC_LIST src/main.cpp src/lib/module1.cpp src/lib/module2.cpp) - 若坚持用
GLOB,至少加注释提醒团队:“增删源文件后需手动 re-run cmake” -
file(GLOB_RECURSE)更危险——它会递归匹配,可能意外引入第三方或临时文件 - CMake 官方文档明确指出:“We do not recommend using GLOB to collect a list of source files from your source tree.”
交叉编译时 toolchain.cmake 里最关键的三行
工具链文件不是“选配”,而是让 CMake 正确识别交叉编译器、sysroot 和目标架构的唯一可靠方式。漏掉任意一行都可能导致链接失败或符号找不到。
最小可行 toolchain.cmake 必须包含:
-
set(CMAKE_SYSTEM_NAME Linux)—— 告诉 CMake 目标系统类型(不能写成GNU/Linux或留空) -
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)—— 显式指定完整路径或可执行名,CMake 不会自动推导交叉前缀 -
set(CMAKE_FIND_ROOT_PATH /opt/sysroot-arm)—— 指向目标平台的 rootfs,否则find_package会去宿主机找库
容易踩的坑:把 CMAKE_SYSTEM_PROCESSOR 当成必需项——其实多数情况下它只是辅助信息,不设也不影响基础构建;真正关键的是前三项是否准确指向目标环境。


















