同步 Rust GCC 后端或如何测试墨菲定律

Lobsters Hottest 工具

摘要

这篇博客文章详细介绍了使用 git subtree 将 Rust GCC 后端仓库与 Rust 主仓库同步的复杂过程,以及出现的诸多问题,体现了墨菲定律。

<p><a href="https://lobste.rs/s/hy7ckt/syncing_rust_gcc_backend_how_test_murphy_s">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/09/28 01:43

# 同步Rust GCC后端或如何验证墨菲定律 来源:https://blog.guillaume-gomez.fr/articles/2026-09-22+Syncing+Rust+GCC+backend+or+how+to+test+Murphy's+law 本文关于Rust GCC后端(请勿与GCC编译器的Rust前端gccrs(https://rust-gcc.github.io/)混淆),介绍我们如何将其仓库与Rust主仓库同步,以及为何整个过程如此艰难——耗费两个月才最终完成。这是对墨菲定律的绝佳诠释: > 任何可能出错的事情终将出错。 ## GCC后端的开发方式 GCC后端在独立仓库中开发:https://github.com/rust-lang/rustc_codegen_gcc/ 。这使我们能在不破坏Rust CI的前提下进行实验。目前这些变更仅存在于GCC后端仓库中。 作为Rust编译器的代码生成后端(下文简称"codegen"),其源代码也存在于Rust编译器仓库中:https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_gcc 。该文件夹内容与我们的仓库通常保持一致。但当编译器添加新功能或清理代码时,有时需要同步到各codegen后端(LLVM、cranelift和GCC),这又会导致变更仅存在于Rust仓库中。 因此两个仓库各自存在独有变更,我们需要在某个时间点将它们合并同步。 ## 同步工作的原理 现在进入"有趣"环节:两个仓库间的变更同步。我们使用`git subtree`功能。如果没听说过它?这很正常,因为它是个不完善的功能(对大仓库支持不佳)。你可以在`git`仓库的此处(https://github.com/gitgitgadget/git/pull/493)查看修复该问题的拉取请求。因此你需要克隆`git`仓库,检出该分支,构建此版本并将其放在本地备用。我们在此处(https://github.com/rust-lang/rustc_codegen_gcc/blob/master/doc/subtree.md)提供了详细操作指南。 准备好补丁版`git`后,下一步是将Rust仓库的变更合并到`rustc_codegen_gcc`仓库: ``` # 当前目录为rust仓库。 git-subtree push -P compiler/rustc_codegen_gcc/ ../rustc_codegen_gcc/ sync_branch_name cd ../rustc_codegen_gcc git checkout master git pull git checkout sync_branch_name git merge master ``` 将Rust变更合并到GCC后端后,我们就能将`rustc_codegen_gcc`的变更推送回Rust: ``` # 当前目录为rust仓库。 git pull origin master git checkout -b subtree-update_cg_gcc_YYYY-MM-DD git-subtree pull --prefix=compiler/rustc_codegen_gcc/ https://github.com/rust-lang/rustc_codegen_gcc.git master git push ``` 由于`rustc_codegen_gcc`针对特定`GCC`版本(包含上游GCC未合并变更的我们自己的分支),还需要更新Rust的GCC子模块: ``` # 当前目录为rust仓库。 cd src/gcc git fetch git checkout $(cat compiler/rustc_codegen_gcc/libgccjit.version) ``` 提交变更,确认编译通过后即可推送。 最后一步:Rust仓库的拉取请求合并后,需要将合并提交反向同步回`rustc_codegen_gcc`仓库: ``` # 当前目录为rust仓库。 git-subtree push -P compiler/rustc_codegen_gcc/ ../rustc_codegen_gcc/ sync_branch_name ``` 至此完成! 现在来谈谈上次同步经历及为何提到墨菲定律。 ## 目前一切顺利 2026年7月24日,我提交了#159844(https://github.com/rust-lang/rust/pull/159844)。首先遇到许可证问题:我们复制了一个用于识别CPU特性的文件。经过法律讨论后,该问题于7月31日解决。 同期我们还遇到CI镜像问题——新GCC版本需要"更新"的软件包。为减少网络导致的CI不稳定,Rust基础设施提供了比直接从外部下载更可靠的镜像(位置固定且流量小得多)。 当更新GCC版本时,Rust CI会完全重新构建GCC,以便从事GCC后端开发的Rust开发者使用。新GCC版本需要比我们docker镜像中更新的`make`版本。因此:我们将新`make`源码添加到镜像,将其构建进docker镜像,然后按常规流程构建GCC。 至此问题全部解决!该变更于8月3日合并。至今三个问题,虽不理想但也不算最糟。目前一切顺利。 但正如你可能猜到的,事情并未就此结束。 ## 听说过副作用吗? 合并后我立即在zulip基础设施团队频道收到通知——CI完全崩溃,错误信息似乎与GCC相关。因此我们决定回滚同步拉取请求。当然,尝试通过GitHub界面回滚时: > #### https://blog.guillaume-gomez.fr/articles/2026-09-22+Syncing+Rust+GCC+backend+or+how+to+test+Murphy's+law#回滚失败:发现仓库规则违规 > 由于创建操作被限制,无法创建新引用。 手动完成回滚(#160468(https://github.com/rust-lang/rust/pull/160468))后,CI恢复正常。但同步工作仍未完成,我们仍不清楚为何同步拉取请求的CI能成功。经调查发现,构建的GCC未启用某些特性导致测试失败。关键问题是:为何同步CI会成功?这让我们发现了CI缓存的bug。修复缓存问题后,只剩GCC构建错误的问题。 有趣的是,构建GCC时会根据系统工具配置功能。如果链接器不支持`retain`,该功能会被禁用。最近我们在GCC后端添加了"可外部实现项"的支持...而这正需要`retain`功能(如感兴趣可参见GCC后端的相关拉取请求:gcc#88(https://github.com/rust-lang/gcc/pull/88)、gcc#89(https://github.com/rust-lang/gcc/pull/89)、cg_gcc#921(https://github.com/rust-lang/rustc_codegen_gcc/pull/921)和cg_gcc#962(https://github.com/rust-lang/rustc_codegen_gcc/pull/962))。因此相关测试在Rust仓库中已为GCC后端取消忽略,导致测试失败。 首要任务是通过在CI中安装更新版`binutils`来修复GCC构建,我在#161006(https://github.com/rust-lang/rust/pull/161006)中于8月12日完成此操作。经过多次尝试,终于使其正常工作并于8月17日合并。 最后一个障碍排除了!等等,这破坏了`miri`构建。回滚! 与其在docker中替换已安装的`binutils`,不如仅将其用于GCC构建以限制影响范围?尝试此方案!在#161243(https://github.com/rust-lang/rust/pull/161243)中完成并于8月21日合并。 ...但`miri`似乎又出问题了!幸好这次只是时间巧合:实际上是个不相关的拉取请求更新了`cc` crate,恰好在我们之后合并。虚惊一场。 此后时间已过,我们需要再次将Rust仓库的变更同步到`rustc_codegen_gcc`仓库。于是我们提交了cg_gcc#959(https://github.com/rust-lang/rustc_codegen_gcc/pull/959)。结果...失败了。Rust引导程序的变更破坏了sysroot处理(简言之:rustc查找库的路径),无法再找到GCC库。该问题于9月3日在#162152(https://github.com/rust-lang/rust/pull/162152)中修复。 尝试从Rust同步到`rustc_codegen_gcc`:cg_gcc#972(https://github.com/rust-lang/rustc_codegen_gcc/pull/972),再次失败。这次是因为`rustc_codegen_gcc`需要与Rust使用相同的LLVM版本(我们使用LLVM工具进行部分测试,如汇编测试的`FileCheck`)。 更新LLVM和构建`rustc_codegen_gcc`的`rust`版本后,我们提交了新的同步请求:cg_gcc#974(https://github.com/rust-lang/rustc_codegen_gcc/pull/974)。这次成功了!\o/ 于9月8日合并。 现在尝试从`rustc_codegen_gcc`同步到Rust:#162499(https://github.com/rust-lang/rust/pull/162499)。CI因`run-make`测试(Rust的测试套件)失败。好吧,这怪我。在上次修复与这次同步之间,我在#162482(https://github.com/rust-lang/rust/pull/162482)中修复了Rust引导程序的bug——该bug曾阻止LLVM以外的codegen后端运行`run-make`测试。 考虑到这点,添加了提交来为GCC后端忽略这些测试,直到我们端修复完成。 再次运行CI...又失败了!这次是因为期间我们在`rustc_codegen_gcc`中更新了GCC版本,需要更新版`make`。那就更新吧!为确保更新`make`版本不会破坏其他功能,我单独提交了#163031(https://github.com/rust-lang/rust/pull/163031)仅包含此变更。 似乎没问题。那么现在尝试合并同步请求吧! 9月22日,#162499(https://github.com/rust-lang/rust/pull/162499)合并,同步工作终于完成! ## 下一步计划 这真是一连串不幸!但过程中我们改进了Rust CI,发现了缓存问题,修复了测试套件的bug/限制。虽然令人疲惫,但收获颇丰。 然而,这次同步暴露出该流程存在太多问题,我们应改用其他方案。幸运的是,部分子树已迁移至josh(https://github.com/rust-lang/josh-sync),我们计划很快为`rustc_codegen_gcc`采用相同方案。 ## 结语 猫咪睡得太沉无法带来好运。 我的猫在我双腿间睡觉 RSS订阅(https://blog.guillaume-gomez.fr/rss)RSS订阅(https://blog.guillaume-gomez.fr/atom)

相似文章

使用gccrs编译Linux内核的进展

Lobsters Hottest

gccrs项目致力于为GCC开发Rust前端,近期在编译Linux内核方面取得进展,解决了属性处理、名称解析和资源管理中的问题,并重新组织了开发里程碑。

Grit:用Rust和智能体重写Git

Hacker News Top

本文介绍了Grit,这是一个用Rust重新实现的Git新版本,通过了超过99%的Git测试套件,并且是通过AI智能体创建的。它旨在提供一种基于库、内存安全的替代方案,以取代原版Git。

使用并行Claude团队构建C编译器

Anthropic Engineering

Anthropic研究员展示了如何使用16个并行Claude实例自主构建一个基于Rust的C编译器,该编译器能够编译Linux内核。文章详细介绍了这一多智能体自主编码实验的架构、成本和经验教训。