gccrs:Rust 的另一个编译器

2024 年 11 月 7 日 · Arthur Cohen 代表 gccrs 项目撰写

这篇客座文章由 gccrs 项目应 Rust 项目邀请撰写,旨在阐明其与 Rust 项目的关系以及潜在的协作机会。

gccrs 是一个正在开发的 Rust 备选编译器,作为 GCC 项目的一部分进行开发。GCC 是各种编程语言的编译器集合,它们共享一个通用的编译框架。您可能听说过 gccgogfortrang++,它们都是该项目,即 GNU 编译器集合中的二进制文件。gccrs 的目标是将对 Rust 编程语言的支持添加到该集合中,并力求与 rustc 具有完全相同的行为。

首先,gccrs 作为一个项目启动是因为它很有趣。编译器是极具价值的软件,开发起来非常有趣。该项目早在 2014 年,即 Rust 1.0 发布之前就已启动,但由于当时语言的不稳定性而被搁置。大约在 2019 年,由 Philip Herron 牵头,在 Open Source SecurityEmbecosm 的资助下,编译器的工作重新开始。自那时起,我们稳步朝着全面支持 Rust 语言的方向迈进,我们的团队也在不断壮大,有大约十几名贡献者定期参与项目工作。在过去的四年里,我们参与了 Google Summer of Code 项目,并有多名学生加入了这项努力。

gccrs 的主要目标是为编译 Rust 提供另一种选择。GCC 是一个历史悠久的项目,于 1987 年首次发布。多年来,它积累了大量贡献,并支持多种目标平台,其中包括一些 rustc 主要使用的后端 LLVM 不支持的平台。这种覆盖范围的一个实际例子是自制 Dreamcast 场景,在那里热情的工程师们为 Dreamcast 主机开发游戏。其处理器架构 SuperH 受 GCC 支持,但不受 LLVM 支持。这意味着 Rust 无法在这些平台上使用,除非通过 gccrsrustc-codegen-gcc 后端等努力——它们之间的主要区别将在稍后解释。

GCC 也受益于数十年来用不安全语言编写的软件。因此,该项目开发了大量安全功能,作为外部插件,甚至作为静态分析器嵌入项目内部。这些分析器和插件在 GCC 的内部表示上执行,这意味着它们是语言无关的,因此可以用于所有受 GCC 支持的编程语言。同样,许多 GCC 插件被用于提高关键项目的安全性,例如最近开始支持 Rust 编程语言的 Linux 内核。这使得 gccrs 成为分析不安全 Rust 代码,以及更普遍地分析必须与现有 C 代码交互的 Rust 代码的有用工具。我们还希望 gccrs 通过独特的视角(即一个试图复制另一个工具功能的工具的视角,通常通过仔细的实验和阅读现有文档中未详述的源代码来完成)来帮助完善 Rust 规范工作,从而成为 rustc 本身的一个有用工具。我们还在开发围绕 gccrsrustc 的各种工具,其唯一目的是确保 gccrsrustc 一样正确——这有助于发现令人意外的行为、意外的功能或未说明的假设。

我们想指出,我们协助 Rust 规范工作的目标并非将其变成一个用于认证备选编译器为“Rust 编译器”的文档——尽管我们相信该规范对 gccrs 会有用,但我们的主要目标是通过尽可能地审查和补充规范来为其做出贡献。

此外,该项目仍然“年轻”,仍需要大量工作。对于对编译器感兴趣的贡献者来说,有很多地方可以发挥作用,也有很多容易上手的工作。我们努力为我们的团队和 GSoC 学生创造一个安全、有趣且令人感兴趣的空间。我们鼓励任何感兴趣的人通过我们的各种交流平台与我们交流,并提供指导,帮助您学习如何为该项目以及更广泛的编译器领域做出贡献。

然而,也许更重要的是,gccrs 有一些它不是为了做的事情。该项目有多个明确的非目标,我们对其重视程度与我们的目标一样高。

这些非目标中最关键的一点是,gccrs 不应成为替代的或扩展的类 Rust 编程语言的入口。我们不希望创建一个 GNU 特定的 Rust 版本,具有不同的语义或略微不同的功能。gccrs 不是引入新的 Rust 功能的方式,也不会被用来规避 RFC 流程——如果我们要向 Rust 引入某些内容,我们会使用 RFC 流程。Rust 不是 C,我们不打算通过仅向 gccrs 用户提供某些功能来引入细微的标准差异。我们了解编译器特定标准造成的痛苦,并从较旧的编程语言的历史中吸取了教训。

我们不希望 gccrs 成为 rustc_codegen_gcc 后端的竞争对手。虽然这两个项目都能有效地实现相同目标,即使用 GCC 编译器框架编译 Rust 代码,但它们为该语言解锁的功能存在微妙差异。例如,rustc_codegen_gcc 可以轻松利用 rustc 所有出色的诊断和有用的错误消息,并使 Rust 在 GCC 特定平台上易于使用。另一方面,它首先需要 rustc 可用,而 gccrs 完全是另一个独立项目的一部分。这对于某些用户和核心 Linux 开发者来说很重要,他们认为使用单个编译器编译整个内核(C 和 Rust 部分)的能力至关重要。gccrs 凭借其自身作为独立的 GCC 前端,还可以提供更多插件入口点。它还允许在 libgccjit 不可用的较旧 GCC 版本的 GCC 特定平台上使用 Rust。尽管如此,我们与从事 rustc_codegen_gcc 工作的人员关系非常好,并多次互相帮助,尤其是在处理 GCC 使用的基于补丁的贡献流程方面。

