本月测试基础设施进展:2025 年 1 月至 2 月

2025 年 3 月 11 日 · Jieyou Xu 代表 the Bootstrap Team

本月测试基础设施进展:2025 年 1 月至 2 月

这是对 rust-lang/rust 仓库1 测试基础设施在 **2025 年 1 月和 2 月** 所做变更的快速总结2

和往常一样,如果您在使用我们的测试基础设施时遇到 bug 或用户体验问题,请提交 issue。如果我们不知道 bug 和小问题,就无法修复它们!

感谢所有为我们的测试基础设施做出贡献的人!

亮点

ci.py 现在是一个真正的 citool Rust crate

用于编排 CI 作业的旧 Python 脚本 ci.py 难以维护。对该 Python 脚本的任何更改都有使整个队列崩溃或完全绕过测试的风险。几乎没有测试覆盖率。CI 用户体验改进难以实现且难以审查。

因此,Jakub 决定受够了,并src/ci/github-actions/ci.py 重写为 src/ci/citool,一个真正的 Rust CLI 工具。这使得作业定义能够被正确解析和处理,并且能够添加单元测试。它还允许改进一些错误消息。此外,它改进了在本地(Linux 上)运行 CI 作业的用户体验。请查阅 rust-lang/rust 中的 rustc-dev-guide 文档以获取更新的运行说明(截至撰写本文时,尚未同步回 rustc-dev-guide)。

try-job 现在支持作业名称的 glob 模式

作为 CI 效率提升的一部分,许多 CI 作业被拆分为多个作业(例如 x86_64-apple-{1,2}),以平衡 runner 能力和构建/测试时间。这带来了一个不幸的副作用,即更难知道需要在自定义 try 作业中指定哪个作业名称才能运行您想要的测试。

https://github.com/rust-lang/rust/pull/138307 允许贡献者编写 **glob 模式**来匹配作业名称(最多 20 个匹配作业,请参阅下一个亮点)。例如,如果您想运行所有 msvc 相关作业作为 try-jobs 的一部分,您不再需要指定一堆,例如 try-job: x86_64-msvc-1try-job: x86_64-msvc-2try-job: dist-x86_64-msvctry-job: i686-msvc-1try-job: i686-msvc-2。取而代之的是,您现在可以编写

try-job: `*msvc*`

Which will expand to match against (and thus run) all of x86_64-msvc-{1,2}, i686-msvc-{1,2} and dist-x86_64-msvc.

