C++工程中常用的构建系统(Build System)

Build System是一个技术挑战很高的工作。但是其难度往往被低估。同时,程序员有一大部分工作时间花在和build system打交道,所以build system的好用程度极大地影响团队和公司的工作效率,进而影响业务发展。--摘自《寻找Google的Blaze》
  • 什么是构建系统?为什么需要构建系统?
    • 构建系统(build system)是用来从源代码生成用户可以使用的目标(targets)的自动化工具。目标可以包括库、可执行文件、或者生成的脚本等等。
    • 构建系统的需求是随着软件规模的增大而提出的。如果只是做软件编程训练,通常代码量比较小,编写的源代码只有几个文件。比如你编写了一段代码放入helloworld.c文件中,要编译这段代码,只需要执行以下命令:gcc helloworld.c
    • 当软件规模逐渐增加,这时可能有几十个源代码文件,而且有了模块划分,有的要编译成静态库,有的要编译成动态库,最后链接成可执行代码,这时命令行方式就捉襟见肘,需要一个构建系统。常见的构建系统有GNU Make。需要注意的是,构建系统并不是取代gcc这样的工具链,而是定义编译规则,最终还是会调用工具链编译代码。
    • 当软件规模进一步扩大,特别是有多平台支持需求的时候,编写GNU Makefile将是一件繁琐和乏味的事情,而且极容易出错。这时就出现了生成Makefile的工具,比如CMake、AutoMake等等,这种构建系统称作元构建系统(Meta-Build System)。
  • 常见的构建系统(Build System)

迄今为止C++至少有89种构建系统,这里笔者主要介绍一些大家日常工作中会接触到的构建系统工具。

    • Make(GNU Make,BSD Make):Make可以追溯到1976年,属于最早的构建系统,在类Unix系统上比较常用。在类Unix系统上,大多数C++的项目代码是通过编写或生成Makefile进行编译构建的。Makefile早期设计是给研发者编写的构建脚本,功能强大有很多高级功能。

问题:1. 直接编写Makefile,复杂且难以阅读,维护困难;项目规模比较大的C++项目尤甚。

2. 构建速度相对较慢。笔者常常听人提到“CMake编译速度慢”,CMake表示“这锅我不背”,CMake默认的Build Backend是Make。

    • Ninja:Google的一名程序员推出的注重速度的构建工具,是一个专注于速度的小型构建系统。最初是为了对Chromium、Swift等进行快速编译构建,用来替代GNU Make。设计哲学是通过包含描述依赖关系图的方式提供快速的构建。一般作为元构建系统工具的Build Backend。
    • Bazel:Bazel是Google内部构建系统Blaze的子集。很久以前,Google使用大的,生成的Makefile来构建软件。这导致构建的速度慢而且不可靠,开始干扰开发人员的生产率和公司的敏捷度。因此,Google工程师创造了Bazel。Bazel优点很明显,缺点也很致命,并不适合大多数公司。考虑到部分同事是bazel的拥趸,笔者这里并不多讲,具体参阅下面的链接《寻找Google的Blaze》和《为什么google bazel构建工具流行不起来》。
    • Scons:Scons是一个Python写的自动化构建工具,从构建这个角度说,它跟GNU Make是同一类的工具。它是一种改进,并跨平台的GNU Make替代工具,其集成功能类似于autoconf/automake 。Scons自动配置功能弱(跨平台能力不足),构建速度慢。
    • Boost.Build(b2):在编译Boost库的时候,会用到b2命令,其实就是Boost.Build的缩写。编译C++/C代码时,只需要指定要编译那些可执行文件或库,然后列出相关的源码,Boost.Build帮你搞定其他事情,支持Windows、OSX、Linux和商业的Unix系统。笔者只在编译Boost库时用过这个构建系统,现在Boost已经全面转向CMake了。
  • 元构建系统(Meta-Build System)
Meta-Build System: a build system that generates other build systems。一个生成其他构建系统的构建系统。 如:cmake+make, cmake+ninja,gn+ninja
    • CMake:CMake是Kitware公司为了解决ITK软件跨平台构建的需求而设计出来的,后来VTK也用上了CMake。CMake是一个元构建系统工具,支持多种语言,多种Build Backend(Make,Ninjia,Visual Studio,Xcode等)。有人说:
The true successor of Make. I have been raving about CMake in a series of previous blog posts. incredibuild.com/blog/t
不管CMake是否是一个优秀的构建工具,不管你是否认同 CMake,都无法否认 CMake 目前是 C++ 的 de facto build system。所以在社区以及生态的影响下,使用 CMake 作为构建工具的项目会越来越多。一个佐证是,即使是微软、Google 以及 Facebook 这三家公司都有自己的 C++ 构建系统,他们开源的项目仍支持使用 CMake 构建;并且 CMake 是除了官方构建系统之外的推荐构建系统。

