Eurydice: a Rust to C compiler (yes)

2025/12/07 10:41

Eurydice: a Rust to C compiler (yes)

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:


Summary

Eurydice は、単一の Rust コードベースを 読みやすく、標準に準拠した C または C++ に変換する Rust‑to‑C コンパイラです。
Charon インターフェース経由で rustc の MIR に接続するため、Rust コンパイラを再実装する必要がなく、少ない構文で忠実な意味論的翻訳が可能です。

Core transformations

  • Whole‑program monomorphisation:ジェネリクスを具体型に展開します。
  • Pattern‑match compilation:Rust の
    match
    式を C でタグ付きユニオンへ変換します。
  • Iterator recognition:慣用的な Rust のイテレータチェーンをネイティブ C のループへ変換します。
  • Array initialisation handling:ゼロ初期化、初期化リスト、およびループベースの初期化を区別し、Rust のセマンティクスに合わせます。

Readability choices

  • Rust 構造体 → C 構造体(flexible array members を使用)。
  • 単一バリアントの列挙型はタグを省略して簡潔化。
  • 制御フローは Charon 経由で再構築し、raw goto ではなくより明確なコードにします。

コンパイラ自体は OCaml の約 8 k 行です:MIR‑to‑KaRaMeL AST 変換が約 3 k 行、カスタムナノパス/最適化が約 5 k 行、内部構文パターン用の小さな ppx が付随。生成コードは C11/C++20 対応または C++17 対応で、マクロによりコンパウンド初期化子と列挙型のメンバーポインタの違いを隠します。

Limitations

  • Rust と C の型レイアウト不一致の可能性。
  • DST 処理から生じる厳格なエイリアシング違反。
  • 単一プラットフォームの MIR ビュー(cfg の調整が必要)。
  • ターゲット固有のモノマル化インスタンスの煩雑な設定。

デプロイには手書きのグループコード―マクロと static inline 関数―を用いて重複する多態コードを削減します。例えば、配列に対して

Eq
トレイトを実装する際にマクロを使用します。

Future work

  • Microsoft/Google の暗号ライブラリとの統合。
  • 仮想テーブルによる動的トレイトのサポート。
  • Charon を通じた完全モノマル化。
  • 2026 年までに Rust 標準ライブラリ全体を抽出し、開発者が単一の権威ある Rust ソースを維持しつつ、レガシーシステム向けに C を段階的に生成できるようにする。

プロジェクトは約 8 k 行の OCaml で、GitHub ユーザー @ssyram@lin23299 が貢献し、ギリシャ神話をテーマとした命名規則(Eurydice, Aeneas, Charon)に従っています。Rust と既存の C エコシステム間でよりスムーズな相互運用性を提供し、両言語が必要な企業の重複作業を削減するとともに、読みやすいクロス言語コンパイラ出力の再利用可能モデルを提示します。

本文

ここ数年で私が最も驚いたことの一つは、単に「C を Rust にコンパイルする」だけではなく、「Rust を C にコンパイルする」という点にも人々が関心を持っているという事実でした。なぜなら、明らかにメモリ安全性などの理由で C から Rust への移行は重要ですが、逆方向も同様に重要だと多くの方が感じているからです!なんだって?

数年前に簡単に触れたことがありますが、このプロジェクトに対する関心の高さには驚かされました。そこで今日は「Rust を C にコンパイルする」ことについてもう少し詳しく掘り下げてみましょう。


Rust の採用障壁

Rust は導入面で大きな進展を遂げており、特に新しいコードを書く際には非常に価値のある選択肢です。私が以前勤めていた会社も、新しく働いている会社も、ほぼすべてのプロジェクトが純粋な Rust で書かれているか、Rust のコンポーネントを持っています。Windows カーネルドライバでも今では Rust で書くことが可能です―驚きですね。

しかし、もしあなたのプロジェクトが「多種多様なターゲットアーキテクチャ・OS・ディストリビューション・ツールチェーン上でビルドされるオープンソースライブラリ」だったとすると、そのうちの一つは Rust をサポートしていない可能性が高いです。暗号ライブラリを例に挙げれば、変わった組み込みターゲット向けに作られた不思議なコンパイラを使っている人々がいて、彼らは「自分で暗号機能を実装しないように」という指示を受けており、あなたのライブラリをビルドしたいと考えています。あるいはメモリエラーに悩まされるフォーマットライブラリを Rust に移植したいケースもあります。さらには社内分析ツールが C コードしか動かないという状況も想像できます。どんなシナリオでも、やがて「Rust への移行を妨げるレガシーなユースケース」が存在し、それが解消されるまで(2035 年に LTS バージョンがすべて退役する頃)あなたは Rust を採用できません。

