Bindgen Bindings Modules

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);
}

Defining 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.

Using 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.

Testing 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.

Current limitations mean that rust_test modules for generated bindings must use the include!() method; rust_test modules without defined sources aren't supported.

Create external/rust/hello_bindgen/src/bindings.rs with the following contents:

// Note that "bindings.rs" here must match the source_stem property from
// the rust_bindgen module, with the ".rs" extension added to it.
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

Then add a module to external/rust/hello_bindgen/Android.bp:

rust_test {
    name: "bindings_test",
    srcs: [
        "src/bindings.rs",
        ":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",
}

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" value defined by the build system in build/soong/cc/config/global.go, may use draft versions like C++1z when they're available.
    • "default" or " " both use the build system default.

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" value defined by the build system in build/soong/cc/config/global.go, may use draft versions like C++1z when they're available.
    • "default" or " " both the build system default.

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.