This document provide guidance for C++/Rust interoperation using FFI (foreign function interfaces).
For interoperating with C++ code, we recommend the the cxx crate. For introductory guidance, please see the cxx chapter in the Chromium section of the Comprehensive Rust course.
If you only need to use a C APIs from Rust (and not the other direction), you can use the bindgen tool. Bindgen will automatically create Rust equivalents of the input C code, which you can then use from your own Rust code. For example, this project uses bindgen to import the Mojo C API. For documentation of various options, see //build/rust/rust_bindgen.gni.
Bindgen can also be used to import C++ headers, but it only supports a limited subset of the language.
In the future, we intend to shift from cxx to Crubit (tracked in https://crbug.com/470466915). However, Crubit is still transitioning to open-source, and is not yet officially supported in Chromium. See crubit.md for some in-progress notes on the current implementation and how to use it.
Chromium does not support any other FFI tools (e.g. cbindgen or zngur), and we do not plan to support them in the future.
All FFI code is unsafe by definition, since the Rust compiler cannot enforce its rules on non-Rust code. This means that when working with FFI, you must be careful to understand exactly what behaviors are possible. Make sure you‘re familiar with our safety guidelines. So long as you’re consistent about writing and following safety comments, you can avoid most problems.
cxx::bridge, it is treated as opaque, zero-sized placeholder type from the perspective of the Rust compiler. This means that it must always be behind an indirection (a pointer, reference, box, etc.), and the Rust compiler makes no assumptions about what it points to.CommandLine variable are not already racy, even though there isn't specific code to enforce that.cxx guidanceThe cxx crate is the current standard for C++/Rust interop in Chromium, but it has some rough edges that we hope will eventually be smoothed over with the adoption of Crubit. This section provides advice for working with cxx in the meantime.
#[cxx::bridge] declaration. cxx supports reusing types across multiple bridges, but there are some rough edges.namespace. For example: #[cxx::bridge(namespace = "some_cpp_namespace")].cxx can't translate), create wrapper functions in a C++ shim file._shim.h (or .cc).These are not necessarily best practices, but take them into consideration when designing your bridges.
cxx's [attributes] to generate more idiomatic code:Self attribute can attach static functions to existing types.rust_name attribute is useful for translating between naming conventions.extern "C++" block as unsafe.In general, you should follow idomatic Rust style, but some idioms are especially useful in an FFI context:
Use From (or TryFrom) to convert between types; it's especially well-suited to converting between types that are logically equivalent, such as FFI types like ffi::ColorType and third-party crate types like png::ColorType.
See an example trait implementation and an example of using the conversion as foo.into().
Note that when implementing the conversion for types defined in other crates, you may need to work around the orphan rule by implementing Into (or TryInto) trait instead.
Use the ? operator alongside the Option or Result types to check for errors.
When used in the FFI layer, this may require splitting some functions into (a) one that returns Result<T, E> and uses ? sugar, and (b) one that translates Result<T, E> into FFI-friendly status.
There are some examples here and here. This example avoids having to come up with a separate name by using an anonymous function.
Use the let Ok(foo) = ... else { ... } syntax to handle errors when you don't always want to return if you see a None. See an example here.