首页 > 代码库 > Blade和其他构建工具有什么不同

Blade和其他构建工具有什么不同

大部分人都至少接触过不止一种构建工具,比如make,autotools。而我们开发了Blade,为什么那么多现成的工具不用,而又再造了一个轮子,相对于传统的make等工具,Blade的好处在又哪里呢?你的项目是否适合用Blade来构建,

以前的文档都是冷冰的介绍,今天本文将从作者和开发人员以及项目代码维护者的角度回答这些问题。

 

Blade总的来说要解决这些问题:

真正环境下的C++软件的开发,往往有数十人甚至数百个开发人员,源代码有成千上万个文件,百万甚至千万行。如何高效而安全地构建这些代码?

为了保证代码质量,我们还需要Codereview,代码提交流程,自动检测工具,单元测试,持续集成等现代化的开发流程,如何保证这些流程被实施?
Blade就是为这样的项目而生的。

下面是我分析的Blade的特点:

[构建规则简单]
Blade的构建规则很简单,是说明性而非指令性的,只要描述出源文件以及依赖即可,不需要描述如何构建。我比较过gyp和cmake的构建规则,都不如blade的简洁。

因为描述的是需要什么而不是怎么做,因此不需要开发人员掌握gcc的命令行,更无需记忆make的哪些奇奇怪怪的自动变量,大幅度降低使用门槛。

Blade还直接支持编译 protobuf,lex, yacc, swig 等,不需要自己写构建命令和规则。

[自动依赖分析和传递]
用过Make的都知道,所有的依赖关系要自己维护。我们都知道C/C++语言中的头文件是个很麻烦的事情,
在手工维护的make的依赖规则中,一般只写出.o文件对.c文件的依赖,这样当.c文件所包含的头文件变化时,
不会自动构建,这时候往往是需要做一次make clean然后重新编译,用make维护增量构建的意义大减。
即使写了对头文件的依赖,但是头文件里还会包含头文件,对于这些间接包含的头文件,是多到无法写出的。

而Blade自动分析头文件依赖关系,构建受影响的代码。头文件变化时,所有直接和间接包含它的源文件都会
被自动找出来,进行构建。而不受影响的源文件则无需重复构建,真正实现了增量构建。对于链接也是一样。

对于大的项目,我们往往分成多个库来构建,而且库之间还会有依赖关系,如果用了一个库,在用make的时候,
我们需要在命令行把它依赖的库都列出来,一个都不能少,而且顺序还不能错,否则都会导致链接错误。
更麻烦的是,假如某个库的实现变了,不再增加了一个新的依赖,那么所以用到这个库的地方都需要修改加上这个依赖。
Blade只需要开发人员写出直接依赖,而库的间接依赖是自动分析出来的,构建时也会自动检查所依赖的库是否需要重新构建。

[提高代码可读性]

既然Blade的构建理念是把整个项目看作一个有机的整体,那么头文件和库文件都在这个项目中有唯一的位置,天然不会重复,不怕重名。我多次经历或者见过头文件或者库文件重名,每次都浪费大量的时间。

Blade提倡从项目根目录开始定位文件和库,彻底避免了这样的问题。在这样方式组织代码的项目工作越久,就越能体会到Blade提倡的#include 从根开始写是在保护你而不是在故意为难你,并开始喜欢这种组织方式。

[构建速度优化]
除了上面所说的依赖关系维护消除了clean使得只需要增量构建外,Blade还开启了并行构建,默认多个进程同时构建,提高构建速度。
对于make也不是不可以并行构建,但是由于依赖关系的负责性,更容易出错。
为了进一步提高构建速度,Blade还支持ccache缓存构建结果和distcc分布式构建。

[易用性]
持续集成是代码质量的有效保证。通过持续集成,使代码持续处于可构建状态,大幅度减少了错误,提高了发布和部署的效率。
在做发布和持续集成时,我们常需要一次构建所有的目标,有时候还需要涉及32位64位等多个平台。
用make时一般的做法是用递归make,在上层的makefile里描述出有哪些子目录,并层层递归。这样的缺点是,
底层目录改动需要修改上层的Makefile,再加上库的依赖不能传递,使得makefile维护的大项目经常处于无法完整成功构建的状态。

Blade支持一下子构建整个目录树,并不需要写额外的描述。

对于递归make,两个目录有依赖关系时,依赖者就无法单独构建,需要跑到上层目录,先构建依赖,再构建自己才行。否则可能会用到旧的库。
Blade在代码树的任意子目录下都能构建,其依赖会被自动找出来构建,不多不少,确保正确性。

Blade内置 debug/release 两种构建类型,32/64位两种目标平台。

Blade的构建进度显示被大幅度简化为做了什么而不是在怎么做,减少了make中默认显示出的完整命令行对视觉的干扰。
为了更醒目地发现问题,构建过程中的警告和错误信息是用彩色高亮现实的,一眼就能看到错误提示行。

Blade的命令行接口类似svn,由一系列子命令,目标名和参数组成,简单好记忆,还支持bash风格的命令行补全,按tab键自动补全命令行。

[方便部署]

在我看来动态库就是灾难,见过不少依赖dlopen加载的库/框架,有的还支持热卸载,甚至想在同一个进程中加载不同版本的两个库来做对比测试,这样的项目无不bug不断,开发人员痛苦不堪。

因此Blade提倡静态链接,默认甚至把libstdc++和libgcc都静态链接到了可执行文件。发布时一个可执行文件就搞定(可能还需要一些配置文件,数据文件等)。省时省心。

[测试支持]
单元测试是代码质量的重要保证,可以把大量的低级错误消灭在萌芽状态,并提高代码的可维护性,降低开发成本。
用make的时候,一般是写一些可执行文件类型的目标,构建出来后,在人工运行它,没有任何机制保证这些测试会被运行。
如果测试写了不运行就等于白写,Blade直接支持类型为测试的目标类型,只需要描述哪些目标是是测试即可。Blade支持命令行批量执行这些测试。
因此运行测试可以由开发人员主动进行,也可以通过开发流程工具,在代码发起review或者提交前运行,以及持续集成时运行,使得测试真正做起来。
为了提高测试效率,自动支持多个测试进程并发运行,支持增量测试(自动跳过最后一次是成功且没有新的变化的测试程序)。
为了检查内存泄露,测试集成 gperftools,自动检测测试程序的内存泄露,使得大部分内存泄露可以在单元测试时发现。

 

最后总结一下,Blade是为了减轻大规模C++项目的维护成本,提高开发效率和质量而生的现代化构建工具。

Blade和其他构建工具有什么不同