cpp_api_from_rustcpp_api_from_rust (aka cc_bindings_from_rs) is a Crubit tool that takes a Rust crate as input and generates C++ APIs (a .h header) as output, enabling C++ to call Rust. This document provides instructions for using cpp_api_from_rust in Chromium.
See //docs/rust/crubit/README.md for general information about Crubit.
cpp_api_from_rust for a rust_static_library crateExample:
// build/rust/tests/test_cpp_api_from_rust/lib.rs: pub fn mul_two_ints_via_rust(x: i32, y: i32) -> i32 { x * y }
# build/rust/tests/test_cpp_api_from_rust/BUILD.gn import("//build/rust/rust_static_library.gni") rust_static_library("rust_lib") { crate_root = "lib.rs" sources = [ crate_root ] cpp_api_from_rust = { target_name = "rust_lib_bindings" cpp_namespace = "rust_lib" } } source_set("unittests") { sources = [ "unittests.cc" ] deps = [ ":rust_lib_bindings", ] }
// build/rust/tests/test_cpp_api_from_rust/unittests.cc:
// `rust_lib` part of the `#include` path comes from the target name
// (i.e. from `rust_static_library("rust_lib")` above).
#include "build/rust/tests/test_cpp_api_from_rust/rust_lib.h"
void foo() {
auto product = rust_lib::mul_two_ints_via_rust(3, 4);
}
cpp_api_from_rust for a third_party/rust crateSet cpp_api_from_rust = true in gnrt_config.toml as follows:
[crate.qr_code.extra_kv] allow_unsafe = false cpp_api_from_rust = true
After modifying gnrt_config.toml you have to re-run tools/crates/run_gnrt.py gen to regenerate the crate's BUILD.gn file.
At this point you should be able to depend on the bindings and use them as follows. Note that check_includes_strict = true and public are set so that C++ targets depending on :my_cpp_code do not have to wait for the Rust compilation (see Crubit and build performance):
# My BUILD.gn:
source_set("my_cpp_code") {
# Enforces that `my_cpp_code.h` does not #include headers from private
# `deps`, which also stops GN from forwarding the bindings-related
# order-only dependencies to C++ targets that depend on `:my_cpp_code`.
check_includes_strict = true
public = [ "my_cpp_code.h" ]
sources = [ "my_cpp_code.cc" ]
# ...
deps += [ "//third_party/rust/qr_code/v2:cpp_api_from_rust" ]
}
// my_cpp_code.cc
// The last `qr_code` part of the `#include` path comes from the `crate_name`
// attribute of the `//third_party/rust/qr_code/v2:lib` target.
#include "third_party/rust/qr_code/v2/qr_code.h"
void foo() {
// ...
rs::SliceRef<const uint8_t> rs_in(in);
auto result = ::qr_code::QrCode::new_(rs_in);
// ...
}
Let's assume that cpp_api_from_rust bindings are generated for //some/dir:some_target - e.g.:
# some/dir/BUILD.gn import("//build/rust/rust_static_library.gni") rust_static_library("some_target") { crate_root = "lib.rs" sources = [ crate_root ] cpp_api_from_rust = { target_name = "some_target_bindings" } }
The generated bindings can then be found and inspected in <out_dir>/gen/some/dir/some_target.h. For example:
$ cat out/rel/gen/build/rust/tests/test_cpp_api_from_rust/rust_lib.h | head -3 // Automatically @generated C++ bindings for the following Rust crate: // rust_lib_1dc874e1 // Features: ...
If public APIs of a crate depend on types from another crate, then the dependency on the other crate needs to be explicitly specified in BUILD.gn.
1st-party Rust libraries can specify dependencies of their bindings as follows:
// build/rust/tests/test_cpp_api_from_rust/lib.rs: chromium::import! { "//build/rust/tests/test_cpp_api_from_rust:internal_helper"; "//build/rust/tests/test_cpp_api_from_rust:other_lib"; } pub fn create_multiplier(x: i32) -> other_lib::Multiplier { internal_helper::do_something(); other_lib::Multiplier::new(x) }
# build/rust/tests/test_cpp_api_from_rust/BUILD.gn import("//build/rust/rust_static_library.gni") rust_static_library("rust_lib") { crate_root = "lib.rs" sources = [ crate_root ] deps = [ ":other_lib", ":internal_helper", ] cpp_api_from_rust = { target_name = "rust_lib_bindings" cpp_namespace = "rust_lib" bindings_deps = [ "//some/other/lib:other_lib_bindings" ] } }
Note how other_lib_bindings are listed in bindings_deps of cpp_api_from_rust above.
Note that types from internal_helper are not used in public APIs of rust_lib and therefore internal_helper is not listed in bindings_deps attribute of cpp_api_from_rust.
If public APIs of the Rust crate use C++ types (from Rust bindings generated by rust_api_from_cpp), then bindings_deps should list the rust_api_from_cpp target. The C++ bindings will then refer to the original C++ types. See rust_lib_using_cpp_type in build/rust/tests/test_rust_api_from_cpp/round_trip/BUILD.gn for an example.
//third_party/rust libraries3rd-party Rust crates can specify dependencies of their bindings with the following gnrt_config.toml entry:
[crate.my_crate_name.extra_kv]
allow_unsafe = false
cpp_api_from_rust = { bindings_deps = ["some_other_crate/v123"] }
After modifying gnrt_config.toml you have to re-run tools/crates/run_gnrt.py gen to regenerate the crate's BUILD.gn file.
C++ bindings for Rust standard library are automatically injected as a dependency of all other bindings. Therefore usually there is no need to explicitly depend on these bindings, but if needed other targets can depend on //build/rust/crubit.
C++ bindings for Rust standard library are placed in a C++ namespace that corresponds to the original Rust crate as follows:
std crate => rs::std namespacealloc crate => rs::alloc namespacecore crate => rs::core namespaceThe bindings can be #included from the following paths:
#include "third_party/crubit/support/rs_std/rs_std.h"#include "third_party/crubit/support/rs_std/rs_alloc.h"#include "third_party/crubit/support/rs_std/rs_core.h"Side-note: The auto-generated
build/rust/std/rules/BUILD.gnoverrides the include paths to make sure that Chromium can use the canonical paths (ones that are unified across other major Crubit clients). There is no actualthird_party/crubit/supportdirectory in the root of the Chromium repo.
The sections below should help diagnose and fix some issues you may encounter. If your issue is not covered, then please see docs/rust/crubit/README.md for instructions how to report a new bug.
If cpp_api_from_rust is unable to generate bindings for a given Rust API, then the generated .h file will contain a comment explaining why. The sections below describe a few errors that are somewhat related to how Chromium integrates Crubit into its build system.
--crate-header was specified for this crateIf you see an error like:
$ cat out/rel/gen/build/rust/tests/test_cpp_api_from_rust/rust_lib.h ... // Error generating bindings for `create_multiplier` defined at // ../../build/rust/tests/test_cpp_api_from_rust/lib.rs;l=22: Error formatting // function return type `other_lib::Multiplier`: Type `other_lib::Multiplier` // comes from the `other_lib_1dc874e1` crate, but no `--crate-header` was // specified for this crate ...
Then you want to read the “Specifying binding dependencies” section above.
C++ targets that depend on the bindings (directly or transitively) have to wait for the Rust compilation, unless the target that depends on the bindings sets check_includes_strict = true (with the bindings in private deps) or isolates the .cc files in a source_set with public = []. Most bindings end up being transitively used by many C++ targets, so please follow Crubit and build performance when adding a dependency on the bindings.
lld-link: error: undefined symbol: ___crubit_thunk_foo_bar_bazcpp_api_from_rust-generated APIs cannot be called from another build component (another .so or .dll) than the one that contains the Crubit-generated source_set.cpp_api_from_rust is not supported in the host toolchain (e.g. when generating bindings for host-side build tools).