第一个CMake项目:CMakeLists.txt结构,project()与cmake_minimum_required(),add_executable()
说实话,我见过太多新手一上来就对着CMakeLists.txt发懵。这玩意儿看起来不就是个文本文件吗?怎么那么多讲究?
嗯,它确实就是个文本文件。但它是整个CMake构建系统的灵魂。今天我们就从零开始,把这个文件拆开揉碎了讲清楚。
CMakeLists.txt:项目的"总指挥"
每个CMake项目,根目录下必须有一个CMakeLists.txt。这是硬性规定,没得商量。我刚开始用CMake时,就犯过这种低级错误——把文件命名成cmakelists.txt(少了个大写字母),结果折腾了半小时才发现。
这个文件说白了就是告诉CMake三件事:
- 你的项目叫什么名字
- 需要什么版本的CMake
- 要编译哪些源文件
就这么简单。别把它想得太复杂。
cmake_minimum_required():版本红线
先看这个函数:
cmake_minimum_required(VERSION 3.10)
它的意思很直白——如果用户机器上的CMake版本低于3.10,直接报错退出。为什么要这么干?
我在项目中遇到过一件事:有个同事用了3.5版本的CMake,结果我们项目里用了3.10才支持的IN_LIST操作符。编译到一半报错,排查了整整一个下午。从那以后,我每个项目第一行必写这个。
版本号怎么选?我个人习惯看项目里用了哪些CMake特性。如果只是简单编译,3.10就够用。如果要用到FetchContent、target_precompile_headers这些高级功能,至少得3.14以上。
project():给项目一个身份
接下来是project():
project(MyProject VERSION 1.0.0 LANGUAGES CXX)
这个函数干了三件事:
- 定义了项目名称——
MyProject - 设置了版本号——
1.0.0 - 指定了编程语言——
CXX(就是C++)
你可能会问:版本号有什么用?说实话,小项目确实用不上。但一旦项目大了,需要生成安装包、做版本管理时,PROJECT_VERSION这个变量就派上用场了。我维护的一个开源库,就是靠这个变量自动生成头文件里的版本宏,省了不少事。
add_executable():生成可执行文件
最后是核心函数:
add_executable(my_app main.cpp utils.cpp)
第一个参数是目标名称,也就是生成的可执行文件名(Windows下会变成my_app.exe)。后面的参数是源文件列表。
这里有个坑:我曾经把源文件路径写错了,结果CMake没报错,但编译时链接失败。排查了半天才发现是路径问题。所以建议用${CMAKE_CURRENT_SOURCE_DIR}来拼接绝对路径,或者直接用相对路径(相对于CMakeLists.txt所在目录)。
源文件多了怎么办?可以用变量:
set(SOURCES
main.cpp
utils.cpp
network.cpp
database.cpp
)
add_executable(my_app ${SOURCES})
这样清晰多了。我一般把源文件按模块分组,用不同的变量名管理。
完整的CMakeLists.txt长什么样?
把上面三个拼起来,就是一个最小可用的CMake项目:
cmake_minimum_required(VERSION 3.10)
project(MyFirstProject VERSION 1.0.0 LANGUAGES CXX)
set(SOURCES
main.cpp
utils.cpp
)
add_executable(my_app ${SOURCES})
就这几行。你把它放到项目根目录,然后执行:
mkdir build
cd build
cmake ..
make
就能编译出my_app可执行文件。是不是很简单?
本章知识体系
下面这张图帮你理清CMakeLists.txt的核心结构:
避坑指南
最后分享几个我踩过的坑:
- 文件名大小写:CMakeLists.txt,C和L必须大写。我见过有人写成cmakelists.txt,结果CMake根本找不到。
- 路径中的空格:项目路径里不要有空格。虽然CMake能处理,但有些编译器会报错。我吃过这个亏,后来所有项目目录都用下划线。
- 源文件遗漏:add_executable里漏写源文件,编译能过但链接会报"undefined reference"。排查方法:先检查源文件列表是否完整。
- 版本号写错:cmake_minimum_required(VERSION 3.10) 中间的VERSION不能省略。我见过有人直接写cmake_minimum_required(3.10),结果报错。
好了,这就是第一个CMake项目的全部内容。你可以在自己的机器上试试,写一个最简单的"Hello World"程序,用CMake编译运行。相信我,当你看到终端里输出"Hello World"的那一刻,会很有成就感。