1. CMake入门:CMake是什么、为什么用CMake、CMake与Makefile的关系、CMake的安装与版本选择
1.1 CMake到底是什么?
简单来说,CMake是一个跨平台的构建系统生成器。它不是编译器,也不是构建工具本身——它生成的是构建脚本。
我刚开始接触CMake时,也困惑过:既然有Makefile,为什么还要多此一举?后来在项目中吃了不少苦头才明白,CMake解决的是「不同平台、不同编译器、不同依赖」这个让人头疼的问题。
举个例子:你在Windows上用Visual Studio写代码,同事在macOS上用Clang,服务器跑的是Linux用GCC。没有CMake,你得维护三套Makefile。有了CMake,你只需要写一份CMakeLists.txt,然后让它帮你生成对应的构建文件。
核心概念:CMake本身不构建项目,它生成构建文件(如Makefile、Visual Studio解决方案、Xcode项目等),然后由底层的构建工具去执行真正的编译和链接。
1.2 为什么用CMake?
说实话,C++的构建工具链一直是个痛点。我见过太多团队因为构建配置问题浪费大量时间。CMake之所以成为事实标准,有几个关键原因:
- 跨平台:一套CMakeLists.txt,Windows/Linux/macOS通吃
- 支持多种生成器:Make、Ninja、Visual Studio、Xcode……你想要的它都有
- 依赖管理:通过
find_package可以优雅地处理第三方库 - 模块化:支持子目录、库的创建和链接,大型项目也能保持清晰
- 社区生态:几乎所有现代C++库都提供CMake支持
我记得有一次接手一个遗留项目,它的Makefile有2000多行,而且只支持GCC。客户要求移植到MSVC,我花了整整一周才搞定。如果当初用了CMake,可能半天就解决了。
个人建议:如果你在2024年还在手写Makefile,除非项目非常小(比如只有几个源文件),否则真的可以考虑迁移到CMake。长期来看,维护成本会低很多。
1.3 CMake与Makefile的关系
很多人以为CMake和Makefile是竞争关系,其实不是。它们更像是「设计师」和「施工队」的关系。
Makefile是直接告诉构建工具「怎么做」的脚本。而CMake是告诉你「想要什么」,然后由CMake生成对应的Makefile(或其他构建文件)。
看个简单的对比:
// 传统Makefile写法
hello: hello.cpp
g++ -o hello hello.cpp -std=c++17
// CMake写法(CMakeLists.txt)
cmake_minimum_required(VERSION 3.15)
project(HelloWorld)
add_executable(hello hello.cpp)
target_compile_features(hello PRIVATE cxx_std_17)
你想想看,如果项目有20个源文件、5个第三方库、还要支持3个平台……手写Makefile会变成什么样子?而CMake只需要几十行配置就能搞定。
注意:CMake生成的Makefile通常比手写的更复杂,因为它要处理各种边界情况。不要试图去读懂它——你只需要维护CMakeLists.txt就够了。
1.4 CMake的安装与版本选择
安装CMake其实很简单,但版本选择上我踩过坑,所以想多说几句。
安装方式
| 平台 | 推荐方式 | 命令/步骤 |
|---|---|---|
| Ubuntu/Debian | apt | sudo apt install cmake |
| macOS | Homebrew | brew install cmake |
| Windows | 官方安装包 | 从cmake.org下载.msi安装 |
| 通用 | 源码编译 | 下载源码,./bootstrap && make && sudo make install |
我个人习惯用包管理器安装,省事。但如果你需要最新版本,或者包管理器里的版本太老,那就去官网下载二进制包。
版本选择策略
这里有个常见的坑:很多人直接装最新版,结果发现项目里用的某些语法在新版中被废弃了。或者反过来,装了个老版本,结果新特性用不了。
我的建议是:
- 新项目:用CMake 3.20以上,支持现代CMake的几乎所有特性
- 维护老项目:看项目里
cmake_minimum_required指定的版本,保持一致 - 团队协作:统一版本,避免「我这边能编译你那边不行」的尴尬
避坑指南:我曾经在一个项目里用了CMake 3.25的新特性,结果CI服务器上装的是3.16,构建直接挂了。从那以后,我养成了习惯:先在cmake_minimum_required里指定最低版本,并且用if(CMAKE_VERSION VERSION_GREATER ...)做版本判断。
验证安装
装完之后,跑一下这个命令确认:
cmake --version
你会看到类似这样的输出:
cmake version 3.27.8
CMake suite maintained and supported by Kitware (kitware.com/cmake).
嗯,看到版本号就说明装好了。
1.5 第一个CMake项目
光说不练假把式。我们来写一个最简单的CMake项目,感受一下流程。
项目结构:
my_project/
├── CMakeLists.txt
└── main.cpp
main.cpp内容:
#include <iostream>
int main() {
std::cout << "Hello, CMake!" << std::endl;
return 0;
}
CMakeLists.txt内容:
cmake_minimum_required(VERSION 3.10)
project(MyFirstProject)
add_executable(my_app main.cpp)
构建步骤:
mkdir build
cd build
cmake ..
cmake --build .
./my_app
就这么简单。你看到了吗?cmake ..生成构建文件,cmake --build .执行真正的编译。整个过程清晰明了。
重要:永远在单独的build目录里构建,不要把生成的文件混在源码目录里。这是CMake社区的最佳实践,也是我一开始就养成的习惯。
好了,第一章就到这里。你已经知道了CMake是什么、为什么用它、它和Makefile的关系,以及怎么安装和写第一个项目。下一章我们会深入CMakeLists.txt的语法,看看那些常用的命令到底在做什么。