1 ポイント 投稿者 GN⁺ 3 시간 전 | 1件のコメント | WhatsAppで共有
  • crustcは、rustc 1.98.0-nightly (c712ea946 2026-06-16) 全体を 4,600万行のCコード に変換したデモで、GCCmake でビルドすると動作する Rust コンパイラが生成される
  • 基盤ツールである cilly は、Rust を C にコンパイルする Rust コンパイラバックエンド であり、このリポジトリはコンパイラが自分自身をコンパイルする最も目立つショーケースとして構成されている
  • cilly は対象の C コンパイラとプラットフォームの型レイアウト、サイズ、アラインメント、文字エンコーディング、整数形式などを witness プログラム で問い合わせ、特定の C コンパイラが受理できる C コードを生成する
  • 主な目標は、LLVM/GCC のサポートはないが C コンパイラはある 古い、または特殊なハードウェア で Rust を使えるようにすることで、TCP 経由でリモートの C コンパイラと通信するネットワーク透過性も含まれる
  • 現在生成される C は、作者のワークステーションの ISA である ARM64 Linux を対象としており、cilly のツールチェーン全体はまだ一般公開向けの準備ができておらず、最適化関連のバグも追跡中である

rustcをCに変換したデモ

  • crustc は、rustc 1.98.0-nightly (c712ea946 2026-06-16)4,600万行のCコード に変換したリポジトリである
  • この C コードは GCCmake でビルドでき、ビルド結果は動作する Rust コンパイラ になる
  • 実行例では LLVM ライブラリのパスを指定したうえで ./rustc/rustc --version を実行し、同じ rustc 1.98.0-nightly バージョンを出力している
  • 生成された Rust コンパイラは、コードのコンパイル、coreallocstd のビルドが可能である
  • コードには C コードのほかに一部の C++ LLVM ラッパー も含まれる
    • Rust が LLVM の一部機能を公開するために C++ を使っている
    • そのラッパーは LLVM バージョンに依存しており、単独ビルドが煩雑なため、事前コンパイル済みの状態で提供される

cillyの役割

  • crustc は、新しい Rust-to-C コンパイラツールチェーン cilly のデモ / ティーザーである
  • cilly ツールチェーン全体は、ユーザーの Rust コードを任意のターゲット向けに C へコンパイルすることを目指している
  • このリポジトリは、cilly がコンパイラ自身をコンパイルする様子を示すために構成されている
  • cilly は Rust ライブラリであり Rust コンパイラバックエンドでもあり、つまりプラグインの形で Rust を C にコンパイルする
  • 作者は過去 3 年間 Rust を C にコンパイルする作業を続けており、rustc_codegen_clr のような公開された試みや複数の非公開の試みを経て、cilly が 14 回目の試みだと述べている

Cコンパイラに合わせてコードを生成する仕組み

  • cilly の主な特徴は、C コンパイラに適応 する点である
  • 特定のコンパイラとプラットフォームが何をサポートしているかを確認する witness プログラム を生成できる
    • 例として _Thread_local int KEYWORD_TLS_SUPPORTED; があり、その C コンパイラが _Thread_local をサポートする場合にのみコンパイルされる
  • cilly は、特定の C コンパイラが受理できる C コードを生成しようとする
  • 型レイアウト、サイズ、アラインメント、文字エンコーディング、整数形式が問い合わせ対象である
    • 文字エンコーディングについては ASCII かどうかを確認する
    • 整数形式については two's complement かどうかを確認する
  • 可能な場合はフォールバックを使う
  • ANSI C の外にある仮定を避けようとしており、strict aliasing のような現代 C 標準に関わる動作にも回避策を用意している
  • まれに (void*)(uintptr_t)(ptr) の往復変換のような 合理的な仮定 が必要になる場合がある
    • そのような仮定は文書化し、可能なら CHAR_BIT = 8 のような assert も追加する