请注意 glob 模式周围的反引号 (`)。这是为了防止 GitHub UI 将 glob 模式解释为(可能不匹配的)markdown 斜体标记。反引号将被 CI 工具忽略。

自定义 try-job 作业限制现在是 20 个(原来是 10 个)

您现在最多可以运行 20 个自定义 try-job,而不是之前的 10 个限制。

基于 Makefilerun-make 测试基础设施已退役

近 8 年前,敏锐的早期贡献者注意到基于 Makefilerun-make 测试既难运行又难编写。当时提议我们将 run-make 测试Makefile 切换到 rust,原因有很多,例如

  • 使其对贡献者更易于访问。Makefile 语法(与 bash 交织)和语义本身就是 bug 和陷阱的来源,并且经常令人沮丧。
  • 在可行且有益的情况下,减少对外部工具(尤其是外部二进制工具)的依赖。
  • 减少平台依赖。
  • 避免不得不处理不同风格的 make(各种版本的 GNU make,nmake),它们彼此之间(微妙地)不兼容3
  • 使其无需使用某种 Unix 兼容层(例如 MSYS)即可在 Windows 上本地运行测试套件(无论是 MSVC 还是 mingw)。

2023 年,在与多位贡献者协商后,我们达成共识,采用了一个新的run-make 测试基础设施,它有两个关键组成部分

  1. 每个 run-make 测试都包含一个测试配方,即 rmake.rs。这是主要的测试文件。
  2. 测试配方可以访问一个名为run-make-support 的测试支持库。该支持库集中了不同 run-make 测试使用的通用辅助函数。它还允许重新导出有用的生态系统 crate 供测试使用,例如objectregex。生态系统 crate 使得 rmake.rs 测试能够执行比大多数基于 Makefile 的测试使用的基于文本的操作更精确的检查。

这里最重要的区别也许是 Rust 贡献者的可访问性得到了改善。rmake.rs 测试只是普通的 Rust 程序。这意味着贡献者不再需要不断地与所有 Makefile 和 shell 语法怪癖(多种引用风格、插值等)或行为怪癖(例如 pipefail)作斗争4

有 200 多个 run-make 测试,所以我们无法一次性全部移植。因此,采取的方法是

  • 遗留的基于 Makefilerun-make 测试基础设施与新的基于 rmake.rsrun-make 测试基础设施并行存在。使用哪种测试基础设施取决于测试目录是否包含 Makefilermake.rs
  • 我们维护了一个类似任务追踪的 issue,详尽列出了所有需要移植的基于 Makefilerun-make 测试,并跟踪了它们的迁移进度。邀请贡献者认领他们希望帮助移植的特定测试。
    • 这将工作量分摊给了许多贡献者,从而使这次迁移成为可能。如果贡献者需要帮助或想讨论方法,例如他们想针对特定的try-jobs 运行测试,仍然会提供指导。
    • 通过一个有导师指导的Google Summer of Code (GSoC) 2024 项目@Oneirical 致力于移植大部分 run-make 测试。您可以在这里阅读他们的最终 GSoC 报告。
    • 许多维护者也帮助提供了基础设施、审查、测试和建议,并亲自编写了迁移 PR。
    • 感谢在此工作中提供帮助的每个人!
  • 采用了一种并非简单的 1 对 1 移植的迁移过程。在可能的情况下,贡献者尝试改进测试以
    • 获得充分的文档,通过链接到相关的上下文、参考、讨论、实现历史和合适的 issue。许多 Makefile 版本的测试没有任何测试描述。需要进行大量的 git 考古工作来弄清楚测试最初想测试什么。
    • 实际测试测试想要测试的内容。例如,tests/run-make/translation没有测试它想要测试的内容,因为 Makefile 没有设置 SHELL=/bin/bash -o pipefail
    • 变得更精确且不易出错。相当多的 run-make 测试能够利用优秀的object crate 对二进制文件(用于符号和调试信息)执行结构化分析,而不是尝试对二进制工具(如 objdumpnm,它们的 CLI 接口和文本输出格式在不同平台之间也可能不同)的人类可读文本输出进行文本搜索。

这项迁移工作耗时约一年,直到我们最终能够宣布所有基于 Makefilerun-make 测试都已移植完成,因此我们在 2025 年初得以退役遗留的基于 Makefile 的测试基础设施

当然,新的测试基础设施并非完美无缺。仍然有一些问题、期望的改进和测试用户体验上的小瑕疵有待解决。然而,与整个测试基础设施一样,它们可以并且将会随着时间的推移得到改进。

Bootstrap 测试和构建步骤指标现在可在 GitHub 作业摘要中查看

https://github.com/rust-lang/rust/pull/137077 实现了 bootstrap 测试和构建指标的后处理逻辑,将其转换为GitHub 作业摘要

Sample job summary

值得注意的变更

本节旨在类似于“兼容性说明”,但面向人类测试编写者。

基于 rustc (ToolRustc) 的工具具有统一的分阶段处理方式

之前,希望使用本地构建的 rustc 的工具在它们的工具和测试步骤中不一致地实现自己的分阶段逻辑。这导致了很多困惑,因为不同的 ToolRustc 工具(及其测试)以不同的方式处理分阶段;有些有不必要的构建,而另一些则似乎“差了一个阶段”。在不同地方存在单独“砍掉”或“增加”阶段的技巧。为了使这种情况更易于维护,https://github.com/rust-lang/rust/pull/137215 统一了 ToolRustc 工具的分阶段逻辑。

值得注意的是,在可能的情况下,不带参数的 ./x test./x test src/tools/{cargo,clippy} 现在默认使用 stage 2。以前,./x test src/tools/{cargo,clippy} 在没有明确测试阶段配置的情况下对应于 --stage 1,但它们实际上仍然需要构建 stage 2 rustc。如果您在测试这两个工具时尝试指定小于 2 的测试阶段,Bootstrap 现在会发出警告(它们不一定能与 stage 1 rustc 一起工作是一个已存在的问题)。

此外,以前的 ./x build $rustc_tool --stage 0 调用(非 std 或 bootstrap 工具)现在等同于 ./x build $rustc_tool --stage 1。在 https://github.com/rust-lang/rust/pull/137215 之前,构建流程中 rustc 工具的阶段会因不一致的调整而增加,并且当在 ./x build $rustc_tool 调用上指定 --stage N 时,它会构建 stage N+1 rustc。现在,./x build $rustc_tool --stage N 将使用 stage N rustc 生成一个 rustc-tool。

请查阅新的《Bootstrap 中编写工具》章节,以进一步澄清如何选择正确的 bootstrap 工具模式。

run-make-supportrmake.rs 现在固定使用 stage 0 编译器构建

参见https://github.com/rust-lang/rust/pull/137373https://github.com/rust-lang/rust/pull/137537

以前,run-make-supportrmake.rs 错误地使用了顶层阶段的编译器构建,这是错误的。run-make-supportrmake.rs 应该使用 stage 0 编译器构建(它们是测试基础设施,需要可靠,无论待测试的 stage > 0 编译器是否可能损坏)。这导致一些 rmake.rs 测试在测试配方本身中意外地使用了不稳定特性,这将给 beta/stable 版本向后移植/升级带来问题,也将给像 rustc_codegen_cranelift 这样需要在 stage 0 运行 run-make 测试的树外 codegen 后端带来问题。

文档也已更新,明确阐明 run-make-supportrmake.rs 不得使用不稳定特性。

corealloc 单元测试现在分别位于单独的 coretestsalloctests 包中

将 std 测试与 std crate 放在同一个包中有一些问题,例如

导致测试依赖于本地构建的标准库 crate,同时又通过 libtest 间接依赖它

https://github.com/rust-lang/rust/pull/135937core 测试移动到单独的包中,https://github.com/rust-lang/rust/pull/136642alloc 测试移动到不依赖于 core 的单独包中,以防止重复 crate 问题,即使 sysroot 构建和测试构建之间的编译器标志不匹配。

std 的其他部分仍然存在这个问题。这是正在进行的一项努力的一部分,旨在使 std 测试更健壮,并且更容易由自定义 codegen 后端构建。

PR 列表

改进

修复

清理

文档更新

请注意,由于 rustc-dev-guide 已成为 rust-lang/rust 中的 josh 子树,一些文档更新是随着 rust-lang/rust PR 本身进行的。