RFC-0153:为 Fuchsia 自定义 Ninja

RFC-0153:Ninja 自定义(紫红色)
状态已接受
领域
  • 构建
说明

提议使用适用于 Fuchsia 的 Ninja 构建工具的定制版本来加快构建速度、改善状态报告和易用性。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2022-01-22
审核日期(年-月-日)2022-03-17

摘要

此 RFC 会建议使用开源的临时自定义版本 用于 Fuchsia 平台 build 的 Ninja 工具, 集成了几个现有的第三方补丁,这些补丁可显著提高 性能和易用性,以及上游维护人员 无法接受 动机部分。

具体而言,这样做可以:

  • 通过优化时间安排,显著缩短总构建时间 Ninja 使用的算法。

  • 改进状态报告和记录,并解决 严重的易用性问题 触发器类型

  • 在不使用的情况下,提高 Ninja 的响应速度和一般性能 更改其行为。例如,通过提升某些忍者的速度 22 倍。

  • 基于上述改进,可显著加快 构建系统和 IDE(例如 Visual Studio Code 和 Vim), 可以在极短时间内重新生成 IDE 绑定,并且 提供出色的交互式代码编辑体验。

您可以通过在 git 目录中维护一个自定义 git 分支来实现自定义 https://fuchsia.googlesource.com/third_party/ninja,该域名将受管理 使用严谨跟踪的分支策略 并在上游传输,并通过 在最近的上游历史记录顶部显示。

该实验性分支的现状将于 2022 年第 3 季度修订,因为 我们计划帮助上游维护者接受感兴趣的拉取请求, 但这些因素所依赖的许多外部因素超出了此 RFC 的讨论范围。 预计到那时,自定义分支将不再是 所需的资源。

设计初衷

Ninja 构建工具由 Google 的 Evan Martin 开发, 为 Chrome 浏览器工作时进行的一项实验 1。 实验取得成功,并成为了非常有用的工具, Chrome 官方版本,并且是开源的。然后,它很快就被选中了 由许多其他构建配置工具或系统开发 其中包括:

  • GN 构建工具,现在供 Chrome、Fuchsia 和 Pigweed 项目使用。
  • Android 项目使用的 Blueprint 和 Kati 工具。
  • CMake 构建生成器,支持将 Ninja 作为后端。
  • Meson 构建系统,被许多 Linux 开源项目使用。
  • 开发者可以使用 CMake 或 GN 构建 LLVM, 包括为 LLVM 做贡献的 Fuchsia 团队成员。

目前,全球有数以千计的开发者在使用 Ninja, 并在 GitHub 上作为开源项目进行维护。忍者的维护人员 尽量确保项目能够始终如一地践行最初的 小巧、简单、可靠且极为可移植

由于多种原因,上游 Ninja 项目的进展仍然 但有大量感兴趣的拉取请求 可能需要几个月甚至几年才能进行审核。当前维护者 但遗憾的是,这大多数是 因为没有时间正确审核和测试重要更改, 这也是回归测试套件状态的结果, 目前非常基本,在许多情况下需要对拉取请求进行手动测试。 该维护人员首先也会希望获得任何帮助来提升该测试的效果 以方便和加速 Ninja 的维护工作 和进化。例如,他不是反对将代码库从 C++03 到 C++11,但前提是能保证代码可编译和运行 可以在较旧的发行版(即 Centos 7、Debian 8、Ubuntu 18.04 和 OSX 10.12)使用其默认工具链,并由适当的连续 集成验证。

遗憾的是,该网页上有大量阻止问题 而要解决这些问题,就需要进行大量的工作, Fuchsia 构建团队目前还无法实现这一目标。

这份 RFC 提供了一项技术提案,可临时解决此问题 即使我们非常希望 致力于与上游合作解决这一问题 。此类头部数量可能来自 Fuchsia 项目, 的努力,以及曾表示对 Ninja 的 未来的发展和改进。但是,资助此类工作不在服务范围内 。

同时,Ninja 的自定义分支可让您择优挑选 影响最大的拉取请求,为 Fuchsia 开发者带来最大的好处。 为了确保此分支尽可能靠近上游, 严厉的分支策略的执行,以确保 Fuchsia 分支始终可以表现为顶部的一系列图块, 近期的上游版本

请注意,这种情况与 偏离上游的自定义 Android Ninja 分支 自创立以来,这显著增加,并且缺乏 Fuchsia 所需的功能 build。

触发此 RFC 的最有趣的拉取请求包括:

使用更好的调度算法加快构建速度

