C++との相互運用性

Rust コミュニティには C++ と Rust の相互運用のためのオプションが複数用意されており、絶えず新しいツールが開発されています。現在のところ、Chromium では CXX というツールを使用しています。

言語境界全体をインターフェース定義言語(Rust によく似ています)で記述すると、CXX ツールが Rust と C++ の両方で関数と型の宣言を生成します。

Overview diagram of cxx, showing that the same interface definition is used to create both C++ and Rust side code which then communicate via a lowest common denominator C API

CXX の詳細な使用例については、CXX チュートリアル をご覧ください。

図を見ながら話しましょう。裏で行われる処理は以前とまったく同じであり、このプロセスを自動化すると次のようなメリットがあることを説明します。

  • このツールは、C++ 側と Rust 側が一致することを保証します(たとえば、#[cxx::bridge] が実際の C++ または Rust の定義と一致しない場合、コンパイル エラーが発生しますが、同期されていない手動バインディングを使用すると、未定義の動作が発生します)。
  • このツールは、C 以外の機能に対する FFI サンク(小さな C-ABI 互換のフリー関数)の生成を自動化します(Rust または C++ メソッドへの FFI 呼び出しの有効化など。手動バインディングでは、このようなトップレベルのフリー関数を手動で作成する必要があります)。
  • ツールとライブラリは、次のような一連の主要な型を処理できます。
    • &[T] は、特定の ABI やメモリ レイアウトを保証するものではありませんが、FFI の境界を超えて渡すことができます。手動バインディングでは、std::span<T> / &[T] を手動で分離し、ポインタと長さから再構築する必要があります。言語ごとに空のスライスの表現方法が若干異なるため、エラーが発生しやすくなります。
    • std::unique_ptr<T>std::shared_ptr<T>Box などのスマート ポインタは、ネイティブにサポートされています。手動バインディングでは、C-ABI 互換の未加工ポインタを渡す必要があるため、ライフタイムとメモリ安全性に関するリスクが高まります。
    • rust::String 型と CxxString 型は、言語間の文字列表現の違いを理解し、維持します(たとえば、rust::String::lossy は、非 UTF8 の入力から Rust 文字列を作成できます。また、rust::String::c_str は文字列を NUL 終端できます)。