The build system supports generating bindgen bindings through the rust_bindgen
module type. Bindgen provides Rust FFI bindings to C libraries (with some
limited C++ support, which requires setting the cppstd
property).
Basic rust_bindgen usage
What follows is an example of how to define a module that uses bindgen, and
how to use that module as a crate. If you need to use bindgen bindings through
an include!()
macro, such as for external code, see the
Source Generators
page.
Example C library to call from Rust
An example C library which defines a struct and function for use in Rust follows.
external/rust/libbuzz/libbuzz.h
typedef struct foo {
int x;
} foo;
void fizz(int i, foo* cs);
external/rust/libbuzz/libbuzz.c
#include <stdio.h>
#include "libbuzz.h"
void fizz(int i, foo* my_foo){
printf("hello from c! i = %i, my_foo->x = %i\n", i, my_foo->x);
}
Define a rust_bindgen module
Define a wrapper header, external/rust/libbuzz/libbuzz_wrapper.h
, which includes
all relevant headers:
// Include headers that are required for generating bindings in a wrapper header.
#include "libbuzz.h"
Define the Android.bp
file as external/rust/libbuzz/Android.bp
:
cc_library {
name: "libbuzz",
srcs: ["libbuzz.c"],
}
rust_bindgen {
name: "libbuzz_bindgen",
// Crate name that's used to generate the rust_library variants.
crate_name: "buzz_bindgen",
// Path to the wrapper source file.
wrapper_src: "libbuzz_wrapper.h",
// 'source_stem' controls the output filename.
// This is the filename that's used in an include! macro.
//
// In this case, we just use "bindings", which produces
// "bindings.rs".
source_stem: "bindings",
// Bindgen-specific flags and options to customize the bindings.
// See the bindgen manual for more information.
bindgen_flags: ["--verbose"],
// Clang flags to be used when generating the bindings.
cflags: ["-DSOME_FLAG"],
// Shared, static, and header libraries which export the necessary
// include directories must be specified.
//
// These libraries will also be included in the crate if static,
// or propagated to dependents if shared.
// static_libs: ["libbuzz"]
// header_libs: ["libbuzz"]
shared_libs: ["libbuzz"],
}
To learn more about using bindgen flags, see the bindgen manual section on Customizing Generated Bindings.
If you used this section to define a rust_bindgen
module as a prerequisite to
using the include!()
macro, return to Prerequisite
on the Source Generators page. If not, proceed with the next sections.
Use bindings as a crate
Create external/rust/hello_bindgen/Android.bp
with the following content:
rust_binary {
name: "hello_bindgen",
srcs: ["main.rs"],
// Add the rust_bindgen module as if it were a rust_library dependency.
rustlibs: ["libbuzz_bindgen"],
}
Create external/rust/hello_bindgen/src/main.rs
with the following content:
//! Example crate for testing bindgen bindings
fn main() {
let mut x = buzz_bindgen::foo { x: 2 };
unsafe { buzz_bindgen::fizz(1, &mut x as *mut buzz_bindgen::foo) }
}
Finally, call m hello_bindgen
to build the binary.
Test Bindgen bindings
Bindgen bindings typically contain a number of generated layout tests to prevent memory layout mismatches. AOSP recommends that you have a test module defined for these tests, and that the tests run as part of your project's normal test suite.
A test binary for these can be easily produced by defining a rust_test
module
in external/rust/hello_bindgen/Android.bp
:
rust_test {
name: "bindings_test",
srcs: [
":libbuzz_bindgen",
],
crate_name: "buzz_bindings_test",
test_suites: ["general-tests"],
auto_gen_config: true,
// Be sure to disable lints as the generated source
// is not guaranteed to be lint-free.
clippy_lints: "none",
lints: "none",
}
Visibility and linkage
Generated bindings are usually very small, as they consist of type definitions,
function signatures, and related constants. As a result, it is generally
wasteful to link these libraries dynamically. We have disabled dynamic linkage
for these modules so that using them via rustlibs
will automatically select a
static variant.
By default, rust_bindgen
modules have a visibility
property of
[":__subpackages__"]
, which will only allow modules in the same Android.bp
file or those beneath it in the directory hierarchy to see it. This serves two
purposes:
- It discourages the use of raw C bindings elsewhere in the tree.
- It avoids diamond linking issues with a mix of static and dynamic linkage.
Usually, you should provide a safe wrapper library around the generated module you've added in the same directory tree as the bindings which is intended for other developers to use. If this doesn't work for your use case, you can add additional packages to visibility. When adding additional visibility scopes, please take care that you do not add two scopes which may be linked into the same process in the future, as this may fail to link.
Notable rust_bindgen properties
The properties defined below are in addition to the Important common properties
that apply to all modules. These are either particularly important to Rust
bindgen modules, or exhibit unique behavior specific to the rust_bindgen
module type.
stem, name, crate_name
rust_bindgen
produces library variants, so they share the same requirements with
the rust_library
modules for the stem
, name
, and crate_name
properties. See
Notable Rust library properties
for reference.
wrapper_src
This is the relative path to a wrapper header file that includes the headers required
for these bindings. The file extension determines how to interpret the header
and determines which -std
flag to use by default. This is assumed to be a C
header unless the extension is either .hh
or .hpp
. If your C++ header must have
some other extension, set the cpp_std
property to override the default behavior
that assumes the file is a C file.
source_stem
This is the filename for the generated source file. This field must
be defined, even if you're using the bindings as a crate, since the stem
property only controls the output filename for the generated library variants.
If a module depends on multiple source generators (such as bindgen
and protobuf
)
as source rather than as crates through rustlibs
, you must ensure that all source generators
that are dependencies of that module have unique source_stem
values. Dependent modules
copy sources from all SourceProvider
dependencies which are defined in
srcs
to a common OUT_DIR
directory, so collisions in source_stem
would
result in the generated source files being overwritten in the OUT_DIR
directory.
c_std
This is a string representing which C-standard version to use. Valid values are listed below:
- A specific version, such as
"gnu11"
. "experimental"
, which is a value defined by the build system inbuild/soong/cc/config/global.go
, may use draft versions like C++1z when they're available.- Unset or
""
, which indicates that the build system default should be used.
If this is set, the file extension is ignored and the header is assumed to
be a C header. This cannot be set at the same time as cpp_std
.
cpp_std
cpp_std
is a string representing which C standard version to use. Valid values:
- A specific version, such as
"gnu++11"
"experimental"
, which is a value defined by the build system inbuild/soong/cc/config/global.go
, may use draft versions like C++1z when they're available.- Unset or
""
, which indicates that the build system default should be used.
If this is set, the file extension is ignored and the header is assumed to
be a C++ header. This cannot be set at the same time as c_std
.
cflags
cflags
provides a string list of Clang flags required to correctly interpret the
headers.
custom_bindgen
For advanced use cases, bindgen can be used as a library, providing an API that
can be manipulated as part of a custom Rust binary. The custom_bindgen
field
takes the module
name of a rust_binary_host
module, which uses the bindgen API instead
of the normal bindgen
binary.
This custom binary must expect arguments in a similar fashion to bindgen
, such
as
$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]
Most of this is handled by the bindgen
library itself. To see an example of this
usage, visit external/rust/crates/libsqlite3-sys/android/build.rs.
Additionally, the full set of library properties is available to control the compilation of the library, although these rarely need defining or changing.
handle_static_inline and static_inline_library
These two properties are meant to be used together and allow production of wrappers for static inline functions which can be included in the exported bindgen bindings.
To use them, set handle_static_inline: true
and set static_inline_library
to
a corresponding cc_library_static
which defines the rust_bindgen
module as
source input.
Example usage:
rust_bindgen {
name: "libbindgen",
wrapper_src: "src/any.h",
crate_name: "bindgen",
stem: "libbindgen",
source_stem: "bindings",
// Produce bindings for static inline fucntions
handle_static_inline: true,
static_inline_library: "libbindgen_staticfns"
}
cc_library_static {
name: "libbindgen_staticfns",
// This is the rust_bindgen module defined above
srcs: [":libbindgen"],
// The include path to the header file in the generated c file is
// relative to build top.
include_dirs: ["."],
}