介绍 tmux-rs

2025 年 7 月 3 日
《Introducing tmux-rs》
作者:Collin Richards

  • 约 6 个月来,作者将 tmux 从 C 语言移植到 Rust 语言,现已完成 100%(不安全)Rust 代码基础,分享从约 67,000 行 C 代码到约 81,000 行 Rust 代码(不包括注释和空行)的移植过程。

    • Starting with C2Rust:以使用C2Rust工具开始项目,其输出代码虽能运行但难以维护且比原 C 代码大 3 倍,作者手动重构后仍需参考原 C 代码,最终放弃 C2Rust 输出,手动将文件从 C 翻译为 Rust。
    • Build process:重写的重要部分是理解项目的构建方式,使用autotools,通过build.sh脚本结合cargomake进行构建,早期尝试将代码拆分为小 crate 但发现将所有代码放在一个 crate 更简单,后来改为每次翻译一个函数并进行验证,还使用cc crate 构建 Rust 二进制文件并链接 C 库。
    • Interesting bugs:在翻译代码过程中引入了许多 bug,如函数翻译后程序出现段错误,原因是 C 代码使用了隐式声明导致类型不匹配;另一个 bug 是手动翻译结构体类型声明时遗漏了*,导致 C 和 Rust 代码对类型的看法不同。
    • C Patterns in Rust

      • Raw pointers:Rust 有两种引用类型&T&mut T,在将 C 代码移植到 Rust 时,由于 Rust 引用的不变量要求,不能直接使用 Rust 引用,而需使用*mut T*const T原始指针。
      • Considering Goto:C 中的goto在 tmux 代码库中的使用较为温和,c2rust transpiler 用算法模拟goto逻辑,多数情况下可使用更简单的方法实现goto的跳转,如向前跳使用带有break语句的标签块,向后跳使用带有continue的标签循环。
      • Intrusive Macros:Tmux 大量使用通过宏定义的两种数据结构,作者通过多次迭代实现了模仿 C 代码的良好 Rust 接口,遇到的挑战是处理一些实例可同时存在于不同容器的情况,通过使 trait 泛型来解决。
      • Yacc shaving:Tmux 使用yacc实现自定义配置语言解析器,作者最终使用lalrpop crate实现解析器,结构与yacc相似,还需实现适配器将 lalrpop 与自定义词法分析器接口。
    • Development process

      • Vim:在项目中使用 neovim 并依赖自定义宏加速翻译过程,如将ptr == NULL转换为ptr.is_null()等。
      • AI Tools:在开发后期尝试使用 Cursor,但感觉它没有增加速度,只是节省了手指疼痛,因为它会偶尔插入 bug,需要花费时间审查生成的代码,不过如果手指真的受伤,仍会使用它。
  • Conclusion:虽然代码已 100%为 Rust,但作者认为未达到主要目标,手动翻译的代码不比 C2Rust 输出好多少,且容易崩溃,下一个目标是将代码库转换为安全 Rust,已发布 0.0.1 版本供其他 Rust 和tmux爱好者使用。
阅读 11
0 条评论