Visual Studio,Android Stuido,QT6,Intel TBB和Boost全面转向CMake,众多的开源代码用户,CMake目前是C++的de facto build system。

CMake已经这么成功了,笔者就说一说CMake的一些不足之处:

      • 本身不支持增量编译和云编译(相比bazel):笔者并不认为这是CMake的不足,毕竟工具的定位不同,bazel早期定位是为构建服务端软件设计的。事实上C++已经有了很成熟的增量编译工具ccache和sccache,分布式编译工具distcc和icecc。就编译速度而言,cmake+ninja+ccache就足以超过bazel。cmake从3.16版本开始又增加了一 些其他的编译加速手段;具体笔者将会在下期《编译加速极致之道》中详细介绍。
      • CMake语法过于灵活和强大:优点是它,缺点也是它。灵活的语法用好了能够发挥CMake应有的威力,用不好就是灾难。事实上很多初学者没能掌握CMake的正确用法,在项目中滥用CMake语法,造成项目一塌糊涂,然后归罪于CMake(谁让你设计这么灵活呢)。这时候就需要在项目规范CMake的用法,在团队中多加培训。 题外话:笔者并不是CMake的铁杆粉丝,笔者实际上更愿意用XMake。
    • Blade:腾讯开源构建系统,Tecent“台风”云计算平台开发过程中。为了解决 GNU Make,Autotools 的难用和繁琐的问题,开发了Blade。GitHub - chen3feng/blade-build: Blade is a powerful build system from Tencent, supports many mainstr
    • GYP (Generate Your Projects):早期Chromium开源项目采用的是GYP构建系统,这也是一种元构建系统。Google工程师根据GYP规则编写构建工程文件(通常以gyp, gypi为后缀),GYP工具根据gyp文件生成GNU Makefile。接着Chromium项目又整出了Ninja构建系统,但这个Ninja并不是用来取代GYP的,而是取代GNU Make的,据谷歌官方的说法是速度有了好几倍的提升。
    • GN (Generate Ninja):GN文件相当于GYP文件的下一代,和GYP差别不大,但是总体上比原来的GYP文件更清晰。
    • GNU Autotools (Autoconf,Automake和libtool)

Autoconf:用于为工程产生配置脚本;

Automake:用于简化创建一致性和功能性Makefile的过程;

Libtools:用于为共享库的可移植创建提供一个抽象;

  • 其他的构建系统(Others)
    • XMake:XMake是一个基于Lua的轻量级跨平台自动构建工具,支持在各种主流平台上构建项目。国人开发的,已经很接近CMake了,同时具备CMake和Bazel的优点,外加包管理功能。学习成本低,使用起来远比CMake和Bazel等DSL语言简单。奈何起步太晚,没有经过众多大型项目的检验,很多坑还没有被踩过填上,不敢轻易用在大型C++工程中。

XMake = Build Backend + Project Generator + Package Manager+ [Remote|Distributed] Build + Cache.

    • Microsoft NMake,MSbuild,Visual Studio系列:NMake是Windows下的make实现,是Visual Studio的一部分,Visual Studio随附的命令行build工具(现已被MSBuild代替)。MSbuild和NMake是微软旗下的两种构建系统工具,MSBuild是“后起之秀”。在Visual Studio2013之前,MSBuild是作为.NET框架的一部分,但是在其之后,MSBuild被绑定到了Visual Studio。所以,Visual Studio依赖于MSBuild,但是MSBuild并不依赖于Visual Studio。
    • QMake:QT自带的构建工具,用过QT的人应该比较清楚。题外话:笔者在之前公司曾主推过将QT项目中的QMake脚本全部转换成CMake,当时主要考虑到方便QT项目能够复用构建框架管理的基础功能代码。当时项目中用的还是QT5,没想到QT团队在QT6产品中直接弃用自己研发的QMake,全面转向CMake。想当初笔者提出这一想法时并不是每个人都赞同,幸得时任CTO的支持完成了这一规划。现在回头看来,竟领先QT团队一步。
    • XCode:Mac OS X上的集成开发工具(IDE)。
    • 其他的诸如Meson,Premake,FMake,Fastbuild,Waf等等太多了。
C++开源构建系统排名
CMake Build Backend

cppcon.org/class-2019-c

大型C++工程的构建技术:Modern CMake vs Bazel

寻找 Google Blaze

为什么google bazel构建工具流行不起来 - 生栋 - 博客园

Google软件构建工具Bazel FAQ - 生栋 - 博客园

slant.co/topics/4263/~o

cmake.org/cmake/help/la

Blade - 腾讯开源的构建系统 c/c++编译环境 - zhchoutai - 博客园

编辑于 2022-10-06 15:15