docs/rust/ffi.md
This document provide guidance for C++/Rust interoperation using FFI (foreign function interfaces).
[TOC]
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.