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

好,咱们直接动手。别管那些花里胡哨的理论,先把第一个CMake项目跑起来。你想想看,学任何东西,第一件事不就是让它「动」起来吗?

我个人习惯,每学一个新工具,先写一个能打印"Hello World"的程序。CMake也不例外。咱们的目标很简单:写一个C++源文件,然后用CMake把它编译成可执行文件。

2.1 项目结构:先搭个架子

首先,你得有个文件夹。我建议你新建一个目录,比如叫 hello_cmake。里面放两个文件:

  • main.cpp —— 你的C++源代码
  • CMakeLists.txt —— CMake的构建脚本

就这么简单。别搞复杂了,刚开始越简单越好。

main.cpp 的内容,咱们就用最经典的:

#include <iostream>

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

嗯,这里要注意:文件名别写错了。我见过有同事把 main.cpp 写成 main.CPP,结果在Linux上编译报错,折腾了半天。大小写敏感,切记。

2.2 CMakeLists.txt:核心中的核心

现在,咱们来写 CMakeLists.txt。这是CMake的灵魂文件。说白了,CMake就是靠这个文件来知道「你要编译什么」、「用什么编译器」、「输出什么」。咱们先写一个最精简的版本:

cmake_minimum_required(VERSION 3.10)
project(HelloCMake)
add_executable(hello main.cpp)

就三行。别嫌少,这三行够用了。咱们一行一行拆开看。

2.2.1 cmake_minimum_required:版本声明

第一行 cmake_minimum_required(VERSION 3.10),意思是「这个项目至少需要CMake 3.10版本」。为什么要有这行?

我在项目中遇到过,有人用了一个很新的CMake特性,比如 target_sources 的某些高级用法,结果同事的机器上CMake版本太老,直接报错。所以,这行就是给你的项目设一个「最低门槛」。我个人习惯,一般设到3.10或3.16,这两个版本比较稳定,覆盖了绝大多数常用功能。

注意: 版本号别设得太高。比如你设成3.30,那用户就得去装最新版CMake。除非你确实用了新特性,否则建议设一个保守的版本。

2.2.2 project:项目名称

第二行 project(HelloCMake),就是给你的项目起个名字。这个名字会影响到后面生成的构建目录名、库文件的前缀等等。你可以随便起,但最好有意义。

这里有个小细节:project 命令还可以指定语言,比如 project(HelloCMake CXX) 表示只用C++。不过咱们先不搞那么复杂,默认就好。

2.2.3 add_executable:生成可执行文件

第三行 add_executable(hello main.cpp),意思是「我要生成一个叫 hello 的可执行文件,源文件是 main.cpp」。

你想想看,这就像告诉CMake:「嘿,帮我把这些源文件编译成一个程序,名字就叫hello。」如果有多个源文件,你可以继续往后加,比如 add_executable(hello main.cpp utils.cpp)。不过咱们现在只有一个文件,先这样。

小提示: 可执行文件的名字可以随便起,但别跟系统命令重名。比如你起名叫 test,那在终端里执行 ./test 时,可能会跟系统的 test 命令混淆。我一般用项目名的小写,比如 hello

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

好,文件都写好了。现在咱们来构建。打开终端,进入 hello_cmake 目录,执行以下命令:

mkdir build
cd build
cmake ..
make

或者,如果你用的是Ninja(一个更快的构建工具):

mkdir build
cd build
cmake .. -G Ninja
ninja

我个人推荐用Ninja,编译速度快很多。尤其是大项目,能省不少时间。

执行完 cmake .. 后,你会看到类似这样的输出:

-- The C compiler identification is GNU 11.2.0
-- The CXX compiler identification is GNU 11.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc - works
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/hello_cmake/build

看到「Configuring done」和「Generating done」就说明配置成功了。然后 makeninja 会编译你的代码,生成可执行文件。

最后,运行它:

./hello

你应该会看到:

Hello, CMake!

嗯,到这里,你的第一个CMake项目就跑起来了。是不是很简单?

2.4 避坑指南:我踩过的几个坑

我曾经在第一次用CMake时,犯过几个低级错误。分享出来,你别再踩了。

  • 忘记创建build目录:直接在源码目录里执行 cmake .make。这样会把编译产生的临时文件(.o文件、Makefile等)混在源码里,非常乱。记住:永远在build目录里构建
  • CMakeLists.txt 文件名写错:注意大小写。CMake只认 CMakeLists.txt,写成 cmakelists.txtCMakeLists.TXT 都不行。
  • 源文件路径写错:在 add_executable 里,源文件路径是相对于 CMakeLists.txt 的。如果你把 main.cpp 放在 src 子目录下,那就要写成 add_executable(hello src/main.cpp)
核心要点: CMake的构建分为两步:配置(cmake)和编译(make/ninja)。配置阶段生成构建系统文件,编译阶段才真正编译代码。这两步缺一不可。

2.5 知识体系图:一图看懂本章核心

下面这张图,帮你理清本章的核心逻辑。从源文件到可执行文件,CMake在中间做了什么。

第一个CMake项目:从源码到可执行文件 main.cpp C++ 源代码 CMakeLists.txt 构建脚本 CMake 配置 + 生成 cmake_minimum_required 构建系统 Makefile / Ninja 由CMake生成 编译器 g++ / clang++ hello(可执行文件) add_executable(hello main.cpp) 告诉CMake:我要生成一个叫hello的程序 源文件是main.cpp

这张图展示了整个流程:你提供 main.cppCMakeLists.txt,CMake读取脚本后生成构建系统文件(Makefile或Ninja文件),然后构建系统调用编译器,最终生成可执行文件 hello。说白了,CMake就是帮你省去了手写Makefile的麻烦。

2.6 本章小结

咱们这一章,完成了三件事:

  1. 创建了项目结构:一个 main.cpp 和一个 CMakeLists.txt
  2. 写了一个三行的CMake脚本:声明版本、项目名、可执行文件
  3. cmake ..make 成功构建并运行了程序

嗯,别小看这三行。它们是所有CMake项目的基石。后面无论多复杂的项目,核心逻辑都是这三行:告诉CMake「用什么版本」、「项目叫什么」、「要生成什么」。

我个人建议,你现在就动手敲一遍。别复制粘贴,亲手敲一遍,感受一下。遇到问题很正常,对照着上面的避坑指南检查一下。等你看到终端里打出 Hello, CMake! 的那一刻,你就正式入门了。


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