Linux 内核正在为升级到 Rust 1.77 做准备

Linux 转向更新的 Rust 工具链,包括计划升级到 Rust 1.77,引发了关于内核应在多大程度上依赖不稳定编译器特性,以及这对长期可维护性意味着什么的讨论。评论者在权衡 Rust 的优势——内存安全、现代抽象以及不断演进的分配器支持——与一些实际问题之间进行比较,例如编译器引导构建、二进制体积,以及目前内核中 Rust 代码仍然占比极小。大家普遍认为,Rust 目前在内核中仍将保持可选且渐进的角色,作为一个试验场来推动这门语言及其工具链更适合底层系统工作。

Rust 版本管理与内核对不稳定特性的使用

  • 对于使用稳定版 Rust 的普通项目,编译器升级大多保持向后兼容;像 clippycargo fmt 这样的工具有助于跟踪风格和 lint 变化。
  • Rust-for-Linux 刻意使用 nightly/不稳定特性,因此升级时可能需要非平凡的修复。
  • 这被视为必要之举,用来推动缺失的特性(例如 offset_of、分配器 API)得到实现并帮助它们走向稳定。
  • 引用的估算:在大型代码库中,升级编译器大约每百万行 Rust 需要 ~0.5 小时;由于使用 nightly,Rust-for-Linux 的开销更高。

分配器与内存处理

  • 内核需要细粒度、可失败、按对象类型分配的能力,这推动它转向不稳定的 Allocator API,而不仅仅是 GlobalAlloc
  • allocator_api 提供了可失败构造(例如 try_new)和稳定 API 所不具备的灵活性。
  • 标准库本身允许使用不稳定特性;第三方 crate 在稳定版上则不可以。

二进制体积与依赖

  • 许多关于 Rust 二进制体积的抱怨与以下因素有关:
    • 调试/ panic 机制(例如回溯、支持 Unicode 的格式化)。
    • 对 std 的静态链接。
    • 庞大的依赖树和单态化。
  • 在 no-std 场景(微控制器、内核)中,二进制可以小得多。
  • 去除调试信息/拆分调试信息以及即将到来的 Cargo 默认设置会减小体积;但与 C 相比,Rust 的 “hello world” 仍然有相对较大的固定开销。
  • 有些人认为庞大的构建树和缓存(数百 MB)是有问题的;也有人指出这与现代工具链相当,而且内核中的 Rust 不会引入庞大的依赖图。

内核中 Rust 的范围与结构

  • 当前 Rust 代码只占内核极小的一部分(大约占总行数的 ~0.03–0.05%)。
  • 其中大多数是基础设施;Rust 驱动仍只是“舍入误差”,例如 Android binder 的重写。
  • 内核使用 core 和自定义的 alloc,但不使用 std

引导构建、LFS 与工具链

  • 有人担心 Rust 的引导构建故事“很难看”,可能会威胁 Linux From Scratch(LFS)。
  • 反方观点:LFS 本来就假定宿主机上有 C 编译器;同样也可以假定宿主机上有 Rust 编译器,并且只用 rustc 生成目标文件。
  • 与引导构建其他复杂编译器(例如 GHC)相比,Rust 的情况虽然受到批评,但并不独特。

底层安全、指针与语言选择

  • 关于不安全指针操作与宏 vs 安全指针算术的讨论,凸显了细微的 UB 和性能权衡。
  • 对 Rust 库分层的澄清:core(语言原语)、alloc(堆类型)、std(依赖操作系统的特性)。
  • 有人希望的不只是语言重写,而是像 seL4 那样的形式化验证。
  • 提出了一个问题:“为什么选择 Rust 而不是 Zig?”
    • 一方看重 Rust 强大的内存安全保证。
    • 另一方则认为内存 bug 可以通过测试来处理,并且 Rust 的安全性也有自身权衡;双方未形成共识。