つまり、Rust‑to‑C コンパイラを使う意思がある場合のみ、この障壁を乗り越えることができます。

なぜ必要なのか?

Rust が C にコンパイル可能な後方互換性のシナリオは、以下のような目的に役立ちます。

  • 段階的移行 – コードベースを Rust にポートし、データ型・パターンマッチング・多態性・メモリ安全性などの優れた機能を活用して再構築・クリーンアップします。C バージョンは並行して存在するため、ユーザー基盤を排除せずに済みます。
  • 唯一正統なバージョン – Rust コードが「正統」であり、C コードは自動的(CI で)に生成される形です。両者の同期を CI ジョブで確認できます。
  • 問題点の可視化 – Rust をデフォルトにし、C バックアップを
    --write-us-an-email
    フラグで隠すことで、「まだ Rust に移行できないユーザー」を最終的に列挙することが可能になります。

このようなメリットに惹かれたら、ぜひ Eurydice をご覧ください。


Eurydice とは

Eurydice は「Rust → C コンパイラ」であり、読みやすい C コードを生成することを目指しています。

可読性は主観的ですが、Rust が 全プログラム単位のモノポリゼーション(whole‑program monomorphization)に依存しているため、C コードは Rust コードよりも冗長になるでしょう。実際に

libcrux
を C にコンパイルした結果を見てください。

テストスイートの出力はバージョン管理下にあり、さらに多くのテストが存在します。以下の例では Rust のオリジナルと比較してみます。


Eurydice の設計

Eurydice は MIR(Mid-level Intermediate Representation) で直接プラグインし、Charon を利用して

rustc
の内部構造を再実装する手間を省きます。Charon に関する論文では、そのアーキテクチャについて詳しく説明しています。

MIR レベルでのプラグインメリット

  1. 構文糖(syntactic sugar)を解釈しなくてよい – したがって、Rust の意味論に忠実な翻訳が可能です。
  2. コンパイル対象となる構造体が少ない – C に変換する際の複雑さが軽減されます。

それでも Rust を C に翻訳することは容易ではありません。主に以下を行う必要があります。

  • 型と const‑generic 引数に対して 全プログラムモノポリゼーション
  • パターンマッチをタグ付きユニオンへ変換
  • ループが可能なイテレータはネイティブ C for‑loop に置き換え
  • 配列の繰り返し表現を合理的にコンパイル(可能ならゼロ初期化、そうでない場合は initializer list、コード量が多いと for‑loop)
  • 可視性・
    static
    inline
    など C 固有のルールを処理

さらに生成されるコードは「読みやすさ」を保つ必要があります。たとえば Rust の構造体(DST を含む)は 柔軟配列メンバ を用いて C 構造体に変換します。また、単一ケースの enum にはタグを付けず、可能な限り汎用的なタグ付きユニオンパターンは避けます。Charon は MIR の制御フローグラフ(CFG)を直接 C にコンパイルせず、代わりに制御フローを再構築します。

低レベルの詳細

  • Rust の配列は値型であるため、C では 構造体内に埋め込む(例:
    [u32; 8] → struct { uint32_t data[8]; }
    )。以前はポインタを使い
    memcpy
    に頼っていましたが、タイプ汎用性がなく多くのケースで問題が発生していたためです。
  • C の lvalue 概念では Rust よりも変数宣言が必要になるケースがあります。たとえば
    &[0u32; 1]
    を直接コンパイルすることはできず、配列に名前を付ける必要があります。
  • C の評価順序の曖昧さから、中間計算結果を変数に保存して明示的な順序制御が必要です。
  • 全プログラムモノポリゼーションにより、同一型・関数が異なるジェネリック引数で複数回生成されます。現在はビルトインフェーズで処理していますが、将来的には Charon のサポートを利用する予定です。
  • Peephole 最適化は不可欠です(例:
    array::from_fn
    を認識して in‑place 初期化コードを生成、
    Eq
    トレイトのインスタンスに対して
    memcmp
    を使うなど)。

最後に設計上、Eurydice は Rust よりも多くの振る舞いを定義できることがあります。たとえば Rust では整数オーバーフローでパニックしますが、Eurydice コンパイル済みコードはそうしません。入力コードが検証済みでパニックが発生しない前提にしていますが、これは簡単に変更可能です。

実際にはトレイトを使用すると C コードの量が増大します。そのため、構成ファイルでモノポリゼーションインスタンスの配置を制御し、大規模プロジェクトでは手動介入が必要になる場合があります。


