8、CMake入门:CMakeLists.txt基本语法、project()与add_executable()

说实话,我第一次接触CMake的时候,心里是有点抵触的。那时候我还在用Makefile,觉得手写依赖规则才叫「硬核」。直到有一次接手一个跨平台项目,要在Linux、Windows和嵌入式板子上分别编译,Makefile改得我头皮发麻……嗯,从那以后,我就老老实实学CMake了。

今天咱们聊的,是CMake最核心的三个东西:CMakeLists.txt怎么写project()怎么用add_executable()怎么配。说白了,你只要搞懂这三样,一个多文件C项目就能跑起来了。

8.1 CMakeLists.txt:项目的「总指挥」

每个用CMake管理的项目,根目录下必须有一个 CMakeLists.txt。它就像项目的配置文件,告诉CMake:你的源码在哪、要生成什么、依赖什么库。

我个人习惯把 CMakeLists.txt 放在项目根目录。比如这样一个结构:

my_project/
├── CMakeLists.txt
├── src/
│   ├── main.c
│   ├── utils.c
│   └── utils.h
└── build/          # 编译产物放这里

注意,build/ 目录是我手动建的。为什么?因为CMake推荐「外部构建」,也就是源码和编译产物分开。你想想看,如果编译出来的 .o 文件和源码混在一起,哪天想清理一下,一不小心就把源码删了……我曾经就干过这种蠢事。

小技巧: 在项目根目录执行 mkdir build && cd build && cmake ..,所有临时文件都在 build 里,干净又卫生。

8.2 project():给项目起个名,顺便定个语言

project() 是CMakeLists.txt里第一个要调用的命令。它的作用很简单:声明项目名称,并指定使用的编程语言

基本语法长这样:

project(项目名称 [语言列表])

举个例子:

project(MyProject C)

这行代码干了三件事:

  • 项目名字叫 MyProject
  • 告诉CMake我们只用C语言(不加的话默认C、C++、Fortran都检测,没必要)
  • 自动生成几个变量,比如 PROJECT_NAMEPROJECT_SOURCE_DIRPROJECT_BINARY_DIR

我在项目中遇到过一个问题:如果项目里既有C又有C++,但忘了写 LANGUAGES,CMake会默认启用C++编译器。结果我明明只写了 .c 文件,它却去链接C++标准库,编译倒是过了,但链接时报一堆莫名其妙的错。所以我的建议是——明确写清楚语言,别偷懒。

重点: project() 必须在 cmake_minimum_required() 之后调用。顺序错了,CMake会报错。

8.3 add_executable():把源码变成可执行文件

有了项目名,接下来就是告诉CMake:你要生成一个可执行程序,源码是哪些文件。

语法:

add_executable(目标名称 源文件列表)

比如:

add_executable(my_app src/main.c src/utils.c)

这行代码的意思是:用 main.cutils.c 编译出一个叫 my_app 的可执行文件。注意,目标名称不能有空格,也不能和已有目标重名。

你可能会问:头文件呢?不用写进去吗?

嗯,这里要注意:头文件不需要写在 add_executable()。CMake会自动分析源码中的 #include 依赖。但如果你想让头文件出现在IDE的项目视图中,可以这样写:

add_executable(my_app src/main.c src/utils.c src/utils.h)

这样写不影响编译,只是让IDE更好看。我个人习惯把头文件也列上,因为团队里有人用VS Code,有人用CLion,列出来大家都能看到项目结构。

避坑指南: 我曾经把源文件路径写错了,比如 add_executable(my_app main.c) 但 main.c 在 src/ 目录下。CMake不会报错,但链接时会提示「找不到main函数」。检查路径,这是最基础的坑。

8.4 一个完整的入门示例

咱们把上面讲的串起来,写一个完整的 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(DemoProject C)

add_executable(demo src/main.c src/utils.c)

就这么三行。然后执行:

mkdir build
cd build
cmake ..
make

你就会在 build/ 目录下看到一个叫 demo 的可执行文件。是不是很简单?

你想想看,如果不用CMake,你得手写Makefile,还得处理跨平台的编译器差异。用CMake,三行搞定。这就是工具的价值。

8.5 知识体系:CMake入门核心逻辑

下面这张图,是我梳理的CMake入门阶段的知识脉络。你看一眼,心里就有谱了。

CMake入门核心知识体系 CMakeLists.txt 基本语法:命令(参数...) project(名称 语言) 定义项目名称 指定编程语言 生成内置变量 add_executable(目标 源文件) 生成可执行文件 列出 .c 源文件 头文件可选列出 三行代码,搞定一个多文件C项目

8.6 常见问题与避坑

问题 原因 解决办法
cmake 提示 CMake Error: The source directory does not appear to contain CMakeLists.txt 当前目录下没有 CMakeLists.txt 检查是否在项目根目录执行 cmake
make 后找不到 main 函数 源文件路径写错了,或者漏写了源文件 检查 add_executable() 中的文件路径
编译时提示 undefined reference to 某个函数定义在另一个 .c 文件中,但没被包含 把缺失的 .c 文件加到 add_executable() 里
cmake 版本太低 CMakeLists.txt 里写了高版本才支持的命令 降低 cmake_minimum_required 版本,或升级CMake
我的经验: 刚开始学CMake,别想着一步到位。先写一个最简单的 CMakeLists.txt,能编译通过再说。后面再慢慢加库、加子目录、加编译选项。一口吃不成胖子,编译也是。

好了,CMake入门就聊到这儿。你只要记住:project() 定项目名和语言,add_executable() 定目标和源文件,再加上 cmake_minimum_required() 保底,一个多文件C项目就能用CMake管理起来了。剩下的,都是锦上添花。


公众号:蓝海资料掘金营,微信deep3321