The Bridge Module

CXX relies on a description of the function signatures that will be exposed from each language to the other. You provide this description using extern blocks in a Rust module annotated with the #[cxx::bridge] attribute macro.

#[allow(unsafe_op_in_unsafe_fn)] #[cxx::bridge(namespace = "org::blobstore")] mod ffi { // Shared structs with fields visible to both languages. struct BlobMetadata { size: usize, tags: Vec<String>, } // Rust types and signatures exposed to C++. extern "Rust" { type MultiBuf; fn next_chunk(buf: &mut MultiBuf) -> &[u8]; } // C++ types and signatures exposed to Rust. unsafe extern "C++" { include!("include/blobstore.h"); type BlobstoreClient; fn new_blobstore_client() -> UniquePtr<BlobstoreClient>; fn put(self: Pin<&mut BlobstoreClient>, parts: &mut MultiBuf) -> u64; fn tag(self: Pin<&mut BlobstoreClient>, blobid: u64, tag: &str); fn metadata(&self, blobid: u64) -> BlobMetadata; } }

Speaker Notes

  • The bridge is generally declared in an ffi module within your crate.
  • From the declarations made in the bridge module, CXX will generate matching Rust and C++ type/function definitions in order to expose those items to both languages.
  • To view the generated Rust code, use cargo-expand to view the expanded proc macro. For most of the examples you would use cargo expand ::ffi to expand just the ffi module (though this doesn't apply for Android projects).
  • To view the generated C++ code, look in target/cxxbridge.