
systemd 合并 Rust 支持,可用 Rust 编写组件
来源标题:Systemd Loves Rust
systemd 已合并对 Rust 的支持,今后除 C 语言外,也可以用 Rust 编写 systemd 组件。开发者 Christian Brauner 和 Lennart Poettering 表示,目前 Rust 仅用于组件而非核心部分,因为 Rust 缺乏稳定的共享库 ABI,会导致共享库和二进制文件被重复的 Rust 代码膨胀。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
作者:Christian Brauner 与 Lennart Poettering
systemd 中的共享库使用 Rust 🥺,systemd 二进制程序使用 Rust 😍,关键设计决策,结语
systemd 最近合并了对 Rust 的支持。今后,除了 C 语言之外,还可以用 Rust 编写 systemd 组件。
将另一种核心语言引入一个大型成熟项目,这一选择总是充满争议。当初 Rust 被采纳为 Linux 内核的附加语言时,我们也见过同样的争论。而如今我们知道,那次尝试基本上是成功的。
systemd 对 Rust 的支持有两种可能的含义:
项目得出的结论是:(1) 可以接受,而 (2)(目前)不可接受,因为这两个选项的范围和要求差异非常大。
选项 (2) 很复杂。细节最好留到另一篇博客文章中去讲,但要点是:我们需要 Rust 提供一流的共享库支持。在 Rust 社区,这通常被称为“稳定 ABI 问题”,这是一个众所周知且长期存在的问题。在它实现之前,我们无法将 Rust 集成到根组件中,否则每个共享库和许多二进制程序都会因为重复的 Rust 代码而变得臃肿。
对于像 systemd 这样被拆分成许多微小组件(目前超过 180 个二进制程序)的项目来说,静态链接根本不切实际,也不可取。一般来说,静态链接适用于操作系统的叶子部分,但核心部分往往有不同的要求。
选项 (1) 意味着共享代码仍仅用 C 编写,我们将这些功能封装为 Rust crate。然后这些 crate 被用于 Rust 二进制程序。这使我们能够在所有组件中统一使用所有核心 API 函数,无论它们是用 Rust 还是 C 编写的。
当 Rust 被 systemd 接纳时,项目采纳了以下原则:
统一访问核心 API。systemd 共享库提供了大量辅助工具,它们提供的功能与安全性远远超出 libc 或任何 Rust crate 所能提供的范围。
最明显的例子是 systemd 的 chase*() 系列函数。这是一个纯粹基于 fd 的路径查找 API,整个代码树都在使用它。任何提升路径查找安全性和可靠性的新内核特性都会被立即采纳并安全地抽象出来。在核心 Rust 中,没有任何东西能与之等价。
统一行为。C 和 Rust 编写的二进制程序在解析选项、显示帮助和输出错误消息方面的外观和行为完全一致。
Rust 编写的二进制程序与 systemd 的 C 二进制程序出现意外差异,这是绝对不可接受的。用户永远不应该关心一个二进制程序是用什么语言实现的。这根本不应该影响行为。
统一构建系统。与大多数现代编程语言一样,Rust 自带构建和依赖管理生态系统:cargo。与内核非常相似,systemd 明确选择不依赖 cargo 来构建 Rust。
systemd 使用 meson 作为其构建系统,在我们看来,在它旁边再集成一个构建系统是个坏主意,只会让发行版维护者的生活变得更加复杂。
与 cargo 相关的安全和供应链攻击问题也引起了关注。
受控依赖。systemd 与其他项目保持严格宽松的依赖关系。如今,systemd 仅链接 libc。其他所有依赖都通过 dlopen() 提供,并使用 ELF notes 标记依赖关系。
接受新依赖是一个谨慎的过程,涉及从维护和安全角度对各个项目进行审查。
虽然 systemd 原则上不反对使用外部 crate,但它有意保持保守,在项目对更广泛的 Rust 生态系统和社区积累一定经验之前,不接受对它们的任何依赖。
No-std Rust。systemd 也不使用 Rust 标准库。我们目前不需要使用标准库提供的任何东西。再举一个例子来重申前面的观点:Rust 提供的路径查找功能目前都不适用于 systemd 提供的安全敏感的系统组件。
可失败分配。Rust 中分配失败会导致 panic。systemd 始终将分配视为可失败的,并尽可能优雅地处理。因此,systemd 提供了自己的分配器 crate,使整个 systemd 代码库的内存处理保持一致。同样,这与内核的做法非常相似。
不进行无谓的重写。用 C 编写的、长期存在且可靠的代码库部分,没有充分理由不会被转换。
如果说新语言有什么缺点,那就是它们会导致对已建立且稳定的项目进行重写,目的是使用这种语言,而不是解决实际问题。最明显的例子之一就是重写那些固有攻击面是基于路径查找而非内存安全的组件。移植到另一种语言的项目需要的不仅仅是逐 bug 兼容的重写,才能从重写中真正获益。更重要的是专注于消除其核心攻击面。
Rust 保持可选。现有用户可用的功能集不会退化。我们知道 Rust(尚)不支持所有可能的架构,而且有些地方引入 Rust 会很复杂,所以至少目前,Rust 保持可选,没有 Rust 的 systemd 仍然完全可用并受到支持。
将 Rust 集成到 systemd 是一个持续的过程。看到项目的众多维护者将把它带向何方以及这将如何演变,令人兴奋。Rust 是一门好语言。它的语法是一个需要培养品味和学习的问题,但它确实带来了一系列成熟项目想要使用的特性。systemd 的一位维护者最近发现,他在 systemd 中采用 Fibers 的工作与 Rust 自然地以一种令人惊讶的优雅方式集成在一起。
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。