所有这一切都与一个更宏大的目标紧密相连,我们可以将其概括如下:我们不希望分裂 Rust 生态系统。我们希望 gccrs 帮助 Rust 语言触及更多人群和更多平台。

为了确保这一点,我们采取了多项措施,以确保 Rust 项目的价值观得到尊重和恰当展示。我们非常重视的一个特性是给编译器添加了一个非常烦人的命令行标志,即 -frust-incomplete-and-experimental-compiler-do-not-use。没有它,您将无法使用 gccrs 编译任何代码,并且编译器会输出以下错误消息

crab1: 致命错误:gccrs 尚未能够正确编译 Rust 代码。产生的大多数错误将是 gccrs 的问题,而非您试图编译的 crate 的问题。因此,请直接向我们报告错误,而不是在该 crate 的仓库中提交问题。

我们的 GitHub 仓库:https://github.com/rust-gcc/gccrs

我们的 Bugzilla 跟踪器:https://gcc.gnu.org/bugzilla/buglist.cgi?bug_status=__open__&component=rust&product=gcc

如果您理解这一点,并理解生成的二进制文件可能行为异常,您可以尝试通过传递以下标志来以实验性方式使用 gccrs

-frust-incomplete-and-experimental-compiler-do-not-use

或通过定义以下环境变量(任何值均可)

GCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE

对于 cargo-gccrs,这意味着传递

GCCRS_EXTRA_ARGS="-frust-incomplete-and-experimental-compiler-do-not-use"

作为环境变量。

在编译器能够编译正确的 Rust,并且最重要的是能够拒绝不正确的 Rust 之前,我们将保留这个命令行选项。希望它能阻止用户因为代码无法编译而烦扰现有的 Rust crate 维护者,因为这很可能是由于我们尚未实现部分语言功能造成的。我们为 Rust 语言创建备选编译器的目标绝不能对 Rust 社区的任何成员产生负面影响。当然,这个命令行标志并非所有人都能接受,它的存在也受到了很大的阻力……但我们相信它很好地代表了我们的核心价值观。

类似地,gccrs 与 GCC 项目的其余部分有所区别,它不将邮件列表作为主要的沟通方式。我们正在构建的编译器将由 Rust 社区使用,我们认为我们应该让该社区更容易与我们取得联系并报告他们遇到的问题。由于 Rustaceans 习惯于使用 GitHub,这也是我们在过去五年中一直使用的开发平台。同样,我们使用 Zulip 实例作为我们的主要沟通平台,并鼓励任何想与我们交流的人加入。请注意,我们仍然有邮件列表以及 IRC 频道(gcc-rust@gcc.gnu.org 和 oftc.net 上的 #gccrust),欢迎所有人参与。

为了进一步确保 gccrs 不在生态系统中制造摩擦,我们希望对编译器的细节极其谨慎,对我们而言,这意味着在可能的情况下重用 rustc 组件,在这些组件上共享精力,并与社区中的 Rust 专家进行广泛交流。gccrs 已经使用了两个 Rust 组件:一个稍旧版本的 polonius(下一代 Rust 借用检查器)以及编译器中的 rustc_parse_format crate。重用这些 crate 有多种原因,主要原因是正确性。借用检查是一个复杂的主题,也是 Rust 编程语言的支柱。rustcgccrs 在借用规则上存在细微差异会给用户带来困扰且效率低下——但通过努力开始将 polonius 集成到我们的编译流水线中,我们有助于确保我们产生的结果将与 rustc 等效。您可以在此处阅读更多关于我们使用的各种组件以及我们计划重用更多组件的信息。我们还希望为 polonius 项目本身做出贡献,并在可能的情况下帮助改进它。这种组件的交叉授粉显然会对我们有利,但我们相信它也将对整个 Rust 项目和生态系统有用,并有助于加强这些实现。

重用 rustc 组件还可以扩展到编译器的其他领域:类型系统的各种组件,例如 trait solver(一个至关重要且复杂的软件部分),可以集成到 gccrs 中。像解析这样更简单的事情,例如我们已经对格式字符串解析器和内联汇编解析器所做的,对我们来说也很有意义。它们将有助于确保我们处理的内部表示与 Rust 标准库所期望的表示相对应。

最后,我们认为防止 Rust 生态系统内部出现问题最重要的步骤之一是进一步改善我们与 Rust 社区的关系。我们从 Rust 社区获得的帮助非常大,我们认为 gccrs 对广泛的用户来说可能是一个有趣的项目。我们很乐意听取您对该项目的期望,以及您关于减少生态系统破损或降低与您发布的 crate 摩擦的想法。我们在 RustConf 2024 上愉快地讨论了 gccrs,每个人对项目的兴趣都令人感到温暖。如果您对我们如何能进一步为 Rust 做出贡献有任何想法,请与我们联系。