Generating Rust Bindings for Embedded Libraries

As I talked about in my last post, [Embedded Rust Right Now!](, you can call C functions directly from Rust without much difficulty. However, you normally still need to provide Rust types and prototypes for the corresponding C types and functions you want to use. This can be a time-consuming and error-prone process.

Fortunately there is a tool call rust-bindgen that can generate bindings automatically directly from C header files! It’s a little trickier when you’re cross compiling to target embedded systems, but you just need to pass some extra clang flags to bindgen.

## Setting up rust-bindgen

First off, you’ll need a Rust nightly ([]( Then grab Rust bindgen ([]( and follow the instructions in the README to build it:

cargo build

The bindgen executable will be at: `./target/debug/bindgen`

You’ll also need to add some of the clang libraries to your `DYLD_LIBRARY_PATH`:


## Generating Bindings!

Now you’re ready to generate bindings. As an example, I’m going make Rust bindings for the STM32F4 HAL and driver library `STM32Cube`.

The main header file is `stm32f4xx_hal.h`, so the basic command to start with would be `bindgen stm32f4xx_hal.h`. Unfortunately we’re going to need to add a few more flags to make that work.

I added some include paths for the headers that `stm32f4xx_hal.h` will refer to:

-ISTM32Cube_FW_F4_V1.4.0/Drivers/CMSIS/Device/ST/STM32F4xx/Include -ISTM32Cube_FW_F4_V1.4.0/Drivers/CMSIS/Include

and an extra option also needed by `stm32f4xx_hal.h`


## Making Sure our Types Match our Target

At this point the binding generation would “work” but would be tailored for your host system instead of the STM32F4 target. In particular, certain types might end up being the wrong size (32 vs 64bit, etc.).

To fix this, we need to add flags for a sysroot for our target platform. I’m using this one: [](


And then flags to specify the target architecture/CPU:

-target thumbv7em-none-eabi -mcpu=cortex-m4 -mthumb -mfloat-abi=soft

The final command ends up being:

bindgen STM32Cube_FW_F4_V1.4.0/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h -DSTM32F439xx -ISTM32Cube_FW_F4_V1.4.0/Drivers/CMSIS/Device/ST/STM32F4xx/Include/ -I../STM32Cube_FW_F4_V1.4.0/Drivers/CMSIS/Include –sysroot=gcc-arm-none-eabi-4_9-2014q4/arm-none-eabi -target thumbv7em-none-eabi -mcpu=cortex-m4 -mthumb -mfloat-abi=soft -o

And now we have Rust bindings for STM32F4Cube in ``!

If you’re using `no_std`, to build without the Rust standard library you’ll have to replace instances of `::std::` in `` with `::core::`. Also, if you don’t have a Rust libc built for your target you can replace instances of types like `::libc::c_int` or `::libc::c_short` with the equivalent Rust type for your target such as `i32` and `i16` to remove the dependency on libc. Other than that you should be set.

  • Ben Gesoff says:

    Is there a reason for not compiling bindgen with the –release flag?

    • Job Vranish Job Vranish says:

      Not that I know of, I would expect it would still work just fine.

  • Emily says:

    SIP – A Tool for Generating Python Bindings for C and …

  • Ildar says:

    Doesn’t work anymore (it seems):
    error: unions are unstable and possibly buggy (see issue #32836)

  • Comments are closed.