Eurydice の実装

  1. MIR → KaRaMeL AST
    Charon から取得した MIR AST を KaRaMeL の内部 AST(約 3000 行の OCaml コード)に変換します。トレイトメソッドとそのモノポリゼーションが主な作業です。

  2. Nano‑passes
    約 30 個のナノパスで KaRaMeL AST を簡略化し、C コンパイル対象となる形に整えます。既存の KaRaMeL 用に書かれたものも利用しつつ、新規に約 5000 行の OCaml コードを追加しました。

  3. 変数代入削除
    MIR ではすべての変数が未初期化状態から始まり、最初の値で代入されます。最初のフェーズでこれらを「宣言 + 初期化」に再構築し、コード品質を向上させています。これは MIR を使う欠点ですが、可読性を高めるために選択しました。

  4. カスタム OCaml 文法拡張
    多数の peephole 最適化を管理するため、KaRaMeL 内部言語で具体的なパターンを書けるようにします。これはコンパイル時に ppx で解析・変換され、OCaml AST ノードとして生成されます。


Eurydice 生成コードのデプロイ

Eurydice が生成したコードは 手書きのグルー(マクロや static inline 関数) を必要とします。多くの場合、複数の特化版を生成する代わりに「型を引数に取る単一マクロ」を作成すると便利です。例として

Eq
トレイトの配列実装では、
Eurydice_array_eq(a1, a2, len, t)
というマクロを出力し、内部で
!(memcmp(a1, a2, len*sizeof(t)))
を展開します。

生成コードは以下のいずれかです。

  • C11 および C++20 対応
  • C++17 対応だが純粋な C には非対応

Rust の enum は任意の式位置で使用できます。Eurydice はコンパウンドイニシャライザ(例:

Foo { .tag = bar, .value = { .case_Foo = { .bar = baz }}}
)や、C++20 の designated initializers を利用します。マクロで構文差異を隠蔽しています。C++17(designated initializers が無い場合)はメンバポインタを用いて同様の効果を実現できます。


Eurydice の限界

  • オブジェクトレイアウト: C と Rust で完全に同一になる保証はありません。MIR からレイアウト情報を解析し、コンパイラ固有のアラインメントディレクティブを出力することも可能ですが、現在は実装していません。
  • Strict aliasing の違反: ユーザー定義 DST を作成するときにポインタ型をキャストします(例:構造体内の配列 → 柔軟配列メンバ)。現状では
    -fno-strict-aliasing
    でビルドしてください。
  • プラットフォーム固有コード: Eurydice は MIR を cfg 調整後に見るため、マルチプラットフォームのコードでは「一つのバージョン(AVX2, ARM64 等)しか見えません」。対策が必要です。
  • 設定の複雑さ: モノポリゼーションが広範囲にわたるため、設定言語で「
    __m256i
    を参照する型は AVX2 向けファイルに分離して
    -mavx2
    でビルド」などを表現しなければならず、手間がかかります。

今後の展望

現在は Microsoft と Google の暗号ライブラリへの Eurydice 生成コード統合作業中です。コミュニティも GitHub ユーザー @ssyram と @lin23299 の貢献で拡大しています。次なる目標は dyn トレイト(vtable) のサポートと、Charon が提供するモノポリゼーションを利用して MIR を「Rust コンパイラが生成するもの」と同一に保つことです。

さらに野心的なゴールとして、2026 年までに Rust 標準ライブラリ全体を Eurydice で抽出 しようと考えています。実現は容易ではありませんが、達成可能だと信じています。


PS:名前の由来

「Eurydice」という名前についてよく質問されます。このプロジェクトは Aeneas と Charon と同じインフラを多く共有しているため、ギリシャ神話にちなんだテーマで名付けました。ユリディケ(Eurydice)の物語が、私にとって「C コード生成の地獄から救われ、生者の世界へ戻る」というイメージに響きました――残念ながら、実際にはそのような奇跡は起きませんでした。

同じ日のほかのニュース

一覧に戻る →

2025/12/07 10:17

Using LLMs at Oxide

## Japanese Translation: ## 改訂要約 大型言語モデル(LLM)は、文書の高速解析、コード生成、テキスト作成などで強力なアシスタントとなりますが、人間の判断や責任を置き換えるべきではありません。LLM の強みには、長文の即時要約、コーディングエラーの検出、プローズ提案などがあります。しかし、これら同様にプライバシーリスク(アップロードされたデータでのトレーニングからオプトアウトする必要性)、過度な奉承的表現、クリシェが多い出力による真実感の低下、不安定なデバッグ支援なども伴います。実際の例では、ChatGPT、Claude、Gemini へのデータ共有ポリシーで「全員のモデル改善」を無効化するようユーザーに求められ、Oxide は強力なライターを採用し完全な LLM コンテンツ作成を避ける方針を取っています。ソフトウェアチームは LLM の支援を受けながらも、人間によるコードレビューに依存しています。今後、エンジニアは迅速な反復のために LLM を使用し続けますが、責任と真実感を維持するためにピアレビュー前に厳格な自己レビューを強制します。企業は明確なプライバシー設定とガイドラインを設置し、ライターは独自のスタイルを保持し、開発者は機械出力を検証するプロセスが必要です。この効率向上と人間監督のバランスこそが、将来の業界標準を決定づけるでしょう。

