LLVM 社区支持政策

作为一套编译基础设施,LLVM 拥有多种类型的用户,包括下游和上游,并且这些用户使用了 LLVM 项目、工具和库的各种组合。

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

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

即使不是项目的核心部分,我们也有足够的子社区需要这些更改,并且这些更改之间有足够的重叠,因此将它们放在主代码库中可以有效减少在所有需要它们的外部代码库中重复这些更改。

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

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

核心层级

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

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

涵盖内容

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

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

  • Phabricatorbuildbot 基础设施。

  • 测试套件

要求

此层级的代码必须:
  • 保持官方构建机器处于绿色状态,并通过电子邮件将中断警告发送给所有受影响的开发人员。根据审查政策,这些问题必须尽快解决,或者必须撤销补丁。

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

外围层级

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

这包括同一代码库中的实验性后端、默认情况下禁用的选项和替代路径(正在进行的替换),以及将 LLVM 开发与本地实践集成的单独工作。

每个子社区都有责任维护其自身的部分以及它与核心层级和其他外围部分的交集。

此类别中有三类主要的代码:
  • 通过 实验性路线图或类似工作进入 LLVM 的代码。

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

  • 不属于 LLVM 核心的代码,可以长期与核心层级(以及外围层级中的其他代码)共存,而不会造成中断或干扰。

涵盖内容

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

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

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

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

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

要求

此层级的代码必须:
  • 拥有驻留在主代码库中的明确益处,服务于一个活跃的子社区(上游或下游)。

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

此层级的代码**不得**:
  • 破坏或使核心层级代码或基础设施失效。如果意外发生这种情况,则唯一可接受的行动方案是撤销功能并在脱机状态下处理问题。

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

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

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

  • 拥有会向所有开发人员发送中断警告的构建基础设施。

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

此层级的代码应:
  • 拥有测试基础设施(在有意义的情况下),并且要么没有警告,要么通知包含在子社区中。

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

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

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

纳入政策

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

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

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

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

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

弃用政策

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

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

警告

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

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

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

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

  • 构建和测试变得更难/更耗时,增加了维护成本,超过了预期的收益。

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

移除步骤

无论移除需求多么明确,我们都应该采取渐进式方法来弃用代码,尤其是在仍然有子社区关心它的时候。从这个意义上说,代码永远不会在没有采取一系列步骤的情况下被直接移除。

一组最小的步骤应该是:
  1. 应向 Discourse 论坛(在相应的类别下)提出移除/停用建议,并明确说明所造成的维护成本以及替代方案(如果适用)。

  2. 邮件列表上必须有足够的共识认为移除是合理的,并且没有来自子社区的待处理修复提案。

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

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

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

    3. 其他所有内容都将介于这两个极端之间。

  4. 移除由提出者或曾经维护它的子社区完成,替换和安排在同一提交中原子化地完成。

如果移除提案因某个子社区承诺会维护受影响的代码而被延迟,则该子社区将有一段时间来修复所有问题(具体时间视情况而定,如上所述),如果在规定时间内没有修复这些问题,则应提出后续的移除请求,并且社区可以选择将组件移除,而无需进一步尝试修复。

恢复

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

因此,这种子社区将面临更大的压力,需要将整体维护成本降到最低,并需要展示出缓解所有最初导致其移除的问题的措施。

如果再次未能做到这一点,将再次成为移除候选对象。