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][file-it]. 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
```text
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)
If you'd like to use a `build.rs` script with a `cbindgen.toml`, consider using [`cbindgen::generate()`](https://docs.rs/cbindgen/*/cbindgen/fn.generate.html) instead.
# Writing Your C API
cbindgen has a simple but effective strategy. It walks through your crate looking for:
*`#[no_mangle] pub extern fn` ("functions")
*`#[no_mangle] pub static` ("globals")
*`pub const` ("constants")
and generates a header declaring those items. But to declare those items, it needs to also be able to describe the layout and ABI of the types that appear in their signatures. So it will also spider through your crate (and optionally its dependencies) to try to find the definitions of every type used in your public API.
> 🚨 NOTE: A major limitation of cbindgen is that it does not understand Rust's module system or namespacing. This means that if cbindgen sees that it needs the definition for `MyType` and there exists two things in your project with the type name `MyType`, it won't know what to do. Currently, cbindgen's behaviour is unspecified if this happens. However this may be ok if they have [different cfgs][section-cfgs].
If a type is determined to have a guaranteed layout, a full definition will be emitted in the header. If the type doesn't have a guaranteed layout, only a forward declaration will be emitted. This may be fine if the type is intended to be passed around opaquely and by reference.
# Examples
🚧 🏗
It would be really nice to have some curated and clean examples, but we don't have those yet.
[The README has some useful links though](README.md#examples).
# Supported Types
Most things in Rust don't have a guaranteed layout by default. In most cases this is nice because it enables layout to be optimized in the majority of cases where type layout isn't that interesting. However this is problematic for our purposes. Thankfully Rust lets us opt into guaranteed layouts with the `repr` attribute.
You can learn about all of the different repr attributes [by reading Rust's reference][reference], but here's a quick summary:
*`#[repr(C)]`: give this struct/union/enum the same layout and ABI C would
*`#[repr(u8, u16, ... etc)]`: give this enum the same layout and ABI as the given integer type
*`#[repr(transparent)]`: give this single-field struct the same ABI as its field (useful for newtyping integers but keeping the integer ABI)
cbindgen also supports using `repr(C)`/`repr(u8)` on non-C-like enums (enums with fields). This gives a C-compatible tagged union layout, as [defined by this RFC 2195][really-tagged-unions]. `repr(C)` will give a simpler layout that is perhaps more intuitive, while `repr(u8)` will produce a more compact layout.
If you ensure everything has a guaranteed repr, then cbindgen will generate definitions for:
* struct (named-style or tuple-style)
* enum (fieldless or with fields)
* union
* type
*`[T; n]` (arrays always have a guaranteed C-compatible layout)
*`&T`, `&mut T`, `*const T`, `*mut T`, `Option<&T>`, `Option<&mut T>` (all have the same pointer ABI)
*`fn()` (as an actual function pointer)
*`bitflags! { ... }` (if macro_expansion.bitflags is enabled)
structs, enums, unions, and type aliases may be generic, although certain generic substitutions may fail to resolve under certain configurations. In C mode generics are resolved through monomorphization and mangling, while in C++ mode generics are resolved with templates. cbindgen cannot support generic functions, as they do not actually have a single defined symbol.
cbindgen sadly cannot ever support anonymous tuples `(A, B, ...)`, as there is no way to guarantee their layout. You must use a tuple struct.
cbindgen also cannot support wide pointers like `&dyn Trait` or `&[T]`, as their layout and ABI is not guaranteed. In the case of slices you can at least decompose them into a pointer and length, and reconstruct them with `slice::from_raw_parts`.
If cbindgen determines that a type is zero-sized, it will erase all references to that type (so fields of that type simply won't be emitted). This won't work if that type appears as a function argument because C, C++, and Rust all have different definitions of what it means for a type to be empty.
Don't use the `[u64; 0]` trick to over-align a struct, we don't support this.
cbindgen contains the following hardcoded mappings (again completely ignoring namespacing, literally just looking at the name of the type):
cbindgen supports several different options for configuring the output of your header, including target language, styling, mangling, prefixing, includes, and defines.
## Defines and Cfgs
As cbindgen spiders through your crate, it will make note of all the cfgs it found on the path to every item. If it finds multiple declarations that share a single name but have different cfgs, it will then try to emit every version it found wrapped in defines that correspond to those cfgs. In this way platform-specific APIs or representations can be properly supported.
However cbindgen has no way of knowing how you want to map those cfgs to defines. You will need to use the `[defines]` section in your cbindgen.toml to specify all the different mappings. It natively understands concepts like any() and all(), so you only need to tell it how you want to translate base concepts like `target_os = "freebsd"` or `feature = "serde"`.
Note that because cbindgen just parses the source of your crate, you mostly don't need to worry about what crate features or what platform you're targetting. Every possible configuration should be visible to the parser. Our primitive mappings should also be completely platform agnostic (i32 is int32_t regardless of your target).
While modules within a crate form a tree with uniquely defined paths to each item, and therefore uniquely defined cfgs for those items, dependencies do not. If you depend on a crate in multiple ways, and those ways produce different cfgs, one of them will be arbitrarily chosen for any types found in that crate.
## Annotations
While output configuration is primarily done through the cbindgen.toml, in some cases you need to manually override your global settings. In those cases you can add inline annotations to your types, which are doc comments that start with `cbindgen:`. Here's an example of using annotations to rename a struct's fields and opt into overloading `operator==`:
```rust
/// cbindgen:field-names=[x, y]
/// cbindgen:derive-eq
#[repr(C)]
pub struct Point(pub f32, pub f32);
```
An annotation may be a bool, string (no quotes), or list of strings. If just the annotation's name is provided, `=true` is assumed. The annotation parser is currently fairly naive and lacks any capacity for escaping, so don't try to make any strings with `=`, `,`, `[` or `]`.
Most annotations are just local overrides for identical settings in the cbindgen.toml, but a few are unique because they don't make sense in a global context. The set of supported annotation are as follows:
* field-names=\[field1, field2, ...\] -- sets the names of all the fields in the output struct. These names will be output verbatim, and are not eligible for renaming.
The rest are just local overrides for the same options found in the cbindgen.toml:
* enum-trailing-values=\[variant1, variant2, ...\] -- add the following fieldless enum variants to the end of the enum's definition. These variant names *will* have the enum's renaming rules applied.
WARNING: if any of these values are ever passed into Rust, behaviour will be Undefined. Rust does not know about them, and will assume they cannot happen.
The rest are just local overrides for the same options found in the cbindgen.toml:
* field-names=\[field1, field2, ...\] -- sets the names of all the fields in the output union. These names will be output verbatim, and are not eligible for renaming.
The rest are just local overrides for the same options found in the cbindgen.toml:
* rename-all=RenameRule
### Function Annotations
All function attributes are just local overrides for the same options found in the cbindgen.toml:
* ptrs-as-arrays=\[[ptr\_name1; array\_length1], [ptr\_name2; array\_length2], ...\] -- represents the pointer arguments of a function as arrays. Below how the mappings are performed:
In addition to parsing function names in C/C++ header files, the Swift compiler can make use of the `swift_name` attribute on functions to generate more idiomatic names for imported functions and methods.
This attribute is commonly used in Objective-C/C/C++ via the `NS_SWIFT_NAME` and `CF_SWIFT_NAME` macros.
Given configuration in the cbindgen.toml, `cbindgen` can generate these attributes for you by guessing an appropriate method signature based on the existing function name (and type, if it is a method in an `impl` block).
This is controlled by the `swift_name_macro` option in the cbindgen.toml.
Most configuration happens through your cbindgen.toml file. Every value has a default (that is usually reasonable), so you can start with an empty cbindgen.toml and tweak it until you like the output you're getting.
Note that many options defined here only apply for one of C or C++. Usually it's an option specifying whether we should try to make use of a feature in C++'s type system or generate a helper method.