第 1 章 初识 CMake

基础知识

编译 C++ 源代码似乎是一个相当简单的过程。让我们创建一个简单的小程序,例如经典的 hello.cpp,如下:


chapter-01/01-hello/hello.cpp

#include <iostream>

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

现在,要获得可执行文件,我们需要运行一行命令。用文件名作为参数调用编译器:

$ g++ hello.cpp -o a.out

代码正确,编译器会默默地帮我们生成机器能够读懂的二进制可执行文件。我们可以通过文件名来调用它:

$ ./a.out
Hello World!
$

然而,随着我们项目的发展,你很快就会明白,将所有代码保存在一个文件中是不可能的。良好的代码实践建议文件应该保持短小并且具有良好的组织结构。手工编译每个源代码文件可能是一个令人厌倦并且极易出错的过程。一定有更好的办法。

CMake 是什么?

假设我们通过编写一个脚本来自动化构建,该脚本遍历我们的项目树并编译所有内容。为了避免任何不必要的编译,我们的脚本将检测源代码在上次运行之后是否被修改过。现在,我们想要一种方便的方式来管理每个文件传递给编译器的参数——最好是我们希望根据可配置的标准来做。此外,我们的脚本应该知道如何以二进制形式链接所有已编译的文件,或者更好的是,如何构建可以在更大的项目中重用并作为模块合并的整体解决方案。

我们添加的特性越多,就越有可能得到一个成熟的解决方案。构建软件是一个通用的过程,可以包括许多不同的方面:

  • 编译成可执行文件和库
  • 依赖管理
  • 测试
  • 安装
  • 打包
  • 生成文档
  • 更多的测试

要想出一个真正模块化的、功能强大的、适合各种用途的 C++ 构建应用程序,需要很长时间。但确实有人确实做到了。Kitware 的 Bill Hoffman 在 20 多年前实现了 CMake 的第一个版本。如你所料,它非常地成功。它现在已经有很多功能并且得到了来自社区的支持。今天,CMake 正在被积极地开发,并且已经成为 C 和 C++ 程序员的行业标准。

采用自动化方式构建代码的想法比 CMake 出现早得多,所以很自然地,有很多解决方案:Make、Autotools、SCons、Ninja、Premake 等等。但是为什么 CMake 如今独占鳌头呢?

就个人主观而言,我认为 CMake 做到了以下几点:

  • 它专注于支持现代编译器和工具链
  • CMake 真正做到了跨平台——它支持在 Windows、Linux、macOS 和 Cygwin 上构建
  • 它可以为主流的 IDE 软件生成项目文件,如:Microsoft Visual Studio、Xcode 和
    Eclipse CDT。此外,它也是其他软件(如 CLion)的项目模型。
  • CMake 的操作建立在正确的抽象级别上——它允许你在项目中对文件进行分组,并支持目标的可复用性。
  • 有大量的项目是用 CMake 构建的,并提供了一个简单的方法来将它们包含到你的项目中。
  • CMake 将测试、打包和安装作为构建过程的固有部分。
  • 过时的、没用的特性被弃用,以保持 CMake 的精简。

CMake 为构建提供了一个统一而流畅的体验。不管你是在 IDE 中构建软件,还是直接从命令行构建软件;更重要的是,它也照顾到后期的构建阶段。即使前面的所有环境都不同,你的持续集成/连续部署(CI/CD) 也可以轻松地使用相同的CMake配置,并使用单一标准构建项目。

CMake 是如何起作用的?

你可能会有这样的印象,CMake 是一个一端读取源代码,另一端生成二进制文件的工具——虽然这在原则上是正确的,但并不是全部。

事实上,CMake 并不能自己构建任何东西——它依赖于系统中的其他工具来执行实际的编译、链接和其他任务。你可以将其视为构建过程的协调者:它知道需要完成哪些步骤,最终目标是什么,以及如何为工作找到合适的工人和材料。

这个过程分为三个阶段:

  • 配置
  • 生成
  • 构建

配置阶段
这个阶段 CMake 会从源代码目录(源码树)下读取一些项目相关的信息,并为生成阶段准备一个输出目录(构建树)。

CMake 首先创建一个空的构建树,并收集有关它工作环境的所有信息,例如:计算机体系结构、可用的编译器、链接器和归档器。此外,它检查一个简单的测试程序是否可以被正确编译。

