CMake 教程(深入浅出)

CMake 教程:从零开始掌握现代 C++ 构建系统

在开发 C 或 C++ 项目时,你是否曾为复杂的编译命令而头疼?手动输入 g++ main.cpp -o main 还能应付小项目,但当项目包含几十个源文件、依赖多个第三方库、需要跨平台编译时,这种原始方式很快就会崩溃。这时候,一个强大的构建系统就显得至关重要。

CMake 正是为解决这类问题而生的工具。它不是编译器,也不是解释器,而是一个构建脚本生成器。你可以用它写一份通用的配置文件,然后根据目标平台自动生成 Makefile、Visual Studio 项目、Xcode 工程等。无论你是用 Linux、Windows 还是 macOS,CMake 都能帮你统一构建流程。

本文将带你从零开始学习 CMake 教程,通过真实案例逐步掌握核心概念,让你告别手动编译的繁琐。


为什么选择 CMake?

想象你正在建造一栋房子。如果每次换地皮都要重新设计图纸,那效率会极低。CMake 就像是你的“建筑设计蓝图”——你写一次,就能在不同工地(操作系统)上快速复制使用。

相比传统的 Makefile,CMake 具有以下优势:

  • 跨平台兼容:一套配置文件支持 Windows、Linux、macOS
  • 抽象层级高:无需关心底层编译命令细节
  • 易于维护:项目结构变化时只需修改 CMakeLists.txt,不用改一堆命令
  • 社区生态成熟:几乎所有主流 C++ 库都提供 CMake 支持

对于初学者来说,CMake 的学习曲线并不陡峭。只要你理解基本的“项目-目标-依赖”逻辑,就能快速上手。


第一个 CMake 项目:Hello World

我们来创建一个最简单的 C++ 程序,并用 CMake 构建它。

创建项目结构

hello-cmake/
├── CMakeLists.txt
└── main.cpp

编写源代码

// main.cpp
#include <iostream>

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

注释:这是标准的 C++ Hello World 程序,使用 std::cout 输出文本,return 0 表示程序正常结束。

编写 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

project(HelloCMake VERSION 1.0 DESCRIPTION "A simple CMake example")

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(hello main.cpp)

set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)

注释:

  • cmake_minimum_required(VERSION 3.10):要求 CMake 版本至少为 3.10,避免因版本过低导致语法不支持。
  • project():定义项目名、版本和描述,方便后续管理。
  • set(CMAKE_CXX_STANDARD 11):启用 C++11 标准,让代码支持现代特性如 autolambda
  • add_executable():声明一个可执行文件目标,名字为 hello,依赖 main.cpp
  • set(EXECUTABLE_OUTPUT_PATH ...):指定编译后可执行文件的输出位置。

构建过程详解

现在我们来实际运行构建流程。

创建构建目录并生成构建文件

mkdir build
cd build
cmake ..

注释:

  • mkdir build:创建独立的构建目录,这是最佳实践,避免污染源码目录。
  • cd build:进入构建目录,所有生成的文件(如 Makefile)都放在这里。
  • cmake ..:运行 CMake,其路径指向父目录(..)中的 CMakeLists.txt

执行后,你会看到类似如下输出:

-- 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/cc - skipped
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/hello-cmake/build

注释:CMake 自动检测你的编译器、标准库,并生成相应的构建文件(如 Makefile)。

编译项目

make

注释:make 会读取 CMake 生成的 Makefile,自动编译所有源文件并链接成可执行文件。

编译成功后,你会在 build/bin 目录下看到 hello 可执行文件。

运行程序

./bin/hello

输出结果:

Hello, CMake!

恭喜你!你已经成功完成第一个 CMake 项目。


多文件项目与目标管理

真实项目通常包含多个源文件。我们来扩展之前的例子。

项目结构升级

multi-file-cmake/
├── CMakeLists.txt
├── main.cpp
├── utils.cpp
└── utils.h