ターゲットごとのCコードとABI制約

  • cilly の出力する C コードは コンパイラごと である
    • Arm64 向けに生成した cilly の C を riscv32 でそのまま実行することはできない
    • riscv32 向けの cilly の C を別途生成することは可能である
  • このリポジトリの rustc 生成 C は、作者のワークステーションの ISA の都合で ARM64 Linux を対象としている
  • cilly が生成したコードは、通常の rustc がコンパイルしたコードとおおむね ABI 互換である
  • 一部のプラットフォームでは、rustc が C で表現できない ABI を選ぶため、完全な互換性は難しい
  • Arm64 では、構造体返却ポインタである sret のために制約がある
    • 多くのプラットフォームでは sret は第 1 引数と同じレジスタで渡されるため、第 1 引数を出力ポインタにする方式が可能である
    • Arm64 では sret ポインタは別のレジスタで渡される
    • ネイティブ C コンパイラが小さな構造体に対して return-by-sret を選ぶ必要があるが、16 バイト未満の小さな構造体ではそうしないと説明している

古い、または特殊なターゲットのサポート

  • このプロジェクトの主な目標は、LLVM/GCC のサポートはないが C はサポートしている 古い、または特殊なハードウェア で Rust を使えるようにすることである
  • あるプロジェクトが Rust から C へ移行したり、C プロジェクトの Rust 代替が作られたりする際、そうしたターゲットのサポート不足は Rust の弱点として挙げられることがある
  • cillyrustc と C コンパイラをラップし、Rust コードをその場で C に変換する
  • ユーザー視点では、特定ターゲット向けに使う C コンパイラを定義する方式に近い
  • 設定例では sdcc_z180-unknown-none トリプルと /usr/bin/sdcc-mz180--std-c89-c 引数を使用している

ネットワーク透過性とリモートCコンパイラ

  • cillyネットワーク透過性 を備え、TCP 経由で C コンパイラと通信できる
  • 必要であれば、UART のようなさらに特殊な通信方式にも拡張できる
  • この方式は、C クロスコンパイラが存在しないプラットフォームにおける ブートストラップのパラドックス を解決するための手法である
  • ターゲット OS 上で小さな C サーバーをビルドして実行し、Linux のような一般的なプラットフォームで rustc を動かしたうえで、cilly がネットワーク越しに通信するようにできる
  • 作者は Arm64 Linux 上で rustc を実行しながら、x86 Plan 9 VM 向けの小さな Rust プログラムのコンパイルに成功している
    • Plan 9 環境の出力は gnot osversion 2000 cputype 386 である
    • /tmp/hello_plan9 の実行結果は Hello, world! である
    • nm の結果には rust_begin_unwind シンボルが表示される

makefile生成機能

  • cilly はオプションでオブジェクトファイル内に マーカー を挿入し、IR をキャッシュディレクトリに保存できる
  • その後、そのマーカーを読み取って関数とグローバルを定義位置ごとに分割できる
  • この情報を基に makefile を含むディレクトリを生成し、C コンパイラと make だけで Rust をビルドできるようにする

ビルドと実行条件

  • デモのビルドに使われたシステムは Ubuntu ベースの ARM64 Linux である
    • カーネル文字列は Linux spark-2773 6.17.0-1021-nvidia ... aarch64 である
  • 使用された C コンパイラ情報は GCC 13.3.0Ubuntu LLD 18.1.3 である
  • ビルドには正しい LLVM ライブラリが必要で、最も簡単な方法は rustup install nightly-2026-06-16 で該当 nightly をインストールすることである
  • ビルドコマンドは、LLVM_LIB_DIRlibLLVM.so.22.1-rust-1.98.0-nightly のパスを指定して make -j20 を実行する
  • CFLAGS は動作するが、一部のフラグはコンパイルを遅くする可能性がある
  • 最適化は推奨されない
    • デモはまだ粗削りで、最適化が問題を引き起こす可能性がある
    • この規模では最適化に非常に時間がかかる
  • 最適化なしなら作者のマシンでは数分以内でビルドできる
    • 計測値は 937.98s user, 123.77s system, 1352% cpu, 1:18.48 total である
  • 最適化を有効にすると、大半のコードは速く処理されるが、一部の大きな Rust ファイルで詰まる可能性がある

