
Linux 内核由3600万行C语言代码构成。自Linux 6.1版本起,Rust语言开始逐步融入内核,但进展仅限于个别驱动程序和抽象层——每个发布周期增加几千行代码。如果你跳过渐进式方法,直接让Claude重写主要子系统会如何?我利用空闲时间,将这个想法做了一个规划:将内核分解成可翻译的单元,估算令牌成本,识别潜在风险,并测试Claude把真实内核C代码翻译成Rust的能力。结论是:Claude能够以惊人的准确性翻译孤立的、定义良好的内核模块。它不能翻译整个内核。
这是一个有意义的命题
Linux 内核中已经存在Rust代码了。Linus Torvalds在Linux 6.1(2022年12月)中合并了对Rust的初步支持。截至2025年,已经存在适用于Android Binder、Apple GPU、NVMe、9P文件系统和几个网络驱动程序的Rust驱动程序。Rust-for-Linux项目已经在内核的C API上构建安全的抽象层三年了。
瓶颈不在于Rust是否属于内核。瓶颈是开发者的时间。每个Rust抽象都需要一个深刻理解C内核内部和Rust所有权模型的人来产生正确、安全的翻译。世界上可能只有几百人具备这种技能组合,他们中的大多数人还有日常工作。
LLM是否能压缩翻译的时间?我们要讨论的关键不是要取代这些专家,而是通过生成专家可以审查并加以完善的初稿,而不是让他们从头开始撰写。
问题的范畴
Linux 内核(v6.12)大约是:
仅驱动程序就占代码库的58%。特定于架构的代码是另外12%。“核心内核”——调度器、内存管理器、IPC和进程模型——只占总行数的3%,但包含了95%的复杂性。
翻译单元问题
你不能将3600万行C代码输入Claude并得到Rust代码。上下文窗口不是这样工作的,即使它们可以,内核也不是线性程序——它是一个深度相互连接的子系统图,具有隐式契约、未记录的不变性,以及几十年积累的行为,代码依赖于这些行为,但并未明确说明。
第一个问题是:正确的翻译单元是什么?
选项1:文件对文件
将每个.c文件单独转换为.rs文件,看似简单直接,但这种方法很快就遇到了困难。内核中的C文件依赖于数十个头文件、多个目录层级上定义的宏、特定架构代码中的内联函数,以及跨子系统共享的全局状态。单独处理文件时,大部分上下文信息都会丢失。
为了验证这一点,我让Claude翻译了kernel/sched/fair.c文件,这是完全公平调度器的实现。该文件长达12,000行。Claude生成了语法上正确的Rust代码,但为了它无法识别的每个内核API,它都生成了抽象(例如struct rq、struct task_struct、struct cfs_rq)。编译时,这些代码使用了占位符类型,但语义正确性几乎为零。它看起来像Rust代码,却缺乏实质内容。
选项2:子系统对子系统
将整个子系统——CFS调度器、ext4文件系统、TCP/IP栈——作为一个单元进行翻译。给Claude提供子系统的源文件以及它依赖的头文件。
这样更好,但触及了上下文窗口。TCP/IP网络栈大约有200,000行代码,分布在约400个文件中。即使Claude有200K令牌的上下文窗口,你大约可以放入50,000到70,000行C语言代码(令牌不是字符,C语言有很多结构开销)。一个子系统通常就超过了窗口。
选项3:模块化
内核的模块系统提供了清晰的界限。一个可加载的内核模块(LKM)设有明确的入口点(module_init)和退出点(module_exit),并通过有文档记录的API与内核的其他部分进行交互。模块的规模从200行(一个简单的字符设备)到50,000行(一个复杂的文件系统驱动)不等。
这是正确的翻译单元。模块大小在5,000行以下,连同它们的头文件依赖项,可以舒适地适应上下文窗口,API界面清晰,行为可以在隔离中进行测试。
我通过三个不同复杂度的真实内核模块来验证这一点。
测试1:一个简单的字符设备驱动程序
最简单的内核模块:一个/dev/null风格的字符设备,它接受写入并丢弃它们。
「源代码」:大约150行C代码 「Claude的Rust输出」:大约180行Rust代码 「裁决」:正确
Claude利用kernel crate的抽象生成了一个清晰的Rust翻译。它正确地将file_operations映射到Rust特性实现,使用Box<T>进行堆分配而不是kmalloc/kfree,并利用UserSlicePtr处理__user指针复制。所有权模型自然地强制执行了C版本用显式的goto err链处理的清理。
这是令人鼓舞但不足为奇的。字符设备驱动程序是内核编程的“hello world”,Rust-for-Linux项目有大量的例子。
测试2:一个网络驱动程序(virtio-net风格)
一个简化的网络驱动程序,处理带有DMA环形缓冲区的数据包TX/RX,中断处理和NAPI轮询。
「原文」:约2,400行的C代码 「Claude的Rust输出」:约3,100行的Rust代码 「裁决」:部分正确
Claude处理了高层次结构:设备注册、探测/移除生命周期、中断处理程序注册。NAPI轮询循环在结构上是正确的。DMA缓冲区管理是它遇到困难的地方。
C版本使用dma_alloc_coherent并手动管理物理/虚拟地址对。Claude将其翻译成Rust,但无法强制执行DMA缓冲区在设备可能仍在写入时不得释放的不变性。在C中,这是通过约定和在拆除路径中仔细排序来管理的。在Rust中,这应该由类型系统强制执行——但Claude产生的翻译使用了unsafe块来绕过借用检查器,而不是设计类型使不变性无法表示。
这是核心翻译问题。正确的C到Rust翻译不是句法上的。它需要理解C代码通过程序员纪律强制执行的不变性,并将它们编码到Rust的类型系统中。Claude翻译了代码,但需要一个人来翻译不变性。
测试3:一个文件系统(简化的ext2风格)
一个最小的只读文件系统,具有超级块解析、inode查找、目录遍历和块读取。
「原文」:约4,800行的C代码 「Claude的Rust输出」:约5,600行的Rust代码 「裁决」:结构上健全,语义上不完整
超级块解析和inode读取是正确的——这些本质上是数据结构翻译,带有字节序处理,Claude完美地完成了这一点。目录遍历工作。块分配是只读的,所以没有测试困难的部分(日志记录、写入排序、fsync语义)。
问题出现在VFS集成中。Linux VFS层期望文件系统实现在struct super_operations、struct inode_operations和struct file_operations中设置函数指针。Claude将这些映射到了Rust特性,但生命周期注解是错误的——它创建了自引用结构,其中超级块持有对inode的引用,inode又持有对超级块的引用。这在C中可以编译(裸指针,程序员管理生命周期),但在Rust中无法编译(借用检查器拒绝循环引用)。
正确的解决方案涉及Arc<T>用于共享所有权或Pin<Box<T>>用于自引用类型。没有关于所有权图的明确提示,Claude无法得出这个结论。当我在提示中描述了生命周期关系时,它在第二次尝试中产生了一个正确的基于Arc的设计。
难以逾越的高墙
高墙1:内联汇编
内核包含大约50,000行跨架构特定路径的内联汇编。上下文切换、中断处理程序、TLB刷新、内存屏障和原子操作都需要汇编。Rust通过core::arch::asm!支持内联汇编,但翻译不是机械的——GCC中的x86内联汇编使用AT&T语法,与Rust基于LLVM的内联汇编有不同的约束字母。Claude经常产生混合了两种语法的汇编。
对于这种规模的项目,内联汇编需要由架构专家翻译,而不是由LLM完成。
高墙2:宏密集型代码
内核的宏系统不仅仅是语法糖。例如,container_of、list_for_each_entry以及READ_ONCE/WRITE_ONCE等宏,都编码了安全契约。container_of执行的是不安全的指针算术,依赖于结构体布局的保证。READ_ONCE和WRITE_ONCE则为数据竞争强制执行易失性语义。锁定宏(如spin_lock_irqsave、rcu_read_lock)则编码了临界区的边界。
Claude 翻译的是宏的展开,而非契约本身。它将 container_of 转换为 Rust 中的 unsafe 指针运算,这在技术上是正确的,但却错失了在类型系统中编码容器关系的机会。一个有经验的 Rust 开发者可能会使用泛型 Container<T> 类型或者一个派生宏,使得这种关系在编译时即可检查。
壁垒 3:并发模型
Linux 内核的并发模型建立在自旋锁、RCU(读-复制-更新)、原子操作和因架构而异的内存排序保证之上。RCU 尤其复杂:读者通过推迟销毁直到所有可能的读者都完成来在无锁的情况下访问共享数据。“所有可能的读者都完成”这一部分是通过跟踪跨 CPU 的宽限期来确定的。
Rust 的所有权模型能够表达这些模式中的一些(kernel crate 包含了 Mutex<T>、SpinLock<T> 和 RCU 抽象的工作),但 Claude 一直退回到将 C 风格的 RCU 模式包装在 unsafe 中,而不是利用 Rust 的类型系统来强制执行读取/宽限期契约。每个 unsafe 块都是 Rust 重写没有比 C 原始版本提供更多安全性的地方。
壁垒 4:行为等价
最难的问题不是产生可以编译的 Rust 代码,而是产生在所有条件下都与 C 代码行为相同的 Rust 代码——包括因为在过去 30 年部署在数十亿设备上的经验而发现的未记录的边缘情况。
当写入被电源故障中断时,ext4 文件系统在中期日志提交中有特定行为。当 TCP 栈在 TIME_WAIT 期间接收到一个 RST,且序列号落在特定窗口时,它有特定行为。当实时任务的优先级上限与不同 CPU 上的 PI-boosted 互斥锁持有者冲突时,调度器有特定行为。
这些行为不在注释中,也不在文档中,它们只存在于代码和测试套件中(而这些测试套件本身也是不完整的)。Claude 无法翻译它无法观察到的行为。一个在语法上正确的 Rust 翻译,如果改变了这些行为,就是一种退步,而这些退步中的一些只有在特定硬件上承受生产负载时才会显现出来。
token经济学
抛开硬性限制不谈,原始的经济学也很有趣。
对于翻译内核的大约3600万行 C 代码的一个保守估计:
- 平均每行 C 代码(包括头文件)有 1.5 个token → 每次传递大约有 5400 万个输入token
- 需要多次传递(初始翻译,审查反馈,迭代)→ 总共大约需要 1.5 亿个输入token
- 输出大致等于输入 → 大约 1.5 亿个输出token
- Claude Opus API 定价:每百万输入 15 美元,每百万输出 75 美元(截至 2026 年初)
- 「估计 API 成本:仅token成本就高达 1350 万美元」
这不是一个错别字。仅token成本就高达 1300 万美元,以产生一个仍需要数千专家小时审查的初稿。
相比之下,美国国防部每年大约花费 1500 万美元通过各种合同加强 Linux 内核的安全性。Linux 基金会的整个年度预算大约为 2.5 亿美元。一个 LLM 辅助的内核重写将耗费生态系统总资金的一个有意义的部分。
如果你将范围限定在关键子系统上,成本会大幅下降。核心调度器、内存管理器、网络栈和安全模块总共约 350 万行——大约是完整内核的 10%。针对这些子系统的针对性重写将耗费大约 130 万美元的token,这在一个资金充足的安全计划范围内。
这实际上教会了你什么
以上探讨还只是一个初步的分析,而不是一个项目计划。但这个练习揭示了关于 AI 辅助系统编程的三个实际见解:
1. 翻译粒度决定质量
Claude 在模块级别(< 5,000 行,具有清晰的 API 边界)产生出色的输出,在子系统级别(< 50,000 行,带有头文件上下文)产生可接受的输出,在系统级别(> 100,000 行,具有隐式依赖)产生无用的输出。这不仅适用于内核——任何大型 C/C++ 代码库都会遵循相同的模式。如果您计划进行 AI 辅助的重写或迁移,请将工作分解为适合上下文窗口并包含完整依赖关系的单元。
2. 不变翻译是真正的工作
将C语言的语法转换为Rust语言是一项机械性的任务,Claude在这方面表现出色。然而,将C语言的约定(程序员强制执行的不变性、隐式契约、未记录的排序要求)转换为Rust的类型系统保证,则是一个实际的工程挑战。当您在提示中明确描述不变性时,Claude能够完成这项工作。它不能仅从代码本身推断出不变性,因为根据定义,不变性是代码维护但不声明的属性。
这意味着在重写项目中最有价值的LLM用途并非“翻译这个文件”。而是“这是文件,这是它维护的三个不变性——产生一个Rust翻译,其中类型系统强制执行这些不变性”。人类的工作从编写Rust代码转变为阐述不变性。
3. “正确的翻译”并非“即插即用替代品”
一个正确翻译自C文件的Rust文件并不一定是它被插入的Rust系统的一个正确组件。接口发生了变化。错误处理模型发生了变化。内存分配模型发生了变化。每个翻译的模块都需要一个适配层来与周围的模块集成——无论这些邻居是否仍然是C还是已经变成了Rust。适配层是大多数错误所在的地方,也是Claude最不擅长生成的部分,因为它需要同时理解旧系统和新系统。
现实版本的样子
如果我真的在认真计划这个(我没有),方法将会是:
「第一阶段 – 抽象(第1年)」:扩展Rust-for-Linux的kernel crate以覆盖完整的内核API表面。这已经在自然发生。Claude可以通过从C头文件生成安全的包装器实现来加速这一过程,人类负责审查和修正生命周期注释。
「第二阶段 – 叶子驱动(第1-3年)」:翻译15,000多个硬件驱动,这些驱动本质上是依赖图中的叶子节点。这些驱动对内核API表面的需求很小,行为定义明确。Claude处理这些驱动表现良好。许多驱动可以在轻微的人类审查下被翻译。
「第三阶段 – 文件系统(第2-4年)」:从简单的文件系统(tmpfs, procfs)开始翻译,逐步向复杂的文件系统(ext4, btrfs, XFS)发展。每个文件系统都是一个自包含的子系统,具有定义的VFS接口。Claude在处理日志记录和写入顺序不变性时需要大量的人类指导。
「第四阶段 – 网络(第3-5年)」:TCP/IP栈、数据包过滤和网络设备模型。这是行为等价变得至关重要的地方。网络边缘情况的测试表面是巨大的。
「第五阶段 – 核心(第5-8年)」:调度器、内存管理器和进程模型。最后处理这些,因为它们是最相互连接的,对性能最敏感的,并且最难测试行为等价性。这些可能需要由人类编写,Claude提供初稿。
总估计时间表:在AI协助下8-10年,与Rust-for-Linux社区目前估计的有机采用的20-30年时间范围相比。
真正的价值
这个项目有趣的版本不是用Rust重写Linux。而是利用这个练习来构建更好的系统编程工具,使用LLMs。
如果内核翻译项目产生了:
- 一种「正式的不变式语言」,与C代码并行存在,描述代码维护的契约,LLMs可以阅读并在翻译中强制执行?
- 一个「行为等价测试框架」,能够验证Rust翻译是否与C原始代码在成千上万的边缘情况下的行为相匹配,这些边缘情况是从C代码的控制流自动生成的?
- 一个「类型系统映射工具」,它采用C模式(锁排序、RCU读取部分、DMA缓冲区生命周期)并生成相应的Rust类型约束?
这些工具的价值将超过翻译后的内核本身。它们将适用于每一次C到Rust的迁移,不仅仅是Linux。
这才是真正有意义的。不是“重写Linux。” 而是重写系统代码的重写过程。
结语
Claude能否用Rust重写Linux?不,Claude无法用Rust重写整个Linux系统。但是,Claude能够通过生成有界限的模块初稿,然后由人类进行审查和完善,从而显著加速Rust-for-Linux的进程。目前,对于占代码库60%以上的叶子节点组件,这一方法已经可行。核心内核子系统仍然是一个需要人类工程师来解决的问题——但随着AI处理越来越多的驱动程序,这个问题的范围将会逐渐缩小。
内核最终将用Rust重写。问题是,这需要25年的有机努力还是10年的AI加速努力。登月行动说,答案取决于我们能否清晰地表达30年来C程序员脑海中携带的不变式。