How Our Rust-to-Zig Rewrite Is Going
508 points • 1 day agoArticle Link

Roc 编程语言背后的团队达成了一个重要里程碑:在将编译器从 Rust 重写为 Zig 的过程中已实现功能对等。历时十八个月、编写了约 30 万行代码,这次迁移标志着项目发展的重大转折。尽管与其他项目的快速重写相比工作量更大,但重写决定源自对基础架构进行根本性调整以提升性能和语言特性的需求。团队正期待在今年晚些时候发布官方 0.1.0 。

转向 Zig 的主要原因是需要更细粒度的内存控制以及更快、更稳定的编译。虽然 Rust 的 borrow checker 在安全性上很出色,但为优化诸如 polymorphic defunctionalization 这样的性能关键任务,Roc 编译器不得不大量使用 unsafe 代码块和自定义内存分配器。 Zig 在生态上将这些内存模式视为常态,并且通过增量编译(incremental compilation)等手段,其构建时间已显示出远超此前 Rust 配置的潜力。

此次迁移带来的核心创新之一是 zero-parse deserialization 。借助以无指针数组形式组织的特定数据结构,编译器能够将缓存的构建结果直接加载到内存,基本上以磁盘 I/O 的速度运行。该方法技术上复杂,但绕过了传统解析开销,从而实现极快的增量重建。项目还利用 Zig 简化了 cross-compilation,以最少的配置为包括 WebAssembly 在内的多个平台生成一致的 static binaries 。

在内存安全方面,团队的实际感受与预期一致。尽管 Rust 常因其安全性受到赞誉,编译器开发的性质却包含一些 borrow checker 无法完全消除的固有风险,尤其是涉及生成的 machine code 的正确性。通过在 safety-checking 模式下使用 Zig,团队得以维持较高的稳定性。迁移并未引发内存相关问题的激增,这表明对于这个高度专业化的项目而言,与 Zig 设计理念在架构层面的契合,弥补了放弃 Rust 编译时内存保证的代价。

这次转型并非没有取舍,开发者确实怀念 Rust 的一些便利,例如测试中自动处理的 drop 逻辑、 private struct fields 以及在发布时更成熟的向后兼容规范。但相比获得的收益,这些被视为可以接受的代价。 Zig 的"减法"设计避开了像 macros 这样复杂的特性,转而依赖 comptime 和对 data layout 的直接操控,这与团队目标高度契合。该决定让他们重新掌控构建流水线,并采用更高效、以 allocator 为中心的编程风格,更好地满足现代编译器的特殊需求。

269 comments • Comments Link

• 关于编译器本质上需要内存不安全代码的说法备受质疑——生成机器码本质上是写入数据的操作,并不必然要求使用不安全操作。

• 虽然在热替换(hot-swapping)或性能关键的运行时内部组件中可能会使用 unsafe 块,但编译器的核心逻辑(如解析和代码生成)在很大程度上仍可保持高层抽象并保持安全。

• 必须区分编译器自身的内存安全性与其生成的二进制的安全性。一个内存安全的编译器即便生成了含漏洞的代码,仍然有价值,因为它能隔离并减少错误的攻击面。

• "不安全"(unsafe)一词常被误解为等同于"低级"(low-level),由此产生的误导让人以为任何系统级工作都必须放弃语言层面的内存保护。

• Zig 的 ReleaseSafe 模式对某些错误提供运行时检查,但它并不能像 Rust 的借用检查那样,提供全面的时序内存安全,例如无法完全防止所有的 use-after-free 情形。

• 编译器性能主要由算法效率决定,而不是语言本身的"低级"特性。历史上有带垃圾回收的高级语言成功用于编译器开发,这挑战了为性能必须使用系统语言的观点。

• 从一种稳定成熟的语言迁移到尚未到达 1.0 的语言风险很大,因为破坏性变更和不稳定的生态可能破坏长期维护性和生产可靠性。

• 快速增量构建(如 Zig 展示的那样)能显著提升开发者生产力,尽管 Rust 也在积极改进构建性能和工件管理。

• Rust 在大量使用泛型和复杂类型系统时,可能在大型项目中带来显著的编译时开销,这促使一些人在特定领域(如 Web 后端)考虑更精简或更简单的替代方案。

• 行业内正经历语言采纳的周期,团队会根据当前项目的瓶颈在编译速度、内存控制与安全保证之间权衡,从而重新评估并可能迁移现有工具链。

核心争论在于:使用 Rust 这样的内存安全高级语言与使用 Zig 这样的底层手动管理语言之间的权衡,能否通过最终的性能与安全成果来证明其合理性。虽然各方普遍认同编译器性能至关重要,但关于内存安全是否是现代工具的根本瓶颈或必要保障存在明显分歧。许多观察者指出,编译器的架构与算法设计仍然是决定速度的主要因素,这表明语言选择往往次于实现者的能力。最终,这场讨论凸显了追求"无畏安全"与满足快速迭代及构建性能的现实需求之间的持久张力。