演習: C++ との相互運用

パート 1

  • 以前作成した Rust ファイルに #[cxx::bridge] を追加し、C++ から呼び出される単一の関数 hello_from_rust を指定してください。この関数は引数を取らず、戻り値もありません。
  • 以前の hello_from_rust 関数を修正し、extern "C"#[unsafe(no_mangle)] を削除してください。これは単なる標準的な Rust 関数になります。
  • これらのバインディングをビルドするように gn ターゲットを修正してください。
  • C++ コードでは、hello_from_rust の前方宣言を削除してください。代わりに、生成されたヘッダーファイルをインクルードしてください。
  • ビルドして実行しましょう!

パート 2

少し CXX を試してみるとよいでしょう。そうすることで、Chromium における Rust が実際にはどれほど柔軟かを考える助けになります。

試してみること:

  • Rust から C++ にコールバックする。必要になるものは次のとおりです:
    • cxx::bridge から include! できる追加のヘッダーファイル。 その新しいヘッダーファイル内で C++ 関数を宣言する必要があります。
    • そのような関数を呼び出すための unsafe ブロック、あるいは ここで説明されている ように #[cxx::bridge]unsafe キーワードを指定すること。
    • また、 #include "third_party/rust/cxx/v1/crate/include/cxx.h" も必要になる場合があります
  • C++ 文字列を C++ から Rust に渡す。
  • C++ オブジェクトへの参照を Rust に渡す。
  • 意図的に Rust 関数のシグネチャを #[cxx::bridge] と一致しないようにして、表示されるエラーに慣れる。
  • 意図的に C++ 関数のシグネチャを #[cxx::bridge] と一致しないようにして、表示されるエラーに慣れる。
  • 何らかの型の std::unique_ptr を C++ から Rust に渡して、Rust が C++ オブジェクトを所有できるようにする。
  • Rust オブジェクトを作成して C++ に渡し、C++ がそれを所有するようにする。(ヒント: Box が必要です。)
  • C++ 型にいくつかのメソッドを宣言し、それらを Rust から呼び出す。
  • Rust 型にいくつかのメソッドを宣言し、それらを C++ から呼び出す。

パート 3

これで CXX 相互運用の強みと制約がわかったので、インターフェースが十分にシンプルになる Chromium における Rust のユースケースを 2 つほど考えてみてください。そのインターフェースをどのように定義するか、概略を示してください。

参考資料

学生がパート 2 を進める中で、これらをどう実現するのか、また CXX が裏側でどのように動作しているのかについて、多くの疑問が出てくるはずです。

あなたが遭遇しそうな質問の一部を以下に示します:

  • X と Y の両方が関数型であるにもかかわらず、型 Y で型 X の変数を初期化しようとして問題が発生しています。これは、C++ 関数が cxx::bridge 内の宣言と完全には一致していないためです。
  • C++ の参照を Rust の参照に自由に変換できるように見えます。これは UB の危険はないのでしょうか。CXX の opaque 型については、ゼロサイズなので危険はありません。CXX の trivial 型については、はい、UB を引き起こすことは 可能 です。ただし、CXX の設計上、そのような例を作るのはかなり困難です。