テストと既知の問題

  • ビルドテストは、LD_LIBRARY_PATH に nightly の LLVM ライブラリと ./rustc_driver を指定し、./rustc/rustc --version を実行する方法で行う
  • 通常のプログラムをビルドするには std をビルドする必要がある
    • std がないと error[E0463]: can't find crate for std エラーが発生する
    • 標準ライブラリのビルドについては BUILDING_STD.md を参照する必要がある
  • 既知のバグとして、奇妙なパス正規化の問題により、crustc はビルドされたディレクトリ、つまりリポジトリのルートで実行するとクラッシュする場合がある
  • 別の場所では正常に動作する

cillyの公開状況

  • cilly はまだ 一般公開向けの準備ができていない
  • 作者はできるだけ早く公開する予定だと述べている
  • 公開が遅れている理由として、仕事、大学論文、手のけがを挙げている
  • cilly ツールチェーン全体がまだ公開されていない理由の 1 つは、最適化関連のバグ を追跡中であるためである

1件のコメント

 
GN⁺ 3 시간 전
Lobste.rs のコメント
  • 与えられたコンパイラとプラットフォームが何をサポートしているかを確認する witness プログラムを生成する点が興味深い。
    伝統的な C の configure ビルドチェーンがだいたいこの方式で動くというのはかなり奇妙に感じるが、このコンパイラ、あるいはトランスパイラがそのパターンに従うのは納得できる。
    「14回目の試み: cilly」とは、すごい執念で、その粘り強さがうらやましい。
  • 比較すると、Zig コンパイラ全体を C に変換したバージョンがあり、これはソースからビルドする通常手順の一部になっている。
    規模は 460万行で、このプロジェクトよりほぼちょうど一桁小さい。生成される C コードはターゲットごとに異なるが、コンパイラごとには異ならない。
  • システムプログラマではないが、こうしたプロジェクトが Rust と Zig のどちらを使うかに影響しうるのか気になる。
    Zig の利点には、さまざまなクロスコンパイルターゲットのサポート、セルフホストのツールチェーン、LLVM が選択依存であることが含まれるが、Rust を希少なプラットフォーム向けの C にコンパイルできるという約束は、Zig 側を意識したシグナルのようにも見える。
    • crustc を使うだけではそうはならない。変換されたコンパイラも元のコンパイラと同じコンパイルターゲットしかサポートしないため。
      ただし、別の Rust プロジェクトを C に変換して、C しかサポートしないターゲット上で実行・コンパイルすることは可能。
      とはいえ影響を過大評価すべきではない。かなりニッチな問題に対する、やや手間のかかる解法に近い。rustc はすでにターゲット対応が広く、gcc バックエンドによってさらに広がる予定。
      Zig のクロスコンパイルツールは素晴らしいが、特に Zig や Rust より扱いの難しい C の部分で利便性を高める性格が強く、より多くのターゲットをサポートするという意味合いは相対的に小さい。
      結局、Zig と Rust のターゲット対応はすでにかなり似ていて決定的要因にはなりにくく、2つの言語の間にはもっと重要な違いがたくさんある。
  • すごいとは思うが、結局は LLVM の能力に制限されるのでは?
    • なぜそうでなければならないのか分からない。crustc は Rust を C に変換するツールチェーンである cilly に何ができるかを示す例にすぎない。
      cilly ツールチェーン全体は、ユーザーの Rust コードを任意のターゲット向けの C にコンパイルする。このリポジトリは最も派手なデモだと思うので、コンパイラが自分自身をコンパイルする様子を見せているのだろう。
  • mrustc(https://github.com/thepowersgang/mrustc) も見る価値がある。C++ で書かれた Rust コンパイラで、C にトランスパイルしてから GCC に渡す方式なので、rustc も C に変換できる。