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的语法,看看那些常用的命令到底在做什么。