接下来,CMakeLists.txt 项目配置文件被解析并执行(是的,CMake 项目是用 CMake 的编码语言配置的)。这个文件是一个 CMake 项目的最低限度(源代码文件可以稍后添加)。它告诉 CMake 关于项目结构、目标和依赖项(库和其他 CMake 包)的信息。在此过程中,CMake 将收集到的信息存储在构建树中,例如:系统详细信息、项目配置、日志和临时文件,这些将用于下一步。具体来说,它将创建一个 CMakeCache.txt 文件来存储已经确定的变量(例如编译器和其他工具的路径),并在下次配置时节省时间。

生成阶段
读完项目配置之后,CMake 将为当前具体的工作环境生成一个构建系统。构建系统是一个为其他构建工具提供的简要工程模板(例如,GNU 的 Makefile 、Ninja 或者 Visual Studio IDE 的工程文件)。在这个阶段,CMake 仍然可以通过计算生成器表达式对构建配置进行一些最后的修改。

注意:
生成阶段会在配置阶段之后自动执行。由于这个原因,当提到构建系统的“配置”或“生成”时,本书和一些其他资料经常指的是这两个阶段。要想显式地只运行配置阶段,可以使用 cmake-gui 程序。

构建阶段
为了生成项目中指定的最终工件,我们必须运行适当的构建工具。可以通过 IDE 直接调用,或者使用 CMake 命令。接下来,这些构建工具将执行构建步骤,使用编译器、链接器、静态和动态分析工具、测试框架、报告工具和其他任何您能想到的工具来生成目标。

这个解决方案的美妙之处在于,它能够用一个配置(即相同的项目文件)为每个平台按需生成构建系统:
图1.1 - CMake 的各个阶段

还记得在理解基础部分中我们的 hello.cpp 程序吗?使用 CMake 也很容易构建它。只需要加入以下的 CMakeLists.txt 并敲两条简单的命令:cmake -B buildtree 和 cmake --build buildtree,如下所示:


chapter01/01-hello/CMakeLists.txt:CMake 语言中的 Hello world

cmake_minimum_required(VERSION 3.20)
project(Hello)
add_executable(Hello hello.cpp)

下面是 Dockerized Linux 系统的输出(注意,我们将在为不同平台上安装 CMake 部分讨论 Docker):

root@5f81fe44c9bd:/root/examples/chapter01/01-hello# cmake
-B buildtree.
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /root/examples/
chapter01/01-hello/buildtree
root@5f81fe44c9bd:/root/examples/chapter01/01-hello# cmake
--build buildtree/
Scanning dependencies of target Hello
[ 50%] Building CXX object CMakeFiles/Hello.dir/hello.cpp.o
[100%] Linking CXX executable Hello
[100%] Built target Hello

接下来就是运行:

root@68c249f65ce2:~# ./buildtree/Hello
Hello World!

在这里,我们生成了一个 buildtree 目录下的构建系统。在此之后,我们执行构建阶段,并生成我们最终能够运行的二进制文件。

现在你看到了最终的结果,我敢肯定你一定会有很多问题:这个过程的先决条件是什么?这些命令是什么意思?为什么我们需要两个文件?我如何编写我自己的项目文件?不要担心——这些问题将在下面的部分中得到解答。

获取帮助
这本书将为您提供与当前版本的 CMake 相关的最重要的信息(在撰写本书时是3.20)。为了向你提供最好的建议,我故意避免了任何已被弃用和不再被推荐的特性。我强烈建议至少使用 3.15 版本,它被认为是“现代 CMake”。如需要更多信息,你可以在网上找到最新的、完整的官方文档 https://cmake.org/cmake/help/

为不同平台安装 CMake

CMake 是一个用 C++ 编写的跨平台开源软件。
这意味着你完全可以自己编译它,然而,通常没必要。因为你完全可以从官网(https://cmake.org/download/)上下载提前编译好的二进制文件。

类 Unix 系统可以直接通过命令行来获取安装包。

注意
牢记 CMake 不会同编译器一起被提供。如果你的系统还未安装编译器,你需要在使用 CMake 之前提供它,并确保将它的可执行文件路径添加到 PATH 环境变量了以使 CMake 能找到它。
学习本书的过程中,为了避免解决工具和依赖问题,我建议选择第一种安装方法:Docker。

让我们来看看可以使用 CMake 的不同环境。

Docker
Docker(https://www.docker.com/)是一个提供操作系统级虚拟化的跨平台工具,允许应用程序以完整的包(称为容器)的形式发布。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容