头文件定义

// utils.h
#ifndef UTILS_H
#define UTILS_H

// 声明一个打印函数
void print_message(const char* msg);

#endif

实现函数

// utils.cpp
#include <iostream>
#include "utils.h"

void print_message(const char* msg) {
    std::cout << "Message: " << msg << std::endl;
}

主函数调用

// main.cpp
#include "utils.h"

int main() {
    print_message("Hello from utils!");
    return 0;
}

更新 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(MultiFileCMake VERSION 1.0)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(SOURCES
    main.cpp
    utils.cpp
)

add_executable(multi_hello ${SOURCES})

set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)

注释:

  • set(SOURCES ...):将多个源文件组织成变量,便于维护。
  • add_executable(... ${SOURCES}):将变量传入,CMake 会自动处理所有依赖关系。
  • CMake 会自动分析头文件依赖,确保 utils.cppmain.cpp 之前编译。

再次运行 cmake ..make,即可成功构建。


使用第三方库:链接 Boost

真实项目常需依赖外部库。我们以 Boost 为例,展示如何在 CMake 中链接库。

安装 Boost(以 Ubuntu 为例)

sudo apt install libboost-all-dev

编写使用 Boost 的代码

// boost_example.cpp
#include <iostream>
#include <boost/algorithm/string.hpp>

int main() {
    std::string text = "  Hello, Boost!  ";
    boost::trim(text); // 去除首尾空格
    std::cout << "Trimmed: " << text << std::endl;
    return 0;
}

修改 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(BoostExample VERSION 1.0)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(SOURCES boost_example.cpp)

add_executable(boost_app ${SOURCES})

find_package(Boost REQUIRED COMPONENTS system)

if(Boost_FOUND)
    target_include_directories(boost_app PRIVATE ${Boost_INCLUDE_DIRS})
    target_link_libraries(boost_app ${Boost_LIBRARIES})
endif()

set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)

注释:

  • find_package(Boost REQUIRED COMPONENTS system):查找 Boost 库,要求 system 组件存在。
  • target_include_directories():为目标添加头文件搜索路径。
  • target_link_libraries():链接库文件,CMake 会自动处理依赖顺序。
  • if(Boost_FOUND):安全检查,防止找不到库时报错。

运行 cmake .. && make,即可成功编译并运行。


高级技巧:构建类型与测试

设置构建类型

CMake 支持多种构建类型,如 DebugReleaseRelWithDebInfo

在构建时指定类型:

cmake -DCMAKE_BUILD_TYPE=Release ..
make

注释:-DCMAKE_BUILD_TYPE=Release 会启用优化选项,移除调试符号,提升性能。

添加单元测试(使用 Google Test)

enable_testing()

find_package(GTest REQUIRED)

add_executable(test_math math_test.cpp)

target_link_libraries(test_math GTest::gtest GTest::gtest_main)

add_test(NAME math_test COMMAND test_math)

注释:

  • enable_testing():启用测试支持。
  • add_test():定义一个测试用例,名称为 math_test,命令为 test_math
  • 运行 ctest 可执行所有测试。

总结

通过本篇 CMake 教程,你已掌握:

  • 如何创建并构建一个简单的 C++ 项目
  • 多文件项目的管理方式
  • 如何链接第三方库(如 Boost)
  • 高级功能如构建类型控制和单元测试

CMake 不是魔法,它只是一个工具。但正是这个工具,让你从“编译命令的奴隶”变成了“构建流程的主人”。

无论你是学生、开发者,还是在企业中参与大型 C++ 项目,CMake 都是你必须掌握的技能。它让跨平台开发变得简单,让代码维护变得高效。

记住:写好 CMakeLists.txt,就是给你的项目装上“自动导航系统”

现在,打开你的 IDE,新建一个项目,试着用 CMake 来构建它吧。你会发现,构建不再是负担,而是一种享受。