LLVM 社区支持政策

作为编译基础设施,LLVM 有多种类型的用户,包括下游和上游用户,他们使用其项目、工具和库的各种组合。

它的核心部分包括编译器(前端/中端/后端)、运行时库(RT、C++、OpenMP 等)以及相关工具(调试器、链接器、目标文件操作等)的实现。这些组件存在于我们支持的架构和操作系统的公共版本中,整个社区必须维护和关注它们。

然而,在主仓库中还有其他组件,它们要么服务于 LLVM 的特定子社区(上游或下游),要么帮助社区的部分成员将 LLVM 集成到他们自己的开发工具或外部项目中。主仓库的这些部分并不总是像核心部分那样经过严格的测试,也没有经过验证并与我们的公共上游版本一起发布。

即使不是项目的核心部分,我们也有足够多的子社区需要这些更改,并且这些更改有足够的重叠,因此将它们放在主仓库中有利于最大程度地减少在所有需要它们的外部仓库中重复这些更改。

但是,维护如此多样化的生态系统的成本不低,因此我们将支持级别分为两个层级:核心层级和外围层级,它们具有不同的影响和责任级别。这些层级仅指主仓库 (llvm-project),而不指我们 git 项目中的其他仓库,除非另有明确说明。

无论属于哪个层级,所有代码都必须遵循现有的关于质量、审查、风格等的政策。

核心层级

核心层级包括主仓库中所有已投入生产、经过积极测试并按定期计划发布的代码,包括核心 LLVM API 和基础设施、前端/中端/后端、运行时库、工具等。

**每位** LLVM 开发人员都有责任维护核心层级,无论他们的工作应用于何处。

覆盖范围

核心层级由以下部分组成
  • 官方版本和构建机器人中存在的核心代码 (llvm-project):编译器、调试器、链接器、库等,包括基础设施代码(table-gen、lit、file-check、单元测试等)。

  • 创建版本和构建机器人的构建基础设施(CMake、脚本)。

  • Phabricatorbuildbot 基础设施。

  • test-suite

要求

此层级中的代码必须
  • 保持官方构建机器人为绿色状态,并在发生故障时向所有受影响的开发人员发送警告邮件。必须尽快修复这些问题,或者必须根据审查政策回退补丁。

  • 核心层级中组件的位腐烂将导致该组件降级到外围层级或被删除。子社区可以通过及时修复所有提出的问题来避免这种情况。

外围层级

外围层级包括 LLVM 中服务于特定子社区且通常不直接影响核心组件的部分。

这包括同一仓库中的实验性后端、默认禁用的选项和替代路径(正在进行中的替换),以及将 LLVM 开发与本地实践相结合的单独努力。

每个子社区都有责任关注他们自己的部分以及该部分与核心层级和其他外围部分的交集。

此类别中主要有三组代码
  • 通过实验性路线图或类似努力正在进入 LLVM 的代码。

  • 通过弃用、替换或位腐烂正在退出 LLVM 的代码,如果关心它的子社区无法维护它,则将被删除。

  • 并非旨在成为 LLVM 核心部分,但可以长期与核心层级(以及外围层级中的其他部分)的代码共存,而不会引起崩溃或干扰的代码。

覆盖范围

外围层级由以下部分组成
  • 尚未默认启用的实验性目标和选项。

  • 未发布或未定期测试的主仓库项目。

  • 未在上游验证中使用的旧工具和脚本。

  • 替代构建系统(例如 GN、Bazel)和相关基础设施。

  • 工具支持(例如 gdb 脚本、编辑器配置、辅助脚本)。

要求

此层级中的代码必须
  • 对驻留在主仓库中具有明确的好处,服务于活跃的子社区(上游或下游)。

  • 由此类子社区积极维护,并及时解决其问题。

此层级中的代码**不得**
  • 破坏或使核心层级的代码或基础设施失效。如果意外发生这种情况,则唯一可接受的行动方案是恢复功能并在离线状态下解决问题。

  • 对核心层级代码的开发产生负面影响,相关子社区负责进行更改以解决特定问题。

  • 对其他外围层级的代码产生负面影响,相关子社区负责解决这些问题,同时仍要确保解决方案不会破坏或使核心层级失效。

  • 由于外围组件的特性,对核心层级组件施加次优的实现策略。

  • 拥有向所有开发人员发送有关其故障的垃圾邮件的构建基础设施。

  • 陷入失修状态。这反映了缺乏活跃的子社区,并将导致移除。

