Buildcache 让 Firefox 构建速度提升 17%,编辑 - 编译 - 测试循环大大改善!
2026/4/14 20:46:12 网站建设 项目流程

如何让 Firefox 构建速度提升 17%?

2026 年 4 月 10 日,在之前的文章中提到,与 ccache 和 sccache 相比,buildcache 有独特特性,其 Lua 插件系统可编写自定义包装器。随着 Bug 2027655 合并,可利用此特性缓存 Firefox 的 WebIDL 绑定代码生成过程。

WebIDL 步骤是什么?

构建 Firefox 时,早期步骤之一是运行 `python3 -m mozbuild.action.webidl`,从 `.webidl` 文件生成 C++ 绑定代码,会生成数千个输出文件。此步骤本身不慢,但每次完全重建都会运行,且输入相同输出确定,是缓存的理想选择。不过,编译器缓存从未应用到这一步骤,Buildcache 之前仅包装实际编译器调用,不涉及 Python 代码生成过程。

改进之处

Bug 2027655 中的修复很简单。在 `dom/bindings/Makefile.in` 中,有条件地将 `$(CCACHE)` 作为命令包装器传递给 `py_action` 调用。`config/makefiles/functions.mk` 中的 `py_action` 宏用于运行 Python 构建操作,此 Bug 还引入将命令包装器作为第四个参数传递的功能。当 buildcache 被配置为编译器缓存时,webidl 操作将以 `buildcache python3 -m mozbuild.action.webidl ...` 形式调用,这样 buildcache 就能拦截该操作。注意 `ifdef MOZ_USING_BUILDCACHE` 这个条件判断,这是 buildcache 特有的,因为 ccache 和 sccache 没有缓存任意命令的机制,而 buildcache 可以通过其 Lua 包装器实现。

Lua 包装器

Buildcache 的 Lua 插件系统允许编写脚本处理本身不理解的程序。WebIDL 代码生成的包装器 `webidl.lua` 需要为 buildcache 解答几个问题:能否处理这个命令,通过匹配参数列表中的 `mozbuild.action.webidl` 判断;输入有哪些,包括所有 `.webidl` 源文件以及 Python 代码生成脚本,信息来自 `file-lists.json` 和 `codegen.json`;输出有哪些,包括所有生成的绑定头文件、cpp 文件、事件文件以及代码生成状态文件,同样从 `file-lists.json` 中获取。有了这些信息,buildcache 可以对输入进行哈希处理,检查缓存,然后要么重放缓存的输出,要么运行实际命令并存储结果。该包装器使用了 buildcache 的 `direct_mode` 功能,直接对输入文件进行哈希处理,不依赖预处理输出,这在这里是合适的,因为处理的是读取 `.webidl` 文件的 Python 脚本。

数据对比

以下是在 Linux 上使用 `./mach build` 进行构建的时间,对比了不同的编译器缓存工具。每行显示了一次清空缓存的完全重建(冷启动),以及一次缓存已填充的完全重建(热启动):

| 工具 | 冷启动 | 热启动 | 使用插件 |

| --- | --- | --- | --- |

| 无 | 5 分 35 秒 | 无 | 无 |

| ccache | 5 分 42 秒 | 3 分 21 秒 | 无 |

| sccache | 9 分 38 秒 | 2 分 49 秒 | 无 |

| buildcache | 5 分 43 秒 | 1 分 27 秒 | 1 分 12 秒 |

“使用插件” 列是启用了 `webidl.lua` 包装器的 buildcache,它又节省了 15 秒,使总时间降至 1 分 12 秒。这展示了这种机制的有效性,WebIDL 步骤只是第一个采用这种处理方式的 Python 操作,构建过程中还有其他代码生成步骤也能从相同的方法中受益。更广泛地说,这些数据表明 buildcache 在热启动构建方面表现出色,从 5 分 35 秒的全新构建到 1 分 12 秒的缓存重建,大大改善了编辑 - 编译 - 测试的循环过程。这些只是在一台机器上的单次运行结果,并非严格的基准测试,但趋势已经很明显。

设置方法

如果已经在 `mach` 中使用 buildcache,更新到最新的中央版本后,Makefile 的更改就会生效。要启用 Lua 包装器,克隆 `buildcache-wrappers` 仓库,并通过 `~/.buildcache/config.json` 中的 `lua_paths` 指向它:

```json

{

"lua_paths": ["/path/to/buildcache-wrappers/mozilla"],

"max_cache_size": 10737418240,

"max_local_entry_size": 2684354560

}

```

或者,也可以设置 `BUILDCACHE_LUA_PATH` 环境变量,一个方便的设置位置是在 mozconfig 中:

```makefile

mk_add_options "export BUILDCACHE_LUA_PATH=/path/to/buildcache-wrappers/mozilla/"

```

较大的 `max_local_entry_size`(2.5 GB)是必要的,因为一些 Rust 包会生成非常大的缓存条目。

下一步计划

这里有趣的部分是 Lua 插件系统。WebIDL 包装器只是一个概念验证,但同样的技术适用于任何具有已知输入和输出的确定性构建步骤。Firefox 构建中还有其他代码生成操作也可以采用相同的处理方式,接下来打算探索这些操作。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询