Rust-Rust bindgen: rust-bindgen dtolnayC++ rust-lang/rust-bindgen — A Rust bindings generator dtolnay/cxx — Safe interop between Rust and C++


bindgen automatically generates Rust FFI bindings to C (and some C++) libraries.

For example, given the C header doggo.h:

typedef struct Doggo {
    int many;
    char wow;
} Doggo;

void eleven_out_of_ten_majestic_af(Doggo* pupper);

bindgen produces Rust FFI code allowing you to call into the doggo library's functions and use its types:

/* automatically generated by rust-bindgen */

pub struct Doggo {
    pub many: ::std::os::raw::c_int,
    pub wow: ::std::os::raw::c_char,

extern "C" {
    pub fn eleven_out_of_ten_majestic_af(pupper: *mut Doggo);

Users Guide

? Read the bindgen users guide here! ?


The minimum supported Rust version is 1.34.

No MSRV bump policy has been established yet, so MSRV may increase in any release.

API Reference

API reference documentation is on

Environment Variables

In addition to the library API and executable command-line API, bindgen can be controlled through environment variables.

End-users should set these environment variables to modify bindgen's behavior without modifying the source code of direct consumers of bindgen.

  • BINDGEN_EXTRA_CLANG_ARGS: extra arguments to pass to clang
    • Arguments are whitespace-separated
    • Use shell-style quoting to pass through whitespace
    • Examples:
      • Specify alternate sysroot: --sysroot=/path/to/sysroot
      • Add include search path with spaces: -I"/path/with spaces"

Additionally, bindgen uses libclang to parse C and C++ header files. To modify how bindgen searches for libclang, see the clang-sys documentation. For more details on how bindgen uses libclang, see the bindgen users guide.


See for hacking on bindgen!


  • Add a member names callback for ParseCallbacks
    Add a member names callback for ParseCallbacks

    Jun 6, 2020

    I'm new to both rust and bindgen, so please tell me if there's something I'm doing wrong here, but at least it works

  • libclang not found when building using github actions for windows target
    libclang not found when building using github actions for windows target

    Jun 6, 2020

    I'm trying to use github actions to CI build my crate for several platforms. The windows target build fails on bindgen with:

    thread 'main' panicked at 'Unable to find libclang: "the `libclang` shared library at C:\\msys64\\mingw64\\bin\\libclang.dll could not be opened: The specified module could not be found. (os error 126)"', C:\Users\runneradmin\.cargo\registry\src\\bindgen-0.54.0\src/

    This works all fine for the macos and ubuntu targets btw.

  • Permit IntKind::Custom to represent Paths instead of just Idents
    Permit IntKind::Custom to represent Paths instead of just Idents

    Jun 10, 2020

    If one implements ParseCallbacks::int_macro to specify a custom IntKind, one is currently restricted to mere Idents which must therefore be brought into the generated bindings' scope; this PR permits paths to be specified instead.

    r? @emilio

  • Bindgen produces invalid code (only in one environment)
    Bindgen produces invalid code (only in one environment)

    Jun 10, 2020

    This is probably more an issue on improving documentation.

    I haven't been able to successfully build any projects that has a dependency on bindgen, and can't even get a successful build with the minimal example in the getting started guide.

    trying to build the example in the getting started guide I get:

    293 | #[derive(Copy, Clone)]; 4usize ] , _bindgen_union_align : u32 , }#[test]
        |                                ^ unexpected closing delimiter

    I have followed the requirements which only lists libclang as an external dependency and I run arch and have the latest clang package installed. I also have arch running on a secondary machine and it's able to build projects using bindgen successfully. I haven't been able to figure out what's different on my 2 machines. I've completely reinstalled my rust toolchain from scratch. I've done a bit of searching in the issues and the errors I'm experiencing seem to mostly be around mentioning rustfmt. However those issues are all really old and seem to all be fixed.

    Some of my environment setup:

    rustfmt --version
    rustfmt 1.4.14-stable (e417356 2020-04-21)
    cargo --version
    cargo 1.44.0 (05d080faa 2020-05-06)
    rustup --version
    rustup 1.21.1 (2020-06-09)
    rustc --version
    rustc 1.44.0 (49cae5576 2020-06-01)

    As far as I can see I only have one version of rustfmt because after uninstalling rustup, which rustfmt returned nothing. rustfmt seems to be bundled with the rustup package.

    So I guess I have 3 questions:

    1. If bindgen depends on rustfmt, why doesn't it do so via a cargo dependency to make sure its using a correct version ?
    2. What other environment specific dependencies are being used that aren't listed in the bindgen dependencies?
    3. How can I find out what is broken in my setup when all I get is broken generated code with no clear to debug where something went wrong?

    I'm not sure how many other people are experiencing problems with this, but it would be great to improve the docs/requirements/faq if this is a known issue.

    Any help would be greatly appreciated as I really want to start tinkering with bindgen

  • Interaction of whitelist and opaque
    Interaction of whitelist and opaque

    Jun 12, 2020

    It's not clear from the doc how whitelist* interacts with opaque. If a type is marked both as whitelist and opaque, which takes precedence? What about types transitively marked? Or is there different behavior depending on the order of the method calls? From what I tried it seems opaque overwrites whitelist regardless of order. Happy to help update the doc if someone clarifies this.

  • Include bindgen version in generated file's comment
    Include bindgen version in generated file's comment

    Jun 14, 2020

    Each Rust file generated by bindgen starts with:

    /* automatically generated by rust-bindgen */

    I would find it helpful if that was changed into

    /* automatically generated by rust-bindgen 0.54.0 */

    Or whatever the currently used version happens to be.

    Currently I always solve this myself by having the following in all my scripts:

    #!/usr/bin/env bash
    BINDGEN_VERSION="$(bindgen --version)"
    bindgen ... --raw-line "// Generated using $BINDGEN_VERSION" \

    When coming back to a library you created a while back and you want to re-generate the headers for some reason. Maybe because the underlying C library changed or because you need to expose more/less types or whatever. Then it can help to know what version of bindgen was used last time. For example if you get inconsistent results or have other trouble, having this piece of information available can help track down the problem.

  • Instantiating a template with a template instantiation (eg Template1<Template2<Type>>) causes us to generate bad bindings
    Instantiating a template with a template instantiation (eg Template1>) causes us to generate bad bindings

    Jan 26, 2017


    template <typename> struct a;
    namespace JS {
    template <typename T> using b = a<T>;
    template <typename T> class Rooted { b<T> c; };

    Output with --enable-cxx-namespaces -- --std=c++11:

    /* automatically generated by rust-bindgen */
    pub mod root {
        use self::super::root;
        #[derive(Debug, Copy)]
        pub struct a {
            pub _address: u8,
        impl Clone for a {
            fn clone(&self) -> Self { *self }
        pub mod JS {
            use self::super::super::root;
            pub type b<T> = root::a;
            #[derive(Debug, Copy, Clone)]
            pub struct Rooted<T> {
                pub c: root::JS::b<T>,

    Compilation errors:

    error[E0392]: parameter `T` is never used
    20 |         pub struct Rooted<T> {
       |                           ^ unused type parameter
       = help: consider removing `T` or using a marker such as `std::marker::PhantomData`
    error: aborting due to previous error

    I'm not 100% sure what the best thing to do in this case is, but whatever we do the bindings we emit should compile.

    This seems really familiar... I wonder if we regressed something recently?

  • Add support for 'unsafe fields'
    Add support for 'unsafe fields'

    Jul 20, 2016

    Needed for the next step of

    These are fields which are private but have unsafe accessor functions. Since we generate bindings in a separate module, we can't touch private fields from other parts of the module (an alternative is to inject a footer with these private impls). pub(restricted) exists, but is not stable.

    r? @emilio

  • Auto-generated test failure using <link.h> on Debian 9.
    Auto-generated test failure using on Debian 9.

    Aug 21, 2018

    Input C/C++ Header

    Sorry, I know you asked for no #includes, but I'm at a loss as to what the predicate script should do when I'm just importing types from the C library -- If you can't reproduce from the info below, then could you help me with the predicate script plz? :)

    #define _GNU_SOURCE
    #include <link.h>

    Bindgen Invocation

        let bindings = bindgen::Builder::default()
                               .expect("bindgen failed");

    Actual Results

    When included, like this:

    include!(concat!(env!("OUT_DIR"), "/"));
    $ RUST_BACKTRACE=1 cargo test bindgen_test_layout_La_x86_64_retval
    ---- bindgen_test_layout_La_x86_64_retval stdout ----
    thread 'bindgen_test_layout_La_x86_64_retval' panicked at 'assertion failed: `(left == right)`
      left: `224`,
     right: `240`: Size of: La_x86_64_retval', /home/vext01/research/bg/target/debug/build/bg-29903e2596eaef66/out/
    note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
    stack backtrace:
       0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
                 at libstd/sys/unix/backtrace/tracing/
       1: std::sys_common::backtrace::print
                 at libstd/sys_common/
                 at libstd/sys_common/
       2: std::panicking::default_hook::{{closure}}
                 at libstd/
       3: std::panicking::default_hook
                 at libstd/
       4: std::panicking::rust_panic_with_hook
                 at libstd/
       5: std::panicking::continue_panic_fmt
                 at libstd/
       6: std::panicking::begin_panic_fmt
                 at libstd/
       7: bg::bindgen_test_layout_La_x86_64_retval
                 at ./target/debug/build/bg-29903e2596eaef66/out/
       8: bg::__test::TESTS::{{closure}}
                 at ./target/debug/build/bg-29903e2596eaef66/out/
       9: core::ops::function::FnOnce::call_once
                 at /checkout/src/libcore/ops/
      10: <F as alloc::boxed::FnBox<A>>::call_box
                 at libtest/
                 at /checkout/src/libcore/ops/
                 at /checkout/src/liballoc/
      11: __rust_maybe_catch_panic
                 at libpanic_unwind/

    This is the only failing test.

    Expected Results

    Test passes.

    This is on Debian 9 x86_64, using today's Rust nightly.

    FWIW, OpenBSD's <link.h> does work on an OpenBSD system.

    Any ideas?

  • Publish the executable on
    Publish the executable on

    Jan 14, 2017

    Since this is a useful library that is used in also many non-servo projects, I think it will be convinient to have it in Then also we can do cargo install servo-rust-bindgen .

  • merge into upstream!
    merge into upstream!

    Jul 21, 2016

    Did you consider to merge your modifications into my repo? We both added a lot of features, it would be great if we could join forces.

  • Split off bindgen library into a sub-crate
    Split off bindgen library into a sub-crate

    Nov 4, 2016

    • Unfortunately there's a dependency on log via syntex_errors, so we don't get rid of it all
    • I can't find a more sensible way to set dependencies based on whether you're building the lib or bin
    • So --no-default-features means you need to know what you're doing, as only the lib will build without the logging crates for now
    • The replacement log macros are pretty gross too, but they show a proof of concept ;-)