A project for generating C bindings from Rust code


cbindgenBuild Status Latest Version Api Rustdoc Rust

Read the full user docs here!

cbindgen creates C/C++11 headers for Rust libraries which expose a public C API.

While you could do this by hand, it's not a particularly good use of your time. It's also much more likely to be error-prone than machine-generated headers that are based on your actual Rust code. The cbindgen developers have also worked closely with the developers of Rust to ensure that the headers we generate reflect actual guarantees about Rust's type layout and ABI.

C++ headers are nice because we can use operator overloads, constructors, enum classes, and templates to make the API more ergonomic and Rust-like. C headers are nice because you can be more confident that whoever you're interoperating with can handle them. With cbindgen you don't need to choose! You can just tell it to emit both from the same Rust library.

There are two ways to use cbindgen: as a standalone program, or as a library (presumably in your build.rs). There isn't really much practical difference, because cbindgen is a simple rust library with no interesting dependencies.

Using it as a program means people building your software will need it installed. Using it in your library means people may have to build cbindgen more frequently (e.g. every time they update their rust compiler).

It's worth noting that the development of cbindgen has been largely adhoc, as features have been added to support the usecases of the maintainers. This means cbindgen may randomly fail to support some particular situation simply because no one has put in the effort to handle it yet. Please file an issue if you run into such a situation. Although since we all have other jobs, you might need to do the implementation work too :)

Quick Start

To install cbindgen, you just need to run

cargo install --force cbindgen

