プログラミング
crustc: rustc 全体をC言語に翻訳
crustc: entirety of `rustc`, translated to C (github.com)
要約
このプロジェクトは、Rustコンパイラであるrustcを4600万行のC言語コードに変換した「crustc」を紹介しています。これはGCCとmakeでビルド可能な、機能するRustコンパイラです。この成果は、Rustコードを任意のターゲット向けにC言語へコンパイルする新しいツールチェーン「cilly」のデモンストレーションであり、特にLLVMやGCCのサポートがない古いハードウェアや特殊な環境へのRustの移植を可能にすることを目的としています。
全文翻訳
crustc - rustc 1.98.0-nightly (c712ea946 2026-06-16)、4600万行のC言語に変換されました。これはGCCとmakeでビルドできる、機能するRustコンパイラです。
LLVM(libLLVM.so.22.1-rust-1.98.0-nightly)へのパスを提供する必要があります。
プロジェクトにプリビルドされたLLVMを含めることもできましたが、プロジェクトにランダムなバイナリを埋め込むのは避けたいです。
make -j20 LLVM_LIB_DIR=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib
これは単なるCコード[1]であり、コンパイルすると機能するRustコンパイラが得られます。
(libLLVM.so.22.1-rust-1.98.0-nightlyを指すライブラリパス - rustcはllvmを使用します)
LD_LIBRARY_PATH=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib:./rustc_driver ./rustc/rustc --version
rustc 1.98.0-nightly (c712ea946 2026-06-16)
そのRustコンパイラはコードをコンパイルできます - core、alloc、stdをビルドするなど!
これは何ですか?
これは、私の新しいRustからCへのコンパイラツールチェーンのデモ/ティーザーです。完全なcillyツールチェーンは、任意のターゲット向けに独自のRustをCにコンパイルします。このリポジトリは、コンパイラが自身をコンパイルする様子を示すだけで、私ができる最も派手なショーケースだと信じているからです。
どうやってこれを実現したのですか?
過去3年間、RustをCにコンパイルすることに取り組んできました。rustc_codegen_clrのようないくつかの公開された試みと、多くの非公開の試みを行いました。これは私の計算では14回目の試みです:cillyです。これはC言語コードを生成するためのRustライブラリであり、RustをCにコンパイルできるRustコンパイラバックエンド(つまりプラグイン)です。
cillyの主な革新は、Cコンパイラに適応することです。これは、「証拠」プログラムを生成し、特定のコンパイラとプラットフォームが何をサポートしているかを確認します。
/* これは、Cコンパイラが_Thread_localをサポートしている場合にのみコンパイルされます。 */
_Thread_local int KEYWORD_TLS_SUPPORTED;
これにより、Cillyは特定の、奇妙な「Blorbo OS用のShminky Cコンパイラ」を満足させるCコードを生成します。
/* これは一部のCコンパイラでパスします。 */
assert(sizeof(float) == sizeof(double));
すべての型レイアウト、サイズ、アラインメント、文字エンコーディング(ASCII)、および整数フォーマット(2の補数)が照会されます。可能な場合はフォールバックを使用します。
ANSI C[2]の外にあるもの(厳密なエイリアシングのような「モダン」C標準の回避策を含む)を仮定しないように最善を尽くしています。残念ながら、これはcillyの出力がコンパイラ固有であることを意味します(つまり、Arm64用に生成されたcilly Cをriscv32で実行することはできませんが、riscv32用にcilly Cを生成することはできます)。
このrustcのビルド(生成されたC)は、私のワークステーションのISAであるため、ARM64 Linuxを「ターゲット」としています。
なぜこれを行ったのですか?
この主な目標は、LLVM/GCCのサポートがない古い/マイナーなハードウェアをサポートすることです。まだRustをサポートしていないがCをサポートしているシステムがいくつかあります。プロジェクトがRustからCに移行したり、CプロジェクトのRust代替が作成されたりすると、それらのターゲットのサポートはRustの欠点として正当に提起されます[3]。このプロジェクトの目標は、その問題を解消することです。
cillyはrustcとCコンパイラをラップし、オンザフライでRustコードをCに変換します。ユーザーの観点からは、指定されたターゲットに使用するCコンパイラを定義するのと同じくらい簡単です。
"triple": [ "sdcc_z180-unknown-none" ],
"tool_def": {
"kind": "local",
"compile": {
"base": {
"executable": "/usr/bin/sdcc",
"base_args": [ "-mz180", "--std-c89", "-c" ],
"input_arg_template": [ "{input}" ], // JSONは簡潔にするためにカットされています。
}
}
}
ネットワーク透過性。
cillyはネットワーク透過であり、TCP経由でCコンパイラと通信できます(必要に応じてUARTのような奇妙なものに拡張される可能性があります)。これは、ブートストラップパラドックス/ Cクロスコンパイラのないプラットフォームのソリューションです。Blorbo OSで小さなCサーバーをビルドし、Linuxのような通常のプラットフォームでrustcを実行し、cillyがワイヤー経由で通信できるようにします。私はこれを、Arm64 Linuxでrustcを実行しながら、x86 Plan9 VM用に小さなRustプログラムをコンパイルするために成功裏に使用しました。
term% echo `{cat /dev/sysname} osversion `{cat /dev/osversion} cputype $cputype gnot osversion 2000 cputype 386 term% /tmp/hello_plan9 Hello, world!
term% nm /tmp/hello_plan9 | grep rust_begin_unwind
1020 T _RNvCshfEkAwg4zv6_7___rustc17rust_begin_unwind
Makefileの生成。
cillyはオプションでオブジェクトファイル内にマーカーを埋め込み、IRをキャッシュディレクトリに保存できます。その後、これらのマーカーを読み取り、定義場所ごとに関数/グローバルを分割し、CコンパイラとmakeでRustをビルドできるようにMakefileのディレクトリを生成できます。
ABI互換性
cillyによって生成されたコードは、ほとんどの場合、通常のrustcでコンパイルされたコードとABI互換性があります。ほとんどの場合と言ったのは、一部のプラットフォーム(arm64など)ではrustcがCから表現できないABIを選択するためです[4]。
再現の前提条件
このRustコンパイラは以下でビルドされました:
uname -a
Linux spark-2773 6.17.0-1021-nvidia #21-Ubuntu SMP PREEMPT_DYNAMIC Wed May 27 19:14:05 UTC 2026 aarch64 aarch64 aarch64 GNU/Linux
私が使用したCコンパイラはこれです:
readelf -p .comment ./rustc/rustc
String dump of section '.comment':
[ 1] GCC: (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
[ 2e] Linker: Ubuntu LLD 18.1.3
デモをビルドするには、適切なLLVMライブラリを提供する必要があります。最も簡単な方法は、rustcが提供するLLVMを使用することです:
rustup install nightly-2026-06-16
ビルド
適切なGCC(より新しいGCCバージョンも動作するはずです、未テスト)、適切なLLVMバージョン、およびGNU makeがインストールされている場合は、以下を実行します:
# LLVM(libLLVM.so.22.1-rust-1.98.0-nightly)へのパスを提供する必要があります。
# プロジェクトにプリビルドされたLLVMを含めることもできましたが、プロジェクトにランダムなバイナリを埋め込むのは避けたいです。
make -j20 LLVM_LIB_DIR=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib
# CFLAGSは動作します(注意:一部のフラグはコンパイルを遅くします)
make -j20 CFLAGS=-g
そして…出来上がり!
コンパイル速度
最適化を有効にしないことを強くお勧めします。それらはバグを引き起こす可能性があり(これは単なるデモであり、非常に…粗削りです[5])、最適化は大規模なスケールでは時間がかかるためです。最適化なしで、私のマシンはプロジェクトを数分でビルドします:
make -j20
937.98s user 123.77s system 1352% cpu 1:18.48 total
最適化を有効にすると、特定のより大きなRustファイルで詰まることが予想されます。ほとんどのコードは blitz しますが、それらの巨大なファイルで立ち往生します。
ビルドのテスト
実行します:
LD_LIBRARY_PATH=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib:./rustc_driver ./rustc/rustc --version
rustcのバージョンが表示されるはずです。プログラムをビルドするには、stdをビルドする必要があります。
LD_LIBRARY_PATH=~/.rustup/toolchains/nightly-2026-06-16-aarch64-unknown-linux-gnu/lib:./rustc_driver ./rustc/rustc main.rs
error[E0463]: can't find crate for `std`
| = note: the `aarch64-unknown-linux-gnu` target may not be installed
= help: consider downloading the target with `rustup target add aarch64-unknown-linux-gnu`
= help: consider building the standard library from source with `cargo build -Zbuild-std`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0463`.
BUILDING_STD.md を参照してください。
既知のバグ
奇妙なパス正規化の理由により、crustcはビルドされたディレクトリ(リポジトリのルート、crustc)で実行するとクラッシュすることがあります。他の場所では正常に動作します。
...私も混乱しています。
cillyを試すことはできますか?
いいえ、まだです。一般公開の準備はできていません。できるだけ早くリリースするつもりですが、仕事があります(つまり、GとCのキーが壊れたラップトップでコードを書くことはなくなりました、やったー!)。大学があります(夏休みですが、卒業論文は自分で書くものではありません)。左手をミキサーに入れました。ミキサーが勝ちました。(まだ指はすべてありますが、縫い目はいくつかあります)。これ以上詳しく説明しません。
注釈
1 - CコードといくつかのC++ LLVMラッパーです。Rustは、より多くのLLVMノブを公開するために少量のC++を使用します。これらはLLVMバージョン固有であり、スタンドアロンでビルドするのが面倒なため、プリコンパイルされて出荷されます。
2 - まれに、「合理的な仮定」をしなければならないことがあり、それは目標を停止させる可能性があります。例:(void*)(uintptr_t)(ptr)はラウンドトリップします。これらを文書化し、可能であればアサート(CHAR_BIT = 8)を追加します。
3 - 「RustはPlan 9をサポートしていない」という引数の重みは、Rustに反対する議論としては...