2、第一个CMake项目:创建CMakeLists.txt、cmake_minimum_required、project命令、add_executable、构建与运行

好,咱们正式开始动手了。这一章,我会带你从零搭建一个完整的CMake项目。说白了,就是写一个CMakeLists.txt,然后把它变成能跑起来的可执行文件。

我记得刚接触CMake那会儿,总觉得这东西很神秘。后来发现,其实核心就几个命令。你只要掌握了这五个步骤,后面的路就好走了。

2.1 项目结构长什么样?

先别急着写代码。咱们得先搞清楚,一个CMake项目在磁盘上是怎么组织的。

我个人习惯这样安排:

my_project/
├── CMakeLists.txt      # 核心文件,CMake的"剧本"
├── main.cpp            # 源代码文件
└── build/              # 构建目录(稍后创建)

嗯,就这么简单。一个CMakeLists.txt,一个main.cpp,再加一个空的build文件夹。你想想看,这比那些动辄几十个配置文件的构建系统清爽多了吧?

我的建议:永远把构建产物放在单独的目录里,别跟源码混在一起。我在项目中见过太多人把build目录放在源码树下,结果git status一看全是编译垃圾。用build/目录,干净又卫生。

2.2 编写 main.cpp

咱们先写一个最简单的C++程序,用来验证整个流程。

// main.cpp
#include <iostream>

int main() {
    std::cout << "Hello, CMake!" << std::endl;
    return 0;
}

这段代码没什么好说的。但请注意,我故意用了std::endl而不是\n。为什么?因为我想让你看到,CMake构建出来的程序,连这种细节都能完美支持。

2.3 编写 CMakeLists.txt

这才是重头戏。咱们一行一行来写。

cmake_minimum_required(VERSION 3.15)
project(MyFirstProject VERSION 1.0.0 LANGUAGES CXX)
add_executable(my_app main.cpp)

三行代码,搞定。咱们拆开来看。

2.3.1 cmake_minimum_required

这行命令指定了CMake的最低版本。说白了,就是告诉系统:"我的脚本需要至少3.15版本的CMake才能运行"。

为什么要写这个?我曾经在一个老项目里遇到过,同事用了CMake 3.20的新特性,结果客户的CI机器上装的是3.10,一跑就报错。从那以后,我养成了习惯:明确声明最低版本

避坑指南:不要把版本号写得太高。比如你本地用的是3.30,但团队里有人还在用3.16,你写cmake_minimum_required(VERSION 3.30),人家根本跑不起来。我一般写3.15或3.16,这个版本已经支持了绝大多数常用功能。

2.3.2 project 命令

project命令定义了项目名称和元信息。它的完整语法是这样的:

project(<项目名> [VERSION <主版本>.<次版本>.<补丁>] [LANGUAGES <语言列表>])

咱们的例子中:

  • 项目名MyFirstProject,这个名称会被CMake内部使用,比如生成一些变量名。
  • VERSION1.0.0,版本号。虽然不是必须的,但我建议你从一开始就养成习惯。以后做库的版本管理时,这个字段会直接派上用场。
  • LANGUAGESCXX,表示我们用的是C++。如果你不写,CMake默认会检测C和C++。明确指定可以加快配置速度。
核心要点:project()执行后,CMake会自动设置一些变量,比如PROJECT_NAMEPROJECT_VERSIONPROJECT_SOURCE_DIR等。你可以在后面的脚本里直接引用它们。

2.3.3 add_executable

这行命令告诉CMake:"我要生成一个可执行文件,名字叫my_app,它的源代码是main.cpp"。

语法很简单:

add_executable(<目标名> <源文件列表>)

这里有个细节:目标名生成的可执行文件名默认是相同的。比如add_executable(my_app main.cpp),生成的就是my_app(Linux/macOS)或my_app.exe(Windows)。

你可以在后面用set_target_properties修改输出文件名,但刚开始,保持默认就好。

2.4 构建与运行

文件写好了,怎么把它变成程序?分两步走。

2.4.1 配置阶段(Configure)

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

mkdir build
cd build
cmake ..

这里cmake ..的意思是:build目录里,读取上一级目录的CMakeLists.txt,生成构建系统

你会看到类似这样的输出:

-- The CXX compiler identification is GNU 11.4.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/my_project/build

看到"Configuring done"和"Generating done",说明配置成功了。CMake在build目录里生成了Makefile(如果你用的是Unix Makefiles生成器)或其他构建文件。

一个小技巧:如果你用的是VS Code或CLion,它们通常会自动帮你做这一步。但手动敲一遍命令,能让你更清楚底层发生了什么。

2.4.2 编译阶段(Build)

配置完成后,执行:

cmake --build .

或者,如果你用的是Make,也可以直接:

make

我个人更推荐cmake --build .,因为它不依赖具体的构建工具。不管底层是Make、Ninja还是MSBuild,这一条命令都能搞定。

编译成功后,你会看到:

[100%] Built target my_app

然后在build目录下,就能找到生成的可执行文件了。

2.4.3 运行

直接运行它:

./my_app

输出:

Hello, CMake!

完美。你第一个CMake项目,跑起来了。

2.5 知识体系总览

下面这张图,帮你把这一章的核心逻辑串起来:

第一个CMake项目:核心流程 1. 编写源码 2. 配置 (cmake ..) 3. 构建 (cmake --build) CMakeLists.txt cmake_minimum_required project(...) add_executable(...) main.cpp (源代码) 配置阶段 检测编译器 解析CMakeLists.txt 生成构建文件 输出:Makefile / Ninja build.ninja 构建阶段 编译源代码 链接目标文件 生成可执行文件 输出:my_app (可执行文件) 三行CMakeLists.txt + 两步构建 = 一个可运行的程序

2.6 常见问题与避坑

这一路走来,我踩过不少坑。挑几个典型的跟你说说。

问题1:找不到CMakeLists.txt

如果你执行cmake ..时报错CMakeLists.txt not found,八成是你当前不在build目录里,或者CMakeLists.txt不在上一级目录。检查一下路径。

问题2:版本不匹配

如果你写的cmake_minimum_required(VERSION 3.30),但系统装的是3.16,会直接报错退出。解决办法:要么升级CMake,要么降低版本要求。

问题3:编译错误

如果cmake --build .时报编译错误,先检查main.cpp有没有语法问题。我遇到过最蠢的一次,是文件名写成了main.cppp(多了一个p),CMake没报错,但编译器找不到文件。

我曾经踩过的坑:有一次我在CMakeLists.txt里写了add_executable(my_app main.cpp utils.cpp),但utils.cpp文件根本不存在。CMake配置阶段不会报错,直到编译阶段才崩溃。所以,源文件列表一定要跟实际文件一一对应

2.7 小结

这一章,咱们亲手创建了第一个CMake项目。你学会了:

  • 项目的基本目录结构
  • cmake_minimum_required指定最低版本
  • project定义项目元信息
  • add_executable添加可执行目标
  • 配置和构建的两步流程

嗯,看起来简单,但这就是CMake的基石。后面的所有高级特性,都是在这三行命令的基础上长出来的。你把这个流程跑通了,后面学什么都快。


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