第一个CMake项目:从零开始构建你的第一个可执行程序

说实话,我见过太多新手一上来就对着CMakeLists.txt发懵。其实这东西没那么玄乎,说白了就是一个告诉编译器「怎么干活」的脚本文件。今天我们就从零开始,亲手搭建一个最简单的CMake项目。

我个人习惯把第一个项目叫做「Hello CMake」,而不是传统的「Hello World」。为什么?因为我们要学的不是打印字符串,而是理解CMake的工作流。

创建CMakeLists.txt:项目的灵魂文件

每个CMake项目的根目录下,都必须有一个CMakeLists.txt文件。这是CMake的入口,就像C程序的main()函数一样。

先创建一个空目录,比如my_first_cmake_project,然后在里面新建一个文本文件,命名为CMakeLists.txt(注意大小写,一个字母都不能错)。

核心原则:CMakeLists.txt 是纯文本文件,用任何编辑器都能打开。我建议用VS Code或者Sublime,别用记事本——编码问题会坑死你。

cmake_minimum_required:告诉CMake「你得够新」

文件的第一行,我通常会写这个:

cmake_minimum_required(VERSION 3.10)

这行命令的意思是:当前项目要求CMake的最低版本是3.10。如果用户机器上的CMake版本低于3.10,构建时会直接报错退出。

为什么要加这个?我在项目中遇到过一件事:有同事用了3.5版本的CMake,结果死活编译不过,查了半天才发现是某个新特性不支持。从那以后,我每条CMakeLists.txt都会写这一行。

我的建议:版本号别写太高,3.10或3.16是比较稳妥的选择。写太高了,用户还得升级CMake,体验不好。

project():给你的项目起个名字

第二行,定义项目名称:

project(HelloCMake)

这个project()命令不只是起名字那么简单。它会自动定义几个变量:

  • PROJECT_NAME:项目名称,就是"HelloCMake"
  • PROJECT_SOURCE_DIR:源码目录路径
  • PROJECT_BINARY_DIR:构建目录路径

你想想看,有了这些变量,后面引用路径就方便多了。比如我要引用源码目录下的某个文件,直接写${PROJECT_SOURCE_DIR}/src/main.c就行。

变量名 含义 示例值
PROJECT_NAME 项目名称 HelloCMake
PROJECT_SOURCE_DIR 源码根目录 /home/user/my_first_cmake_project
PROJECT_BINARY_DIR 构建目录 /home/user/my_first_cmake_project/build

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

接下来是最关键的一步——告诉CMake:我要编译一个可执行程序,源码是哪个文件

add_executable(hello_cmake main.c)

这行命令的意思是:用main.c这个源文件,生成一个名为hello_cmake的可执行文件。

注意,这里hello_cmake是目标名称,在Windows上会生成hello_cmake.exe,在Linux/macOS上生成hello_cmake。CMake会自动处理平台差异。

我曾经踩过的坑:源文件名写错了大小写。在Linux上,main.cMain.c是两个不同的文件。CMake不会帮你纠错,只会报「找不到文件」。所以文件名一定要和磁盘上的一模一样。

现在,我们还需要一个main.c文件。在项目目录下创建它:

#include <stdio.h>

int main() {
    printf("Hello CMake!\n");
    return 0;
}

嗯,这里要注意:main.cCMakeLists.txt必须在同一个目录下。这是最简单的单文件项目结构。

完整的CMakeLists.txt长什么样?

把上面三行拼起来,就是一份完整的构建脚本:

cmake_minimum_required(VERSION 3.10)
project(HelloCMake)
add_executable(hello_cmake main.c)

就三行,没了。是不是比你想象中简单?

构建与运行:见证奇迹的时刻

CMake推荐「外部构建」,也就是在项目目录外单独建一个build目录,所有临时文件都扔里面。这样做的好处是:源码目录干干净净,想重新构建时直接删掉build目录就行。

打开终端,进入项目目录,执行:

mkdir build
cd build
cmake ..
make

解释一下:

  • mkdir build:创建构建目录
  • cd build:进入构建目录
  • cmake ..:告诉CMake「源码在上一级目录」,CMake会读取../CMakeLists.txt并生成Makefile
  • make:用生成的Makefile真正编译代码

如果一切顺利,你会看到类似这样的输出:

-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/build
[ 50%] Building C object CMakeFiles/hello_cmake.dir/main.c.o
[100%] Linking C executable hello_cmake

然后运行它:

./hello_cmake

屏幕上会打印出:

Hello CMake!

一个小技巧:如果你用的是CMake 3.13以上版本,可以直接用cmake -B build代替mkdir build && cd build && cmake ..。一行命令搞定创建目录和配置。

知识体系总览

下面这张图,把整个流程串起来了。我建议你多看几遍,理解每个环节的作用:

第一个CMake项目:构建流程 1. 创建CMakeLists.txt cmake_minimum_required 2. cmake .. 配置 生成 Makefile 3. make 编译 生成可执行文件 4. ./hello_cmake 运行 输出 Hello CMake! 项目核心文件 CMakeLists.txt main.c 两者必须在同一目录下

常见问题与避坑指南

我刚开始用CMake时,也踩过不少坑。这里列几个最常见的:

  • 找不到CMakeLists.txt:检查文件名大小写,必须是CMakeLists.txt,不是CmakeLists.txtcmakelists.txt
  • 版本不匹配:如果报错说CMake版本太低,要么升级CMake,要么把cmake_minimum_required的版本号改低一点
  • 编译报错:先检查main.c的语法有没有问题,别急着怀疑CMake
  • 找不到源文件:确认add_executable里写的文件名和磁盘上的文件名完全一致

我曾经犯过的错:在Windows上用VS Code写CMakeLists.txt,保存时用了UTF-8 with BOM编码。结果CMake解析时多了一个不可见字符,报了一堆莫名其妙的错误。后来我学乖了,所有CMake文件一律用UTF-8无BOM格式保存。

好了,到这里你已经完成了第一个CMake项目。虽然只有三行命令,但整个构建流程已经跑通了。后面我们会在这个基础上,一步步加入更多功能。


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