最简可用CMakeLists.txt需三步:cmake_minimum_required(VERSION 3.10)、project(MyApp LANGUAGES CXX)、add_executable(myapp main.cpp);头文件用target_include_directories(myapp PRIVATE include)指定路径;链接库须find_package()后显式target_link_libraries();构建务必在独立build目录中执行。
直接用 CMake 编译 C++ 项目,核心不是写“教程”,而是让 CMakeLists.txt 正确描述你的源码结构、依赖和构建目标——写错一行 add_executable() 或漏掉 target_include_directories(),就会报错或链接失败。
CMakeLists.txt
从单个 main.cpp 开始,避免一上来就加子目录、库、测试。CMake 版本声明、项目名、可执行文件定义三步必须齐:
cmake_minimum_required(VERSION 3.10) —— 低于 3.10 的版本不支持 target_compile_features() 等常用功能,3.10 是当前安全下限project(MyApp LANGUAGES CXX) —— 显式声明只用 C++,避免 CMake 自动启用 C 编译器导致奇怪警告add_executable(
myapp main.cpp) —— 文件名必须真实存在,路径是相对于 CMakeLists.txt 所在目录的;不能写成 add_executable(myapp ./src/main.cpp)(除非 CMakeLists.txt 在项目根目录且 src/ 是子目录)target_include_directories()
编译报错 fatal error: xxx.h: No such file or directory,90% 是没告诉 CMake 去哪找头文件。不要用全局 include_directories()(已过时且污染所有 target),改用 target 级别设置:
include/ 目录下:target_include_directories(myapp PRIVATE include)
PRIVATE 表示只影响 myapp 自身编译,不传递给依赖它的其他 target;要用 PUBLIC 只有当你封装的是库且头文件需被使用者包含时include 指的是 CMakeLists.txt 同级或子目录下的 include/;若头文件在 ../common/include,就得写 ../common/include
pthread 或 fmt)必须分两步只写 find_package(fmt REQUIRED) 不够,也不等于自动链接——CMake 只负责找到库位置,链接动作要显式触发:
pthread):target_link_libraries(myapp PRIVATE pthread)
fmt):find_package(fmt REQUIRED) + target_link_libraries(myapp PRIVATE fmt::fmt)(注意 :: 和别名,不是 fmt)libz.a):target_link_libraries(myapp PRIVATE /path/to/libz.a),但更推荐用 add_library(z STATIC IMPORTED) 再链接,便于跨平台build/ 目录隔离永远不在源码目录运行 cmake .。CMake 生成的中间文件(CMakeCache.txt、Makefile、对象文件)会污染源码树,且切换编译器或配置时极易出错:
mkdir build && cd build && cmake .. && make
cmake -DCMAKE_BUILD_TYPE=Release ..(Debug 是默认值,但显式写出来更可控)CMakeLists.txt 后,进 build/ 目录重新运行 cmake .. 即可,不用删整个目录(除非改了 cmake_minimum_required 或变量作用域)真正卡住人的地方,往往不是语法,而是路径是否真实存在、target 名称是否拼错、PRIVATE/PUBLIC 是否用反、或者 find_package() 找到的库实际没安装——这些错误信息藏在 cmake .. 输出里,而不是 make 阶段。