此层级中的代码应该
  • 在有意义时,拥有测试基础设施,并且没有警告或通知包含在子社区内。

  • 拥有与组件的复杂性和弹性相匹配的支持和测试,对于简单且优雅降级的组件(例如编辑器绑定)的要求远低于必须与 HEAD 保持同步的复杂组件(例如实验性后端或替代构建系统)。

  • 拥有一份文件,明确说明实施状态、可用支持级别、子社区是谁,以及(如果适用)纳入核心层级的路线图。

  • 限制在特定目录或具有一致的模式(例如,唯一的文件后缀),以便在必要时易于移除。

纳入政策

要添加新的外围组件,请向相应的开发邮件列表发送 RFC,提议添加该组件并解释它将如何满足上面列出的支持要求。不同类型的组件可能需要不同程度的详细信息。如有疑问,请咨询社区最佳方法。

纳入必须在社区的 RFC 中达成共识,并且相应的审查(由社区的多个成员进行)的批准是正式的接受通知。

合并后,通常会有一个过渡期,在此期间会发现并修复现有构建机器人上的初期问题。如果无法立即修复这些问题,则子社区负责跟踪和回退所有相关的补丁,并重试纳入审查。

一旦组件在树中稳定下来,它必须遵循此政策,并且以下弃用规则适用。

由于纳入的不确定性,建议不要在离发布分支太近的时候添加新组件。时间将取决于组件的大小和复杂性,因此强烈建议在 RFC 和审查中添加发布和测试经理。

弃用政策

LLVM 代码库中有许多文件没有得到积极维护。但并非所有这些文件都在阻碍项目的发展,因此它们仍然保留在仓库中,并假设它们可能对下游用户仍然有用。

为了使代码保留在仓库中,它的存在不得对维护其他组件(核心或外围)施加不必要的负担。

警告

有多种类型的问题可能会触发弃用请求,包括(但不限于)

  • 组件中的更改持续破坏项目的其他区域。

  • 组件长时间(几周或更长时间)处于损坏状态。

  • 明显更优越的替代方案正在使用中,并且维护很痛苦。

  • 构建和测试更困难/花费更长时间,增加了维护成本,超过了感知到的好处。

如果维护成本高于大多数开发人员可接受的水平,则意味着要么子社区太小(额外的成本应在本地支付),要么不够活跃(问题不会很快得到解决)。在任何一种情况下,移除这种有问题的组件都是合理的。

移除步骤

无论移除的需求多么明确,我们都应该采取渐进式方法来弃用代码,特别是当仍然有子社区关心它时。从这个意义上讲,在采取一系列步骤之前,代码永远不会被彻底移除。

最低限度的一组步骤应该是
  1. 应在 Discourse 论坛(在适当的类别下)提出移除/停用的提案,并明确说明施加的维护成本以及替代方案(如果适用)。

  2. 列表上必须有足够的共识认为移除是必要的,并且没有来自子社区的待处理提案来解决这种情况。

  3. 必须在相同的列表上发布移除公告,并为下游用户留出充足的时间在其本地基础设施上采取行动。时间将取决于要移除的内容。

    1. 如果要移除脚本或文档,它们始终可以从以前的版本中拉取,并且可以在几天内移除。

    2. 如果要移除整个目标,我们需要首先公开宣布,并可能在一个版本中标记为已弃用,然后在下一个版本中移除。

    3. 其他一切都将介于这两个极端之间。

  4. 移除由提案者或过去维护它的子社区进行,替换和安排在同一提交中原子性地完成。

如果移除提案因子社区承诺将处理受影响的代码而被推迟,则子社区将有时间修复所有问题(取决于具体情况,如上所述),如果这些问题未及时修复,则应提出后续移除请求,社区可以选择在不进一步尝试修复的情况下移除该组件。

恢复

如果组件从 LLVM 中移除,它可能会在稍后请求包含修改后的版本,并提供证据表明所有问题都已修复,并且有一个明确的子社区将维护它。

因此,此类子社区将面临更大的压力,以将总体维护成本保持在最低水平,并且需要展示减轻所有被列为最初移除原因的问题的步骤。

再次在这些方面失败,将导致再次成为移除的候选对象。