概要
- tmux をCからRustへ完全移植した個人プロジェクトの紹介
- C2Rust による自動変換の限界と手動移植への切り替え経緯
- ビルドプロセス やC/Rust間連携の工夫と最適化
- バグ発生例 とその原因・解決策の具体的な解説
- Rust移植で直面した C特有パターン の扱いとRust流の実装手法
tmuxのRust移植プロジェクト「tmux-rs」紹介
- Collin Richards によるtmuxのC→Rust移植プロジェクト
- 元のCコード 約67,000行 を 約81,000行 のRust(unsafe)に変換
- 趣味として始めたが、 100% Rust化 という大きなマイルストーンを達成
- C2Rustによる自動変換を試すも、 可読性・保守性の低下 により断念
- 手動でC→Rust 移植を進める方針へ転換
C2Rust利用とその課題
- C2Rust はC→Rust変換ツールだが、セットアップや出力コードの品質に課題
- 例:定数名喪失(COLOUR_FLAG_256→0x1000000)、不要なキャスト多発
- 生成コードは 3倍の行数、可読性・保守性が著しく低下
- 意図把握のためC原文参照 が必須となり、手動リファクタリングに限界
- 結果として 全ファイル手動変換 を決断
- C2Rust自体は他プロジェクトで有用性を実感
ビルドプロセス最適化
- tmux は autotools ベースの複雑なビルドシステム
- Rust静的ライブラリ(staticlib)をMakefileに組み込み、 cargo→make の2段階ビルド
- ミニクレート分割 を試すも、循環依存・リンク問題で断念
- 単一クレート集中方式へ移行
- 関数単位の逐次変換&テスト でデバッグ効率化
- Rustバイナリ主導+Cライブラリ連携へとビルド手法を進化
- ccクレート 利用でC側の残存コードをRustからビルド
典型的なバグとその解決
- バグ例1:関数プロトタイプ不一致
- C側で関数宣言抜け→戻り値型不一致→ポインタ値破壊
- 原因:暗黙宣言(int返却)がRust側のポインタ返却と齟齬
- 対策: 正しい関数宣言追加
- バグ例2:構造体定義不一致
- CとRustでポインタ型を値型に誤訳→メモリアクセス誤り・セグフォ
- 対策: 型定義の正確な同期
C特有のパターンをRustでどう扱うか
- 生ポインタ(raw pointer)
- Rustの参照(&T, &mut T)は非null・有効性保証が必須
- C→Rust直訳では **生ポインタ(mut T, const T) を多用
- unsafeブロック下でのみ利用可能、 安全性担保に注意
- gotoの移植
- CのgotoはRustでは ラベル付きbreak/continue で表現可能
- 複雑なフローは紙に書き出して変換
- 侵入型データ構造(Intrusive Macros)
- CのマクロベースのRed-Black TreeやリストをRust流に再現
- 構造体内部にコレクション用フィールドを持たせる設計
開発ワークフローとツール
- 関数単位でC→Rust変換→即ビルド&テスト の反復
- エディタは Vim、AIツールも一部活用
- ビルドスクリプト やCI設定も適宜調整
まとめ
- tmux-rs はC→Rust手動移植の実践知・ノウハウの宝庫
- C2Rustなどの自動変換ツールの限界と手動変換の意義
- 型・ビルド・バグ対応・設計パターン移植のポイント
- Rust移植で得られる 安全性・拡張性 の実感
- 今後のRust移植プロジェクト の参考事例