2025/12/07 12:03

Z2 – Lithographically fabricated IC in a garage fab

## Japanese Translation: > 著者は、DIYで低コストのポリシリコンゲートプロセスを用いてIntelの最初のプロセッサ技術を模倣し、2.4 mm² のダイに10×10配列(合計100トランジスタ)を製造しました。以前のZ1テストチップ(6トランジスタ)に続き、新しいZ2チップは完全な電気特性評価が可能です:Vth ≈ 1.1 V、Cgs < 0.9 pF、立ち上がり/落下時間 < 10 ns、オン/オフ比 ≈ 4.3 × 10⁶、漏れ電流 932 pA(Vds = 2.5 V)(環境光下では約100倍高い)。これらの数値は、2.5–3.3 V のロジックレベルで信頼性ある動作を示しています。 > 製造は自己整列型「ゲートファースト」プロセスであり、イオン注入を省略し、水・アルコール・アセトン・リン酸・フォトレジスト・デベロッパー・N‑タイプドーパント・HF/CF₄/CHF₃ RIE・HNO₃ などの一般的な実験室化学物質のみを使用し、クリーンルームは不要です。約10 nm のSiO₂ゲート酸化膜と300 nm のポリシリコンを有する25 × 200 mm ウェーハを約45ドルで購入しました。製造には15チップ(1,500トランジスタ)が関与し、少なくとも1チップは完全に機能し、2チップが「ほぼ機能」しているため、推定トランジスタ歩留まりは80 %です。最も頻繁な欠陥はソース/ドレインがバルクシリコンと短絡していることです。 > 今後の作業にはテスト自動化、歩留まり向上、およびオペアンプやメモリアレイなどより複雑なデジタル/アナログ回路への技術拡張が含まれます。成功すれば、このDIY手法はホビイストや小規模ラボの参入障壁を低減し、ニッチなイノベーションを促進し、少量プロトタイプ用に商業製造所への依存度を削減する可能性があります。

2025/12/07 6:55

Screenshots from developers: 2002 vs. 2015 (2015)

## Japanese Translation: 記事は、グラフィカルインターフェイスの台頭にもかかわらず、Unix/Linux ユーザーが10年以上にわたり主にターミナル中心のワークフローを維持していることを示しています。2002 年初頭の最小限デスクトップ(xterm、fvwm、Gnome 2)のスクリーンショットと 2015 年までのユーザー報告はほぼ変化がないことを確認しています:多くの人がまだ軽量ウィンドウマネージャやコンソールエディタ(Emacs や Vim)に依存しています。ある回答者は、fvwm を使用していた FreeBSD から Linux(Lubuntu)と LXDE に移行しつつもコマンドライン中心を維持しました。彼は Firefox、Gimp、Wireshark、VLC などの GUI ツールを追加しましたが、シェル、Perl、および C でスクリプトを書き続け、mutt を使ってローカルでメールを処理しています。別の OS X ユーザーは、Mail.app、Safari、Calendar、Slack の 6 つの仮想デスクトップと専用ターミナルデスクトップを運用しています。数人の参加者はハードウェアアップグレード(例:スマートフォンが初期の Pyramid 90x を上回る)について言及しましたが、classic Unix プリミティブ(`open`、`close`、`fork`)に満足しているようです。 記事ではまた、Pine から Thunderbird または mutt へのメールクライアントの進化と、職務変更後の VirtualBox、LibreOffice、および Wine を介した Windows 互換性についても追跡しています。Hacker News と Reddit(/r/programming、/r/linux)のコミュニティディスカッションはさらに文脈を提供します。 総じて、グラフィカルデスクトップが進化しているにもかかわらず、ターミナル中心のワークフローは継続しています。legacy ウィンドウマネージャ(fvwm)と軽量環境(LXDE、LXQt)は、新しい GUI と共存し続けています。この持続的なミニマリズムは、ソフトウェア開発者がコマンドライン機能を前面に押し出し、ユーザーコミュニティおよび産業界の両方で継続的に求められるターミナルフレンドリーなツールへの需要を満たすべきだという示唆です。

Eurydice: a Rust to C compiler (yes) | そっか~ニュース