Facebook Buck 和 xctool:针对 Android 和 iOS 的开源构建工具

  • Abel Avram
  • 侯伯薇

2013 年 5 月 19 日

话题:开源FacebookAndroidiOS语言 & 开发

本文包含了最新发布的Buckxctool的细节,这是两种 Facebook 内部用于本地 Android 和 iOS 应用程序的构建工具。

Buck

Facebook 最近开源了他们用于构建本地 Android 应用程序的工具Buck。Buck 受到了Google Blaze的启发,创建它是为了处理与多个 Android 库有复杂关联的应用程序,从而减少构建时间。引入 Buck 之后,Facebook 开发的四种本地 Android 应用程序中使用了单一的代码树和构建工具,这让开发更简单、更流畅,错误更少。最初的 38 个库在四种应用程序之间共享了 500 个模块。使用 Buck 替换了最初基于 Ant 的系统之后,第一次针对代码树运行时,构建时间就从 3 分 40 秒降到 1 分 30 秒。

Buck 是用 Java 编写的,而构建规则最初是用 Python 定义的,后来为了更快的规则评估而采用了 Jython。工具现在被用于构建 Android Java 代码,但是团队正在努力使其支持构建纯粹的 Java 代码,而与 Android 无关,它可能会扩展到构建 Python 项目,可能还会支持其他类型的项目。

Facebook 的 Android 代码是以树的形式组织的,其中独立的子树构成了有向无环图,支持与各种不同子树相关的构建规则的并行执行,从而减少了构建时间。包含规则的构建文件分布在代码树中,每个文件针对一个已存在的 Android 模块。只有模块中的文件有变化时,构建文件才会执行,而这些构建可以并行执行。据 Buck 的创造者 Michael Bolin 所说,把并行能力设置为八个线程,会把单元测试的时间从 20 分钟降低到 4 分钟。他在DevCon New York 2013 的话题中详细描述了构建系统。

Buck 知道如何处理文件的多个版本,正如Bolin 在 G+ 的一个话题中说明的:

在构建 Android 应用时,另一个困难的问题是生成 R.java 文件。如果不探究太多细节,你可能会构建多个 Android 应用,它们的 Java 文件依赖于同一个名为 R 的类。对于普通的 Java 类,你可能会编译一次,然后任意数量的其他 Java 类都可以依赖它。然而,在 Android 中,你需要编译的 R 的版本依赖于 Android 应用,其中编译的 Java 代码最终会被包含在内。为你构建的每种 Android 应用都编译 Java 代码的不同版本,效率会很低,所以 Buck 使用了一些聪明的技巧(为编译时而不是运行时创建不同的 R.java 文件),从而减少重复编译。

在不久的将来,团队准备增加一个后台程序,它会监控文件的编辑情况,一旦发现就会立即开始构建。

Buck 运行在 Mac OS 和 Linux 平台上,团队正在考虑把它也移植到 Windows上。

Gerrit的创建者 Shawn Pearce建议使用 Buck替换 Maven,他提到了速度以及其他几种原因:

buck: clean: 0.452s, full 1m21.083s [*], no-op: 7.145s,

maven: clean: 4.596s, full 2m53.776s, no-op: 59.108s,

[*] 完整构建包括下载所有依赖,时间可能会因为远程服务器的性能差别而不同。

Pearce 还指出 Buck 的一些缺点:

- 不支持 Windows

- 没有本地的 Maven Central 支持(通过宏)

- 没有本地的 GWT、Prolog 和 WAR 支持(通过宏)

- Buck 的引导程序需要 Ant

xctool

xctool是 Facebook 最近开源的另一种构建工具,它用于构建 iOS 应用程序。xctool 替换了xcodebuild,具有以下特性:

  • 能够作为 Xcode.app 运行相同的测试
  • 构建输出和测试结果都是 JSON 格式的,使得我们不需要解析输出
  • xctool 只有在发现错误的时候才打印消息,而 xcodebuild 对每个源文件都会打印。

我们想要知道为什么 Facebook 基于 xcodebuild 构建了另一种工具,所以采访了 xctool 的提交者Fred Potter,询问他为什么这个工具更好一些:

xctool 的最大好处在于,它可以从命令行构建和运行单元测试,这和 Xcode.app 从图形化界面上达到一样的效果。如果你为 iOS 设置了持续集成系统,那么这就非常重要了。你想要能够自动化运行测试,那些测试与你的开发人员在本地计算机上运行的完全相同,而 xcodebuild 不会用和 Xcode.app 相同的方式来构建和运行测试。在 Xcode 4 中,苹果把单元测试集成到了 Xcode 中——与“构建”和“运行”一起,有一个新的“测试”动作;使用 Xcode scheme,你可以选择启用或者禁用哪些单元测试;如果你依赖于 iOS 模拟器(也就是应用程序测试)来编写测试,那么 Xcode 会自动载入模拟器并运行测试。这些都是很大的改进,但看起来苹果并没有把这些改进融入到 xcodebuild 中,那使得自动化构建和测试非常困难。

另一个重大的问题是构建和测试失败的报告。使用 xcodebuild,你会得到大量文本输出,其中包含编译命令、编译错误和警告以及 OCUnit 的测试输出。如果你想要自动确定哪个组件编译失败,或者哪个单元测试失败,那么你就需要编写自己的正则表达式解析器,那也是我们和其他 iOS 社区中的人一直在做的工作。那会有效果,但实在很麻烦。有了 xctool,我们会让 xcodebuild 和 OCUnit 测试运行器把构建输出和测试结果作为 JSON 对象的结构化流输出。 这让我们可以很容易地以需要的形式来显示构建和测试结果。例如,我们创建了一个报表,以吸引人的、带有颜色的输出形式来显示结果(https://fpotter_public.s3.amazonaws.com/xctool-uicatalog.gif)。 还有人使用这来把测试结果输出为 JUnit XML,那在流行的 Jenkins 构建系统中会显示得很好。

所以,我们最初创建 xctool 只是为了持续集成系统,但很多开发者最后都在本地计算机上使用它。如果你想要为运行测试拥有命令行的工作流,它会非常方便。

查看英文原文:Facebook Buck and xctool: Open Source Build Tools for Android and iOS

开源FacebookAndroidiOS语言 & 开发