Migrate from cbindgen
This guide walks through moving an existing cbindgen-using crate to
cheadergen. Before you start, read
Comparison with cbindgen and
Limitations so you know what features won’t
carry over.
1. Install cheadergen
See Install cheadergen.
2. Translate your cbindgen.toml
cheadergen config translate \
--from cbindgen.toml \
--to cheadergen.toml
The translator covers the option set cheadergen supports. Any cbindgen-only
options are reported and need a manual decision.
A spot-check, before:
# cbindgen.toml
language = "C"
include_guard = "MYLIB_H"
pragma_once = true
[parse]
parse_deps = true
after:
# cheadergen.toml
pragma_once = true
[header."mylib"]
include_guard = "MYLIB_H"
cheadergen doesn’t have an equivalent of parse_deps because the rustdoc
pipeline always sees dependency types when they’re reachable from extern "C"
items — the option simply isn’t needed.
3. Rewrite cbindgen annotations
cbindgen reads doc-comment annotations like /// cbindgen:rename-all=...;
cheadergen uses proc-macro attributes. Sweep your source and translate them
using this table:
cbindgen (doc comment) | cheadergen (proc-macro attr) |
|---|---|
/// cbindgen:no-export | #[cheadergen::config(skip)] |
/// cbindgen:ignore | #[cheadergen::config(skip)] |
/// cbindgen:rename-all=ScreamingSnakeCase | #[cheadergen::config(rename_all = "SCREAMING_SNAKE_CASE")] |
/// cbindgen:rename-all=SnakeCase | #[cheadergen::config(rename_all = "snake_case")] |
/// cbindgen:rename-all=CamelCase | #[cheadergen::config(rename_all = "camelCase")] |
/// cbindgen:field-names=[x, y] | #[cheadergen::config(field_names(x, y))] |
/// cbindgen:prefix-with-name | #[cheadergen::config(prefix_with_name)] |
/// cbindgen:bitfield (on a field) | #[cheadergen(bitfield = N)] |
You’ll also need to add the crate dependency:
# Cargo.toml
[dependencies]
cheadergen = "0.2"
The proc-macro lives in the cheadergen crate; you don’t need to depend on
cheadergen_cli (that’s the CLI binary).
Tip. The proc-macro attributes are type-checked at compile time. If you write
#[cheadergen::config(field_namse(x, y))](note the typo),cargo buildwill reject it.cbindgen’s doc-comment annotations would silently do nothing.
4. Regenerate and diff
cheadergen generate --output-dir include --bundle
Pass --bundle to match cbindgen’s “single file per crate” shape. Once you
have output, diff it against your committed cbindgen header:
diff -u old-include/mylib.h include/mylib.h
Expect differences in these places:
#[cfg]-gated items.cheadergensees only the items reachable for the current build target;cbindgentranslates them to#ifdefs. There is no way to make these match — see Limitations.- Array length constants.
[i32; FOO]becomesint32_t x[FOO]incbindgenandint32_t x[10]incheadergen. - Whitespace. Both tools format their output, but the rules differ; small whitespace diffs are normal.
- Doc-comment formatting. Doxygen-style vs plain C-comment choices are
controlled by
documentation_style. - Item ordering may differ between
cheadergenandcbindgen.
If anything else looks unexpectedly different, open an issue with the input and a diff.
5. Decide bundled vs partitioned
--bundle is the closest match to cbindgen’s behaviour. Once the bundled
output is right, consider whether
partitioned mode would suit your project
better:
- Workspaces with multiple FFI-facing crates almost always benefit.
- Single-crate libraries usually don’t.
You can switch at any time; the only difference is the CLI flag (or the
bundle setting in cheadergen.toml).
6. Wire it into your build
If your project ran cbindgen from a build.rs, you’ll need to relocate the
invocation: cheadergen can’t run inside build.rs (it deadlocks against
Cargo’s target-dir lock). Move header generation into a command runner that
sequences cheadergen before cargo build; see
Integrate with Cargo for the recipe.
Common migration pitfalls
- You forgot to add
cheadergento[dependencies]. Without it, the#[cheadergen::config(...)]attribute fails to resolve. Errors surface duringcargo build. - You translated
cbindgen.tomlbut never deleted it. Both tools cheerfully ignore the other’s config. Removecbindgen.toml(or rename it tocbindgen.toml.bakuntil you’re confident) to avoid confusion. - The required nightly isn’t installed. Follow the
installation instructions in the error returned by
cheadergen generateto install the missing toolchain.