文章目录
刚接触CMake那会儿,我对着满屏幕的红色报错怀疑人生——这玩意儿怎么比C++模板还难搞?!(别笑!)后来才明白,CMakeLists.txt就是个傲娇的甲方爸爸,你写的每个字母它都要检查八百遍!今天咱们就手把手把这个"项目说明书"的写法掰开揉碎讲清楚!
一、你的第一个CMakeLists.txt(真·5分钟速成版)
先来个最简单的版本镇场子:
cmake_minimum_required(VERSION 3.10) # 重要程度五颗星!!!
project(MyAwesomeProject) # 项目名要够骚气
add_executable(main main.cpp) # 核心中的核心(敲黑板)
运行命令:
mkdir build && cd build
cmake ..
make -j4
(看到那个绿色进度条了吗?恭喜你成功召唤了CMake之魂!)
二、CMakeLists.txt的七种武器(必杀技合集)
1. 头文件大作战
target_include_directories(main
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include # 公共头文件
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src # 私有头文件
)
(划重点)用target_
开头的命令才是现代CMake的正确姿势!那些老教程教的include_directories()
早该进博物馆了!
2. 库文件三连击
find_package(OpenCV REQUIRED) # 找系统库
add_library(mylib STATIC src/mylib.cpp) # 自己造轮子
target_link_libraries(main
PRIVATE
OpenCV::OpenCV
mylib
)
遇到Could NOT find OpenCV
?试试设置-D OpenCV_DIR=/your/opencv/path
(血的教训)
3. 编译选项黑科技
target_compile_options(main
PRIVATE
-Wall # 开启所有警告
-O3 # 优化到飞起
$<$<CXX_COMPILER_ID:MSVC>:/W4> # VS专属福利
)
(高级技巧)这个$<...>
叫做生成器表达式,CMake界的瑞士军刀!
三、大型项目生存指南(保命技巧)
1. 模块化开发(拒绝屎山代码!)
project_root/
├── CMakeLists.txt
├── app/
│ └── CMakeLists.txt
└── lib/
└── CMakeLists.txt
主CMakeLists.txt:
add_subdirectory(lib)
add_subdirectory(app)
子目录CMakeLists.txt:
target_link_libraries(app_main PRIVATE lib_core)
(千万注意)变量作用域!子目录的变量父目录看不见!
2. 安装配置(打包带走)
install(TARGETS main
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
install(DIRECTORY include/
DESTINATION include
FILES_MATCHING PATTERN "*.h"
)
生成安装包:
cmake --build . --target install
四、报错急救包(亲测有效)
1. “No CMAKE_CXX_COMPILER could be found”
(灵魂三问):
- 装了编译器吗?
- 环境变量设置了吗?
- 选对生成器了吗?(
-G "MinGW Makefiles"
)
2. “target […] includes non-existent path”
(常见踩坑):
- 路径写成了
/include/
(多写个斜杠) - 用了绝对路径但换电脑了
- 变量名拼写错误(cmake区分大小写!)
3. “undefined reference to…”
(死亡三件套检查):
- 源文件加到add_executable了吗?
- 链接库顺序对吗?(被依赖的库放后面)
- 用了C++17特性但没设置标准?
五、高手进阶路线(秃头警告)
1. 玩转生成器表达式
target_compile_definitions(main
PRIVATE
$<$<CONFIG:Debug>:DEBUG_MODE=1>
)
2. 自定义Find模块
创建FindMyLib.cmake:
find_path(MYLIB_INCLUDE_DIR mylib.h)
find_library(MYLIB_LIBRARY NAMES mylib)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MyLib DEFAULT_MSG
MYLIB_INCLUDE_DIR
MYLIB_LIBRARY
)
3. 单元测试集成
enable_testing()
add_test(NAME my_test COMMAND test_executable)
六、CMakeLists.txt的十大禁忌(必看!)
- 在非build目录运行cmake(文件污染警告!)
- 用全局命令污染变量(include_directories害死人)
- 忘记设置C++标准(C++20不是默认的!)
- 硬编码路径(/home/xxx这种写法会遭报应)
- 混合使用新旧语法(要么复古要么现代)
- 忽略缓存变量(clean build治百病)
- 过度使用宏(CMake不是C预处理器!)
- 不写版本限制(兼容性炸弹)
- 滥用GLOB收集源文件(新增文件不自动检测)
- 不看官方文档(https://cmake.org/cmake/help/latest/)
(看到这里还没关页面?看来是真爱了!)
最后说句掏心窝子的:CMake就是个越用越香的傲娇工具。刚开始被虐到怀疑人生正常,坚持住!哪天突然开窍了,你会发现它简直是跨平台开发的瑞士军刀。遇到报错别慌,先检查下是不是又忘了写)
——别问我怎么知道的(捂脸)