2、CMake基础语法:CMakeLists.txt文件结构、cmake_minimum_required、project、add_executable、message命令
好,咱们正式开始写CMake。说实话,很多初学者一上来就被各种CMakeLists.txt吓住了,觉得这玩意儿比C++代码还难懂。其实你想想看,它就是个配置文件,告诉编译器怎么干活而已。我当年刚接触CMake时,也是从这几条命令开始的,一步步摸索过来的。
2.1 CMakeLists.txt 文件结构
每个CMake项目,根目录下必须有一个CMakeLists.txt。这是CMake的入口文件,就像C++程序的main函数一样。我习惯把它叫做「项目的说明书」。
一个典型的CMakeLists.txt长这样:
cmake_minimum_required(VERSION 3.16)
project(MyApp VERSION 1.0.0 LANGUAGES CXX)
add_executable(my_app main.cpp utils.cpp)
target_include_directories(my_app PRIVATE include)
嗯,结构其实很清晰:
- 开头:声明CMake最低版本
- 第二行:定义项目名称、版本、语言
- 中间:添加可执行文件或库
- 后面:配置各种编译选项、依赖关系
说白了,CMakeLists.txt就是从上往下执行的脚本。每条命令都有它的作用,咱们一条条拆开讲。
2.2 cmake_minimum_required — 版本底线
这条命令写在最前面,告诉CMake:「低于这个版本就别跑了」。为什么要有这个?因为不同版本的CMake,语法和功能有差异。我曾经在项目里用过3.10版本的特性,结果同事的机器上装的是3.5,一运行就报错,折腾了半天。
cmake_minimum_required(VERSION 3.16)
这里有几个要点:
- VERSION 关键字不能少
- 版本号建议写你实际测试过的版本
- 如果项目用了较新的特性(比如3.14才有的FetchContent),就写3.14
2.3 project — 给项目起个名
project命令定义项目的元信息。我个人觉得这是CMakeLists.txt里最「有仪式感」的一行——它标志着你的代码正式成为一个项目。
project(MyApp VERSION 1.0.0 LANGUAGES CXX)
参数说明:
| 参数 | 含义 | 示例 |
|---|---|---|
| 项目名称 | 你的项目叫什么 | MyApp |
| VERSION | 版本号,可选 | 1.0.0 |
| LANGUAGES | 使用的编程语言 | CXX (C++)、C、Fortran |
为什么推荐写VERSION?因为CMake会自动生成一些变量,比如 PROJECT_VERSION、MyApp_VERSION,后面做版本管理时特别方便。我在做持续集成时,经常用这些变量来打标签。
至于LANGUAGES,默认是C和CXX。如果你只用C++,写CXX就够了,能少检测一些编译器,加快配置速度。
2.4 add_executable — 生成可执行文件
这是最常用的命令之一。它的作用就是告诉CMake:「我要编译一个可执行程序,源文件是这些」。
add_executable(my_app main.cpp utils.cpp)
第一个参数是目标名称,第二个及以后是源文件列表。目标名称可以随便起,但建议和项目名保持一致,或者用下划线连接。我习惯用项目名的小写形式。
这里有个坑:源文件路径是相对于当前CMakeLists.txt的。如果你把源文件放在src目录下,就要写成:
add_executable(my_app src/main.cpp src/utils.cpp)
或者更优雅的方式——用变量:
set(SOURCES src/main.cpp src/utils.cpp)
add_executable(my_app ${SOURCES})
2.5 message — 调试利器
message命令就是CMake里的printf。它可以在配置阶段打印信息,帮你排查问题。我调试CMakeLists.txt时,用得最多的就是它。
message("Hello from CMake!")
message(STATUS "Project version: ${PROJECT_VERSION}")
message(WARNING "This is a warning")
message(FATAL_ERROR "Something went wrong, stop!")
message有几种模式:
- 无前缀:直接打印,不带任何标记
- STATUS:普通信息,前面会加两个横线,看起来更规范
- WARNING:警告,会显示为黄色(在终端里)
- FATAL_ERROR:致命错误,打印后直接终止CMake配置
我曾经在排查一个链接错误时,在CMakeLists.txt里加了十几条message,打印各种变量的值。最后发现是一个路径写错了。嗯,从那以后我写CMake时,总会顺手加几条message,方便后面调试。
message(STATUS "---") 打印分隔线,能让输出更清晰。比如在打印变量列表前后各加一条,一眼就能看出范围。
2.6 知识体系总览
下面这张图,把本章的核心命令和它们的关系画出来了。你可以把它当作CMakeLists.txt的「骨架」:
2.7 实战:写一个完整的CMakeLists.txt
咱们把今天学的串起来,写一个能用的例子。假设项目结构如下:
my_project/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ └── hello.cpp
└── include/
└── hello.h
CMakeLists.txt内容:
cmake_minimum_required(VERSION 3.16)
project(HelloWorld VERSION 1.0.0 LANGUAGES CXX)
message(STATUS "Configuring HelloWorld v${PROJECT_VERSION}")
add_executable(hello src/main.cpp src/hello.cpp)
target_include_directories(hello PRIVATE include)
message(STATUS "Build target: hello")
你看,整个文件就十几行。配置时CMake会打印:
-- Configuring HelloWorld v1.0.0
-- Build target: hello
-- Configuring done
-- Generating done
干净利落。这就是CMake的魅力——用最少的代码,做最多的事。
• cmake_minimum_required 是「门槛」,写在第一行
• project 是「身份证」,定义项目基本信息
• add_executable 是「生产线」,把源文件变成可执行文件
• message 是「对讲机」,帮你随时了解配置状态
嗯,基础语法就这些。别小看这四条命令,它们能撑起90%的小型项目。后面章节我们会在这个基础上,加入库管理、测试、安装等功能,一步步把CMakeLists.txt变强大。
公众号:蓝海资料掘金营,微信deep3321