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,一跑就报错。从那以后,我养成了习惯:明确声明最低版本。
cmake_minimum_required(VERSION 3.30),人家根本跑不起来。我一般写3.15或3.16,这个版本已经支持了绝大多数常用功能。
2.3.2 project 命令
project命令定义了项目名称和元信息。它的完整语法是这样的:
project(<项目名> [VERSION <主版本>.<次版本>.<补丁>] [LANGUAGES <语言列表>])
咱们的例子中:
- 项目名:
MyFirstProject,这个名称会被CMake内部使用,比如生成一些变量名。 - VERSION:
1.0.0,版本号。虽然不是必须的,但我建议你从一开始就养成习惯。以后做库的版本管理时,这个字段会直接派上用场。 - LANGUAGES:
CXX,表示我们用的是C++。如果你不写,CMake默认会检测C和C++。明确指定可以加快配置速度。
project()执行后,CMake会自动设置一些变量,比如PROJECT_NAME、PROJECT_VERSION、PROJECT_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生成器)或其他构建文件。
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 知识体系总览
下面这张图,帮你把这一章的核心逻辑串起来:
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的基石。后面的所有高级特性,都是在这三行命令的基础上长出来的。你把这个流程跑通了,后面学什么都快。