演習: 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 の設計上、そのような例を作るのはかなり困難です。