三个开放的拉取请求有可能缩短 重要性。它们都改变了 Ninja 接收新指令的方式, 根据不同的条件发布:

  • PR 2019:为待复制的命令分配优先级 发布,使用构建日志来估算其时长。作者声称 这样可以缩短大型构建项目的构建时间 20 到 15 分钟!

  • PR 1949:限制生成新命令 以免达到负载限制饱和。这样可以避免构建 争用同一个 CPU 的进程过多 资源。作者声称,可以将测试 build 从 22 分钟缩短到 15 分钟 可能性会受到影响

  • PR 1140:为 Ninja 添加支持, GNU Make jobserver,供 Ninja 和 来协调其 CPU 进程分配。 这来自 Ninja 的 Kitware 分支。请注意 之前的公共关系。作者未发布任何时间,不太可能 非常有用,因为它需要调用的程序来明确支持此操作。

修复了长命令的 Ninja 构建输出问题。

在构建期间,Ninja 仅输出 已完成。实际上,如果一个长时间运行的命令导致构建停止 然后:

  • 如果命令超时(因为在非常 Rust 链接命令中,输出或 通过忍者日志文件来说明哪个目标/命令实际已过期!

  • 在终端上,单行状态似乎已冻结,并且仍然显示 最后一个完成的目标的名称, 令人困惑 (许多开发者认为这是导致延迟的根本原因)。只有 使用“ps”命令但在另一个终端上, 人们都知道这一点

第一点是 Fuchsia build 的问题, 不经修改 Ninja 无法解决的问题其次是易用性 多年来一直困扰用户的烦恼,甚至困扰着用户 存在多个拉取请求以不同的方式进行修复:

这是由于 Ninja 的输出是基于文本的 格式受限,其中还包括任意命令输出,以防出现以下情况 错误。这会造成各种细微问题, 并且会导致输出难以可靠地解析

事实上,当前行为是刻意引入的 来解决 Ninja 的 build 输出无法通过机器解析。 因此,对输出格式的任何更改都被认为 上游。

不过,在 Fuchsia 环境中,解析 Ninja 输出由 Fuchsia 基础设施团队控制, 如果可以完全解决问题,则输出格式非常合理。

序列化状态更新,可更好地过滤日志

Android 自定义的另一个有趣功能是 输出限制,这会将状态更新发送到外部 “frontend”结构化二进制数据流。

这使得 Android 团队可以使用 不同级别的日志记录,将错误消息收集到单独的文件中, 还可以生成准确的构建跟踪记录 chrome://tracing.

对于 Fuchsia 版本,应该可以从 Android 分支可获得同样的益处。

请注意,这是作为拉取请求提出的,但在经过一段时间后被拒绝 进行长时间的 讨论,其中上游认为 解决输出解析问题的更好方法是 把 Ninja 变成一个图书馆比原来更大 (有人尝试使用 需要 120 次提交的实验性 PR)。

改善了开发者体验

Android 分支以极快的速度(高达 22 倍)实现了对 Ninja 输入文件,利用线程解析输入的分块, 在适当的词元边界内确定,并在最终传递中合并广告。

这是因为,Android 构建工具 1.2 GiB 的 Ninja 构建计划,在执行任何操作之前需要 12 秒进行解析 (在具有热文件系统缓存的强大工作站上)。

遗憾的是,Fuchsia build 遇到了类似的情况, 目前大约有 800 MiB 的 Ninja 构建计划,解析过程最多需要 10 秒, 这会让增量构建的体验变得令人厌烦。Fuchsia 构建团队 认为这些改进具有显著的意义,应当集成到 build 使用的 Ninja 版本。

编写代码时,编译器错误消息和警告是 向开发者提供反馈。在静态语言和 在 Rust 等新语言中更加真实, 各种各样的条件。因此,收集反馈的时间 对开发者的工作效率至关重要。等待编译器的每一秒 开发者需要花一秒时间来猜测其代码是否正确 或被其他内容分散注意力的风险,快速反馈是 对于仍在学习语言的程序员来说尤其重要。

最高效的环境会在开发过程中即时获得反馈 保存文件的状态。这种“心流”的感觉非常重要 Fuchsia 开发者创建了一些工具,使他们可以使用完全 不同构建系统、cargo 来获得快速反馈和测试周期。 尽管此工具不受支持,但有些开发者仍在使用它 并且非常规律地中断

对于 Fuchsia,每次调用开始时 Ninja 最多用时 10 秒 来解析自己的 build 文件(build.ninja 文件和其他 )。这个下限会限制我们的广告投放速度 而且至少比我们今天能提供的货物要慢 25 倍。 与其他工具工作流相结合,将解析时间缩短 25-100 倍 于本季度开始推行后,我们就可以利用在 Google Cloud 上 紫红色的花朵,出自“在黑板上的蜗牛慢慢”即“轻快灵敏”。通过 将加快开发周期、提高工程师满意度,以及 优质软件

下面是当前代码更改体验的屏幕截图 并在 IDE 中查看编译错误。

显示 IDE 反馈缓慢的屏幕截图

开发者反馈的延迟几乎完全是因为 Ninja 解析文件所用的时间与下面的 IDE 体验演示进行比较 这一切都可以通过安装了补丁的忍者完成。

显示快速 IDE 反馈的屏幕截图

同样,创建 fx setup-go 是为了专门使用 Go 构建系统 正是因为使用 Ninja 进行增量构建 运行速度太慢

请注意,Android 团队在 2019 年提出了这一确切功能, 当时已被上游维护人员拒绝, C++11,尚不能接受。自那时起已过去的时间 则可以考虑进行此类切换,并获得 系统还会强制执行动机部分。

改进了界面

以下 PR 提交以在交互式终端中实现表状状态输出, 灵感源自 Buck 构建系统(请参见 动画示例)。

公关被作者放弃,但可以重新改编, 在本地构建 Fuchsia 时会得到很好的界面改进。

利益相关方

教员

FEC 任命 pascallouis@google.com 来指导此 RFC 。

审核者

shayba@google.com、构建 maruel@google.com,Fuchsia Platform EngProd abarth@google.com,平台主管

之前积极参与此方面的对话的其他团队成员 主题:

brettw@google.com(作为 Fuchsia Tools 贡献者)。 fangism@google.com、构建 haowei@google.com,适用于 Fuchsia 的 LLVM jayzhuang@google.com,构建 olivernewman@google.com, Fuchsia CI phosek@google.com、Fuchsia 工具链

已咨询

fangism@google.com、构建 jayzhuang@google.com,构建 tmandry@google.com、Rust on Fuchsia rudymathu@google.com、Fuchsia EngProd

社交化

这个想法最初是由 Fuchsia 团队 Rust 的 Tmandry 提出的,后来 在 Google 内部电子邮件会话串中进行了社交,现在 以供进一步讨论和审批。

设计

将使用 Fuchsia 控制的 Git 代码库来复刻上游 Ninja master 分支,用于管理包含 Fuchsia 专属的分支 自定义,同时跟踪上游 origin/master。补丁将 由分支机构的所有者审核,并应被视为 视具体情况而定:

  • 提供的福利
  • 补丁的可维护性
  • 偏离上游,会影响可维护性。

以及所有者认为合适的其他条件。

本地修改列表将以 FUCHSIA.readme 标准做法

该分支的维护人员将是 Fuchsia Build 团队, 对 Fuchsia 构建系统及其正确性负责, 可维护性和性能

此 RFC 的目的是确保该分支不会 与使上游更改难以集成的地步不同。 为此,可采用以下策略:

保持 Fuchsia 分支靠近上游的策略

Fuchsia Ninja 分支应保持严厉,这意味着要 因此,我们会定期创建 "usptream-sync"这些分支将我们的更改表示为 在最新的上游版本的基础上构建了补丁。一些图片应该会对您有所帮助 理解这里的含义。

创建自定义 Git 分支时,通常需要在最上层创建新的分支 现有上游版本的映像,该新版本会添加新的提交内容。以下图形 它说明了“上游”CANNOT TRANSLATE 分支,上面添加了 3 项提交:

upstream  ___U1__U2___
                      \
fuchsia                \__F1__F2__F3

提交由其维护者添加到上游项目。上游和 紫红色历史已经有所不同,例如:

upstream  ___U1__U2______U3__U4__U5
                      \
fuchsia                \__F1__F2__F3

将上游更改导入 fuchsia 分支的一个简单方法是执行 合并操作,这可能会导致需要 可视为:

upstream  ___U1__U2______U3__U4___U5___
                      \                \
fuchsia                \__F1__F2__F3____\F4__

其中 F4 表示合并提交。现在叫“紫红色”分支包含 进行了一些改进,但是不能再以序列的形式来表示 基于上游最新版本(即 U5)的补丁。

为了实现此目标,可以避免直接将上游合并到 紫红色分支而是要创建一个 fuchsia 分支的副本, 在 U5 的基础上进行 rebase 操作,从而解决过程中出现的任何冲突(这可以在 先执行 git rebase 操作在本地)。我们将这个分支称为 upstream-sync-U5 如下所示:

upstream  ___U1__U2______U3__U4__U5
                      \            \
upstream-sync-U5       \            \__F1'__F2'__F3'
                        \
fuchsia                  \__F1__F2__F3

fuchsiaupstream-sync-U5 在功能上应等效, 此时(通过测试强制执行),新提交的内容 F1' 到 F3'甚至可能等同于 F1 到 F3,除非必须 已解决。

现在可以将后者合并为前者(解决任何 只需从 upstream-sync-U5 中获取更改,即可实现冲突,如下所示:

upstream  ___U1__U2______U3__U4__U5
                      \            \
upstream-sync-U5       \            \__F1'__F2'__F3'
                        \                           \
fuchsia                  \__F1__F2__F3_______________\F4

稍后,在与其他上游更改同步时,可以重复此操作,因为 位置:

upstream  ___U1__U2______U3__U4__U5__________________U6__U7
                      \            \                       \
upstream-sync-U5       \            \__F1'__F2'__F3'        \
                        \                           \        \
upstream-sync-U7         \                           \        \__F1"__F2"__F3"__F5"
                          \                           \                            \
fuchsia                    \__F1__F2__F3_______________\F4__F5______________________\F6

每个新的 upstream-sync-XXX 分支都表示自定义状态 作为最新上游版本之上的一系列新补丁。这个 使 Fuchsia 的更改更易于理解,并提高了 根据需要将其发送回上游。

Fuchsia 分支的维护者应创建上游同步分支 。

实现

分支将在 Git-on-Borg 实例上维护,网址为 https://fuchsia.googlesource.com/third_party/ninja(已存在), 及其公共 Gerrit 实例将用于审核和接受补丁。

用于构建 Ninja 预构建二进制文件的 LUCI 配方 将相应地切换其源 GIT 网址, 因为它当前指向上游 GitHub 代码库的镜像。

性能

缩短 Fuchsia 平台构建时间是实现此 RFC 的主要原因, 同时以更快的工具响应速度改善开发者体验 次。

工效学设计

通过缩短向开发者提供反馈的时间,我们将改进开发者 并减少上下文切换。

这种低延迟的同时也为 Fuchsia 的构建系统开辟了新的应用场景,例如 针对依赖于以下各项的源代码在 IDE 内报告编译时错误: 生成的文件这包括使用 FIDL 的代码以及所有 Rust 和 Go 代码 源代码。

向后兼容性

允许树内工具依赖于 紫红忍者的叉子。任何要在 Fuchsia 树之外使用的工具 不得假定存在 Fuchsia 的 Ninja 叉子。

但是,这些 Fuchsia 特定功能应仅限于最低限度 因为能够回滚到上游是此 RFC 的一个重要目标。

例如,对于某些用途,一种有效的替代方案是编写离线工具 直接解析 Ninja 构建计划并对它们执行计算(如 https://fuchsia-review.googlesource.com/c/fuchsia/+/644561).

安全注意事项

此更改应该不会对安全性产生重大影响。忍者已经是了 能够在开发者的系统上运行任意命令。任何安全性 Ninja 的漏洞同样容易来自上游,我们的分支机构 让 Fuchsia 工程师负责审核每一项更改,这是一项改进

通过使用 Google 标准的源代码工具,我们可以减少 代码供应链问题。

隐私注意事项

此方案不应以任何方式影响隐私权。

测试

和目前一样,如果发生任何更改,都会运行 Ninja 测试套件 (包括上游同步合并)。 更改必须遵守 Ninja 的标准测试做法,包括 单元测试。

文档

标准 README.fuchsia 文件将添加到 Fuchsia git 分支的顶部,解释了 分支的当前状态与上游状态之间的差异。

邮件中包含指向此 RFC 的链接,用于说明分支管理策略 此处所述。

缺点、替代方案和未知问题

此方案的主要缺点是,您需要做一些工作才能 通过执行上游同步分支作为 尽可能频繁地执行相关操作每个这样的操作都可能会触发一个或多个 rebase 冲突,需要由 Fuchsia 分支。

请注意,为使这些问题大大简化修正,一个较好方法是 以尽可能多的小补丁分解 Fuchsia 分支中的更改 (每个代码都生成一个可全面测试的源代码树)。

我们一直尝试使用 Android Ninja 分支作为起点, 考虑过,但其差异很大。仅合并最近的 向上游传送更改,将需要解决大量 (例如,他们将所有内容都切换到了 C++17 并移除了 C++03) 完全支持代码),并且非常难以进行 rebase 操作 上游的一组干净斑块。

从上游开始,并重构一些 Android 专用功能 这似乎是一个更好的解决方案, 。

此外,已经进行了多次尝试 提供一些上游补丁,无需更改上游项目, 忍者,但他们都差点了。最值得注意的是,这要归功于 多年来一直进行的调查对 GN 的一系列更改 Ninja 无运维构建时间。但令我们失望的是, 我们只取得了边际改进

请注意,Google 有几个不同的团队在使用 Ninja, 还有一些人表示有兴趣通过协调一致的方式管理 忍者在公司内部不断发展,或者设法帮助 上游维护人员。此 RFC 不会阻止任何此类情况 但其首要任务是快速为 Fuchsia 平台带来好处 。

最后,Fuchsia 现在拥有了一个 Bazel SDK,并演示了 Bazel (请参阅 RFC-0139)。 从长远来看,Fuchsia 应考虑 Ninja 的替代方案 作为平台构建后端,并探索多年来 迁移。在本 RFC 中,我们将此类迁移视为 将超出服务范围。