c2Rustは、C99準拠のコードのRustへのマイグレーションを可能にするオープンソースプロジェクトだ。比較的新しいこのツールの開発を通じて、開発者たちは、C言語の記述方法に関するいくつかの教訓を得るとともに、それをABIレベルでRustに置き換える可能性に関する現在の限界について探ることができた。
c2rustの背景にある根拠は、システムソフトウェアのインクリメンタルな移行を実現し、メモリ破壊を可能な限り除去することによって、よりセキュアなものにする、というものだ。速度や互換性で妥協することなくメモリ安全性を組み込んだRustは、この目的に最適な候補のひとつとなのだ。特に、メモリ管理をガベージコレクションや参照カウンタに依存していないため、それらを使用する多くの言語で問題となるような、FFI(Foreign Function Interface)経由でのCおよびC++との互換性には非常に優れている。一方で、手作業によるコード変換は時間と費用を要するプロセスである。rust2c
は、そのファーストステップを支援しようというものだ。
私たちの目標は、既存のCコードをRustで簡単に実行できるようなツールを開発することです。変換や書き直しのプロセスの大部分を自動化することで、レガシシステムの移行を、最小限の労力で可能な、現実的かつスケーラブルなものにしたいと思っています。
実際にrust2cでは、luaやnginx、zstdといった複雑なソフトウェアでも、正確にトランスパイルして、修正する必要なく動作させることが可能なようだ。その他のケース、例えばQuake 3では多少の手直しが必要となる。また、Linuxカーネルモジュールの一部については、c2rust
ではオリジナルをトランスパイルすることはできない可能性がある。
ただし、実際のrust2c
は、非慣用的で安全でないRustへの変換が可能なだけである。Cの型システムが、基本的な仮定さえも行う上で必要な関連情報の多くを隠蔽してしまうため、それ以上の対応はできないのだ。例えばstrncpy
の宣言では、2つの引数destination
とsource
は実際には配列でなければならないのだが、この事実はジェネリックな文字ポインタ表記というシグネチャの裏に隠されている。
char* strncpy (char* destination, const char* source, size_t num);
これはつまり、安全で慣用的なRustコードの生成には手作業の介入が必要である、ということになる。これらのポインタが安全でない生のポインタではなく、コンパイル時に安全性が保証されるRustのベクタであるということを、自動ツールによって理解するための簡単な方法が存在しないからだ。
このような事実はあっても、rust2c
の開発者たちは、Rustへの自動変換には意味があると主張している。リファクタリングのためのベースを提供することで、より厳密なコンパイラによる作業支援が受けられるから、というのがその理由だ。
ただし、安全でないRustコードであっても、すべてのCコードが正しく変換できる訳ではない。これは自動トランスパイルのみの問題ではなく、Cとの完全なABI互換を備えた代替としてRustを使用する可能性にも影響するもので、2つの言語の機能的同等性を阻害する多くの問題に関連している。具体的には、多様な浮動小数点表現が存在すること、シンボルエイリアスやパック構造体(packed structure)やグローバル変数のアライメントなど、GCC拡張が提供する機能、静的ライブラリのサイズなどがある。c2rust
開発者の分析によると、これらはすべて、既存のCプログラムやライブラリの多くに見られるものだ。
rust2c
の開発チームは、rust2c
の生成したコードから安全でない部分を取り除くためのリファクタリングツールの開発にも取り組んでいる。このツールはリファクタリングを適用する多数のコマンドをサポートし、一部については非慣用的なRustコードに付加された特殊なアノテーションを利用する。
rust2c
はそれ自体Rustで記述されており、LinuxとmacOSにインストールすることができる。実行にはRust nightlyが必要だ。