(--force just makes it update to the latest cbindgen if it's already installed)

To use cbindgen you need two things:

  • A configuration (cbindgen.toml, which can be empty to start)
  • A Rust crate with a public C API

Then all you need to do is run it:

cbindgen --config cbindgen.toml --crate my_rust_library --output my_header.h

This produces a header file for C++. For C, add the --lang c switch.

See cbindgen --help for more options.

Read the full user docs here!

Get a template cbindgen.toml here.


We don't currently have a nice tailored example application, but the tests contain plenty of interesting examples of our features.

You may also find it interesting to browse the projects that are using cbindgen in production:

If you're using cbindgen and would like to be added to this list, please open a pull request!


cbindgen doesn't have a fixed release calendar, please file an issue requesting a release if there's something fixed in trunk that you need released. Ping @emilio for increased effect.

  • fix: resolve path types for 'both' style

    fix: resolve path types for 'both' style

    Potentially fixes #215.

    Types of structs were not being resolved when the style was set to 'both', resulting in the struct keyword not being added to struct field types. This caused compiler errors complaining about missing forward declarations.

    opened by Wodann 24
  • ir: Add the possibility to auto-generate destructors of tagged unions.

    ir: Add the possibility to auto-generate destructors of tagged unions.

    This trades the ABI-safety (making the struct potentially unsafe to pass by value), thus the opt-in rather than auto-generating it.

    The TL;DR is that I need a way to share types that contain boxed slices from the style system. That's fine when they're inside regular structs, since C++ does the right thing, but for unions you need to make it explicit like this.

    The actual Gecko setup will hook into the leak logging machinery to avoid silly leaks and such of course.

    opened by emilio 20
  • Include tag names on C structs

    Include tag names on C structs

    Much C code uses tag names instead of type names on structs. E.g:

    struct account x;


    account x;

    When implementing legacy C interfaces in Rust it is nice be able to generate header files that are compatible with this practice.

    This pull request introduces three style, tag only, typedef only and both tag and typedef.

    Tag only:

    struct balance {
      int dollars;
      int cents;
    struct account {
        struct balance;

    Type only:

    typedef struct {
      int dollars;
      int cents;
    } balance;
    typedef struct {
    } account;

    Both only:

    typedef struct balance {
      int dollars;
      int cents;
    } balance;
    typedef struct account {
    } account;

    The default is Typedef only and no changes has been made to the generated headers (although it seems some other change has resulted in some new types). The test script has been modified to also build the tests with tag only and both. These files end up in tests/expectations/{tag, both}

    opened by janderholm 18
  • uchar.h is missing on macOS

    uchar.h is missing on macOS

    We're using cbindgen to generate both C and C++ headers in our project. However, the generated C header fails to build on macOS with the 0.10.1 release (https://github.com/mbrobbel/dqcsim/pull/313) because uchar.h is missing on macOS.

    target/include/dqcsim.h:5:10: fatal error: 'uchar.h' file not found
    #include <uchar.h>
    opened by mbrobbel 13
  • Find a way to update `serde_derive`

    Find a way to update `serde_derive`

    From #159

    I thought we had an issue filed with exactly what is going on here, but we don't exactly. I'll summarize it here for reference and file an issue later.

    cbindgen depends on syn which depends on proc-macro-2 because syn is geared to be used in proc-macros not random binaries for parsing rust code. proc-macro-2 is the problematic library that causes this crash because it depends on internal compiler libs.

    cbindgen doesn't need any of the functionality from syn that uses proc-macro-2 though, so we had a feature added to syn called proc-macro that we could use to disable this dependency. But disabling that feature is not enough to prevent proc-macro-2 from being linked.

    Unfortunately proc-macro-2 is used by serde_derive as a build time proc-macro crate, and cargo does feature flag resolution once for build dependencies and binary dependencies. So our feature flag gets overridden because serde_derive needs that flag enabled. Even though serde_derive only happens at compile time, and we want the feature disabled at run time.

    But not all serde_derive's have this dependency. Which is why we pin to a version which doesn't yet have it.

    That's what rust-lang/cargo#2589 is about, and why it's still relevant. If that's fixed we could use the feature flag and update serde_derive.

    I don't think we could easily drop the serde_derive requirement either. It's used for parsing cbindgen.toml which isn't required if all you care about is build.rs. But it is used for parsing Cargo.lock which is required for most uses of the crate.

    This has been a major pain, and I'd love to find an answer to it.

    opened by eqrion 13
  • Support generation of Cython bindings

    Support generation of Cython bindings

    Cython [wiki] is a language extension for Python that allows writing C-based Python packages in a more humane way (that includes easier reuse of third-party C libraries).

    Cython "headers" (.pxd files) are basically C headers re-syntaxed in a more Python-like way. So cbindgen seems to be a good place to implement generation of such bindings from Rust code. As you can see from the patch, it mostly requires changes to the cbindgen "backend" that generates the resulting text. (The patch is better read with whitespace differences ignored.)

    opened by petrochenkov 11
  • panic: Result has 2 params but is being instantiated with 1 values

    panic: Result has 2 params but is being instantiated with 1 values

    cbdingen version: v0.14.2

    To reproduce the error, run cbindgen --lang c --output test.h test.rs, with the source of test.rs being:

    use std::fmt;
    // Result<(), T> seems to trip up cbindgen, here T=fmt::Error
    // as it was how I ran into it.
    type FmtResult = Result<(), fmt::Error>;
    fn main() {
        println!("cbindgen doesn't like Result<(), T>");

    Should produce the following error+backtrace with RUST_BACKTRACE=1:

    thread 'main' panicked at 'Result has 2 params but is being instantiated with 1 values', /home/sanoj/.local/share/cargo/registry/src/github.com-1ecc6299db9ec823/cbindgen-0.14.2/src/bindgen/ir/opaque.rs:112:9
    stack backtrace:
       0: backtrace::backtrace::libunwind::trace
                 at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88
       1: backtrace::backtrace::trace_unsynchronized
                 at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66
       2: std::sys_common::backtrace::_print_fmt
                 at src/libstd/sys_common/backtrace.rs:84
       3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
                 at src/libstd/sys_common/backtrace.rs:61
       4: core::fmt::write
                 at src/libcore/fmt/mod.rs:1025
       5: std::io::Write::write_fmt
                 at src/libstd/io/mod.rs:1426
       6: std::sys_common::backtrace::_print
                 at src/libstd/sys_common/backtrace.rs:65
       7: std::sys_common::backtrace::print
                 at src/libstd/sys_common/backtrace.rs:50
       8: std::panicking::default_hook::{{closure}}
                 at src/libstd/panicking.rs:193
       9: std::panicking::default_hook
                 at src/libstd/panicking.rs:210
      10: std::panicking::rust_panic_with_hook
                 at src/libstd/panicking.rs:475
      11: rust_begin_unwind
                 at src/libstd/panicking.rs:375
      12: std::panicking::begin_panic_fmt
                 at src/libstd/panicking.rs:326
      13: <cbindgen::bindgen::ir::opaque::OpaqueItem as cbindgen::bindgen::ir::item::Item>::instantiate_monomorph
      14: cbindgen::bindgen::ir::ty::Type::add_monomorphs
      15: cbindgen::bindgen::library::Library::generate
      16: cbindgen::bindgen::builder::Builder::generate
      17: cbindgen::main
      18: std::rt::lang_start::{{closure}}
      19: std::rt::lang_start_internal::{{closure}}
                 at src/libstd/rt.rs:52
      20: std::panicking::try::do_call
                 at src/libstd/panicking.rs:292
      21: __rust_maybe_catch_panic
                 at src/libpanic_unwind/lib.rs:78
      22: std::panicking::try
                 at src/libstd/panicking.rs:270
      23: std::panic::catch_unwind
                 at src/libstd/panic.rs:394
      24: std::rt::lang_start_internal
                 at src/libstd/rt.rs:51
      25: main
      26: __libc_start_main
      27: _start

    The error does not occur with --lang c++.

    Also reported here: https://github.com/eqrion/cbindgen/issues/206, but without a snippet to reproduce it.

    bug help wanted 
    opened by snyball 11
  • Expand slices to separate pointer and size

    Expand slices to separate pointer and size

    It would be really nice to support slices by splitting those into separate (pointer, size) values, e.g.

       objects: &[Object],

    would be translated into:

       objects: *const Object,
       objects_length: size_t,

    where the "_length" suffix is configured like all the other prefixes/suffixes

    opened by kvark 11
  • Prefix for associated constants

    Prefix for associated constants

    We are looking at the bitflags output of this struct:

    bitflags! {
        pub struct TextureUsageFlags: u32 {
            const TRANSFER_SRC = 1;
            const TRANSFER_DST = 2;
            const SAMPLED = 4;
            const STORAGE = 8;
            const OUTPUT_ATTACHMENT = 16;
            const PRESENT = 32;
            const NONE = 0;
            const WRITE_ALL = 2 + 8 + 16;

    The result looks like this:

    #define WGPUOUTPUT_ATTACHMENT (TextureUsageFlags){ .bits = 16 }
    #define WGPUPRESENT (TextureUsageFlags){ .bits = 32 }

    There is "WGPU" prefix attached (which we specify in the options, but it's only means for types), and instead we'd want the type name to be the prefix, i.e.


    The current output is not very usable - it's not desired to have the type prefix affecting associated constants, and the way they are generated now there appears to be conflict between types (i.e. we have similar constants for BufferUsageFlags bitflags, and they overlap).

    cc @grovesNL @eqrion @IGI-111

    opened by kvark 11
  • Added support for `#[repr(transparent)]`

    Added support for `#[repr(transparent)]`

    #[repr(transparent)] was stabilized today:

    Version 1.28.0 (2018-08-02)

    The #[repr(transparent)] attribute is now stable. This attribute allows a Rust newtype wrapper (struct NewType(T);) to be represented as the inner type across Foreign Function Interface (FFI) boundaries.

    opened by regexident 11
  • Fixes and improvements for tagged enums

    Fixes and improvements for tagged enums

    • Implement support for repr(C, Int) (fixes #119)
    • Fix wrapper kind for C-like tagged enum (fixes #126)
    • Wrap tag into anonymous struct in C++ (fixes #122)

    cc @Gankro

    opened by RReverser 11
  • `with_parse_expand(...)` from build.rs seems to hang indefinetly

    `with_parse_expand(...)` from build.rs seems to hang indefinetly

    I have a pretty simple project that uses macros. I try to expand them from inside my build.rs file and it seems to hang forever.

    per my build script below... If I remove with_parse_expand(...) line then my project generates headers fine except I don't get the expansions in my header. If I add back the with_parse_expand(...) statement then my build never finishes. My repo is pretty minimal and perhaps it can be used to reproduce. : https://github.com/TomzBench/minicbor-c

    Below is my build script:

    use std::env;
    fn main() {
        let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
            .expect("Unable to generate bindings")
    opened by TomzBench 7
  • cbindgen not exporting items declared after macro expansion.

    cbindgen not exporting items declared after macro expansion.

    I'm building a library that is intended to be loaded dynamically with dlopen/LoadLibrary so I'd like to have autogenerated function pointer types as well.

    I came up with the following macro

    macro_rules! extern_fn {
        ($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),*) $body:block) => {
            paste::paste! {
                pub type [<PFN_ $func_name>] = unsafe extern "C" fn($($arg_name: $arg_ty,)*) -> $crate::ctypes::error_t;
            fn $func_name($($arg_name: $arg_ty,)*) -> $crate::ctypes::error_t {
                let result: Result<(), $crate::error::Error> = try {
                let Err(e) = result else {
                    return $crate::error::Error::ok()
    extern_fn! {
        fn do_stuff(filename: *const c_char) {
            // do stuff

    This would normally export a #[no_mangle] function do_stuff, and a function pointer type PFN_do_stuff. cbindgen does not detect either of these declarations. I tried expand but it fails with an error or hands indefinitely when I tell it to expand the crate name.

    opened by chyyran 1
  • docs.rs link broken (worked from root of this repo on GitHub)

    docs.rs link broken (worked from root of this repo on GitHub)


    Fails as it tries https://docs.rs/crate/cbindgen/docs.md Screenshot 2022-12-03 at 2 57 04 PM

    …but on this GitHub repo it works: Read the full user docs here!

    opened by SamuelMarks 0
  • Need verbose output when generate() gets failed

    Need verbose output when generate() gets failed

    I had got

      thread 'main' panicked at 'Unable to generate bindings: ParseSyntaxError { crate_name: "code_impl", src_path: "/home/usr/src/code.rs", error: Error("unexpected end of input, expected one of: `fn`, `extern`, `use`, `static`, `const`, `unsafe`, `mod`, `type`, `struct`, `enum`, `union`, `trait`, `auto`, `impl`, `default`, `macro`, identifier, `self`, `super`, `crate`, `::`") }', build.rs:25:10

    and I spent a lot of time to find an error in a comment (rust parses comments?) inside code.rs.

    Anyway please could you add some verbose mode into cbindgen to show us full details about parsing error? Or I'm missing some existing option...?

    opened by antmak 0
  • Problems when I use it together with the bindgen.

    Problems when I use it together with the bindgen.

    Hello, I'm using cbindgen and bindgen to generate bindings for my project.

    The project is previously written in C, but now I want to introduce Rust to it. The problem is, when I use it together with the binden, how can I set the cbindgen to ignore the bindings.rs generated by the binden? Now I found that the cbindgen generates C bindings for those functions which actually written in C!

    Thank you!

    opened by fslongjin 0
  • Panic when flattening certain generics

    Panic when flattening certain generics

    The oauth2 crate defines a type Error which is a generic enum. When flattening a certain variant of this enum for use in my libraries Error type, cbindgen panics

    use oauth2;
    pub type OAuth2ReqwestReqwestError = oauth2::reqwest::Error<reqwest::Error>;
    pub enum Error {
    impl From<OAuth2ReqwestReqwestError> for Error {
        fn from(val: OAuth2ReqwestReqwestError) -> Self {

    The error message on running cbindgen is

    thread 'main' panicked at 'Error is not generic', /Users/georgemp/.cargo/registry/src/github.com-1ecc6299db9ec823/cbindgen-0.24.3/src/bindgen/ir/opaque.rs:105:9
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

    The following snippet wherein I extract the reqwest::error from the oauth2 generic works

    use oauth2;
    pub enum Error {
    impl From<oauth2::reqwest::Error<reqwest::Error>> for Error {
        fn from(val: oauth2::reqwest::Error<reqwest::Error>) -> Self {
            match val {
                oauth2::reqwest::Error::Reqwest(error) => Error::Reqwest(error),
                _ => unreachable!("Error is expected to be from Reqwest"),

    It seems like the presence of this line pub type OAuth2ReqwestReqwestError = oauth2::reqwest::Error<reqwest::Error> is triggering the panic.

    If there is anything information you'd like on this, please let me know. Thanks

    opened by georgemp 1
Ryan Hunt
Ryan Hunt
A self-guided learning project that includes Rust + Wasm together

A self-guided learning project that includes Rust + Wasm together. Who knows, maybe Typescript and React joins too..

M.Yavuz Yagis 1 Feb 14, 2022
Create a Python project automatically with rust (like create-react-app but for python)

create-python-project Create a Python project automatically with rust (like create-react-app but for python) Installation cargo install create-python-

Dhravya Shah 2 Mar 12, 2022
Rust based WASM/JS bindings for ur-rust

ur-wasm-js WASM/JS bindings for the ur-rust rust library Getting started Installation Either build the library yourself with wasm-pack or install for

Lightning Digital Entertainment 5 Feb 28, 2024
Create, open, manage your Python projects with ease, a project aimed to make python development experience a little better

Create, open, manage your Python projects with ease, a project aimed to make python development experience a little better

Dhravya Shah 7 Nov 18, 2022
C-like language compiler, the final project of ZJU Compiler Principle course

cc99 cc99 (not cc98.org) is a C-like language compiler, which is the final project of ZJU Compiler Principle course. It supports many of the C99 langu

Ralph 37 Oct 18, 2022
Vite + Webassembly starter project

Vite + Typescript+ Webassembly A starter project for you to create a blazingly fast web application Before getting started You need to get these prere

Saugi 9 Aug 18, 2022
🚀 An OSS project to develop and run serverless applications on WebAssembly

Wasm Workers Server Wasm Workers Server (wws) is a framework to develop and run serverless applications server in WebAssembly. These applications are

VMware  Labs 300 Apr 26, 2023
Automatically generates Rust FFI bindings to C (and some C++) libraries.

bindgen bindgen automatically generates Rust FFI bindings to C (and some C++) libraries. For example, given the C header doggo.h: typedef struct Doggo

The Rust Programming Language 3.2k Jan 4, 2023
Rust-JDBC bindings

jdbc A Rust library that allows you to use JDBC and JDBC drivers. Usage First, add the following to your Cargo.toml: [dependencies] jdbc = "0.1" Next,

Aurora 18 Feb 9, 2022
Lua 5.3 bindings for Rust

rust-lua53 Aims to be complete Rust bindings for Lua 5.3 and beyond. Currently, master is tracking Lua 5.3.3. Requires a Unix-like environment. On Win

J.C. Moyer 150 Dec 14, 2022
Safe Rust bindings to Lua 5.1

rust-lua Copyright 2014 Lily Ballard Description This is a set of Rust bindings to Lua 5.1. The goal is to provide a (relatively) safe interface to Lu

Lily Ballard 124 Jan 5, 2023
mruby safe bindings for Rust

mrusty. mruby safe bindings for Rust mrusty lets you: run Ruby 1.9 files with a very restricted API (without having to install Ruby) reflect Rust stru

Anima 200 Oct 12, 2022
Rust bindings for writing safe and fast native Node.js modules.

Rust bindings for writing safe and fast native Node.js modules. Getting started Once you have the platform dependencies installed, getting started is

The Neon Project 7k Jan 4, 2023
Objective-C Runtime bindings and wrapper for Rust.

Objective-C Runtime bindings and wrapper for Rust. Documentation: http://ssheldon.github.io/rust-objc/objc/ Crate: https://crates.io/crates/objc Messa

Steven Sheldon 336 Jan 2, 2023
High-level Rust bindings to Perl XS API

Perl XS for Rust High-level Rust bindings to Perl XS API. Example xs! { package Array::Sum; sub sum_array(ctx, array: AV) { array.iter().map(|

Vickenty Fesunov 59 Oct 6, 2022
Rust <-> Python bindings

rust-cpython Rust bindings for the python interpreter. Documentation Cargo package: cpython Copyright (c) 2015-2020 Daniel Grunwald. Rust-cpython is l

Daniel Grunwald 1.7k Dec 29, 2022
Rust bindings for the Python interpreter

PyO3 Rust bindings for Python. This includes running and interacting with Python code from a Rust binary, as well as writing native Python modules. Us

PyO3 7.2k Jan 4, 2023
Safe Rust <---> GraalVM Polyglot bindings using procedural macros

The class macro is the primary way to generate bindings to Java types; it will generate a struct (with generics if specified) that implements Pass and Receive and has all the methods you give stubs for. The methods generated can be used like normal rust methods, however mutability is not enforced. The fully-qualified type name should precede a block containing method and constructor stubs. Java primitives like char, int, and byte are aliased to corresponding Rust types.

Alec Petridis 33 Dec 28, 2022
Rust bindings for accessing the Go containers/image stack

Rust bindings for accessing the Go containers/image stack This crate contains a Rust API that forks /usr/bin/skopeo and talks to it via a custom API.

Containers 16 Dec 26, 2022