mozilla/cbindgen
A project for generating C bindings from Rust code
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 1w ago
- ✓38+ active contributors
- ✓Distributed ownership (top contributor 31% of recent commits)
Show all 6 evidence items →Show less
- ✓MPL-2.0 licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/mozilla/cbindgen)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/mozilla/cbindgen on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: mozilla/cbindgen
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/mozilla/cbindgen shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 1w ago
- 38+ active contributors
- Distributed ownership (top contributor 31% of recent commits)
- MPL-2.0 licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live mozilla/cbindgen
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/mozilla/cbindgen.
What it runs against: a local clone of mozilla/cbindgen — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in mozilla/cbindgen | Confirms the artifact applies here, not a fork |
| 2 | License is still MPL-2.0 | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 40 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of mozilla/cbindgen. If you don't
# have one yet, run these first:
#
# git clone https://github.com/mozilla/cbindgen.git
# cd cbindgen
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of mozilla/cbindgen and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "mozilla/cbindgen(\\.git)?\\b" \\
&& ok "origin remote is mozilla/cbindgen" \\
|| miss "origin remote is not mozilla/cbindgen (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MPL-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MPL-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is MPL-2.0" \\
|| miss "license drift — was MPL-2.0 at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "src/bindgen/mod.rs" \\
&& ok "src/bindgen/mod.rs" \\
|| miss "missing critical file: src/bindgen/mod.rs"
test -f "src/bindgen/ir/mod.rs" \\
&& ok "src/bindgen/ir/mod.rs" \\
|| miss "missing critical file: src/bindgen/ir/mod.rs"
test -f "src/bindgen/parser.rs" \\
&& ok "src/bindgen/parser.rs" \\
|| miss "missing critical file: src/bindgen/parser.rs"
test -f "src/bindgen/bindings.rs" \\
&& ok "src/bindgen/bindings.rs" \\
|| miss "missing critical file: src/bindgen/bindings.rs"
test -f "src/bindgen/config.rs" \\
&& ok "src/bindgen/config.rs" \\
|| miss "missing critical file: src/bindgen/config.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 40 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~10d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/mozilla/cbindgen"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
cbindgen is a code generator that automatically produces C/C++11 header files from Rust libraries with public C APIs, eliminating manual header maintenance and ensuring consistency with Rust's actual type layout and ABI guarantees. It processes Rust source code (via syn parser), builds an intermediate representation (IR), and emits either C or C++ bindings through language-specific backends (clike.rs and cython.rs). Dual-mode library (src/lib.rs) + CLI binary (src/main.rs, requires 'clap' feature). Core IR lives in src/bindgen/ir/ (ty.rs, function.rs, structure.rs, enumeration.rs, etc.); Cargo integration in src/bindgen/cargo/ (cargo.rs, cargo_expand.rs, cargo_metadata.rs); language backends in src/bindgen/language_backend/ (clike.rs for C/C++, cython.rs for Cython); config parsing via src/bindgen/config.rs; final output via bindings.rs.
👥Who it's for
Rust library authors who need to expose C/C++ FFI interfaces to C/C++ consumers, and C/C++ developers consuming Rust libraries. Particularly used by Mozilla (the maintainer) for projects like Servo and Stylo that require safe Rust+C interop without manual header synchronization overhead.
🌱Maturity & risk
Production-ready and actively maintained. Version 0.29.2 with MPL-2.0 license, Rust 1.74+ requirement, comprehensive CI via GitHub Actions (.github/workflows/cbindgen.yml and deploy.yml), and documented via docs.md and internals.md. Appears well-established with stable API surface, though marked as 'adhoc' development (features added as-needed by maintainers).
Standard open source risks apply.
Active areas of work
Cannot determine from provided metadata—no commit history, PR list, or issues snapshot included. Check .github/workflows/cbindgen.yml for recent CI runs and browse CHANGES file for version history.
🚀Get running
git clone https://github.com/mozilla/cbindgen.git
cd cbindgen
cargo build
cargo install --path .
cbindgen --help
Verify installation: cbindgen --version. For library use, add cbindgen = "0.29" to your Cargo.toml and call in build.rs.
Daily commands:
As CLI: cbindgen --config cbindgen.toml --crate my_crate --output output.h [--lang c] (defaults to C++). As library in build.rs: cbindgen::Builder::new().with_crate(".").generate().unwrap().write_to_file("bindings.h"); (see src/lib.rs exports).
🗺️Map of the codebase
src/bindgen/mod.rs— Main entry point that orchestrates the entire C binding generation pipeline from Rust code to C output.src/bindgen/ir/mod.rs— Intermediate representation (IR) module that defines the abstract syntax tree for all Rust constructs that cbindgen processes.src/bindgen/parser.rs— Parses Rust source code using syn crate and converts it into the internal IR representation.src/bindgen/bindings.rs— Generates final C/C++ output from the IR, handling all language-specific code generation rules.src/bindgen/config.rs— Configuration system that defines all customizable options for binding generation loaded from cbindgen.toml files.src/bindgen/language_backend/mod.rs— Abstract backend interface for multiple language targets (C, C++, Cython) with pluggable code generators.
🛠️How to make changes
Add support for a new Rust type construct
- Define a new IR item type in the Item enum (
src/bindgen/ir/item.rs) - Add parsing logic to convert syn AST to your IR type (
src/bindgen/parser.rs) - Implement C code generation for the new type (
src/bindgen/bindings.rs) - Add formatting logic for C output (
src/bindgen/writer.rs) - Create test cases with expected C output in tests/expectations-symbols/ (
tests/expectations-symbols/)
Add a new code generation backend (e.g., Python, Ruby)
- Create a new backend module implementing the LanguageBackend trait (
src/bindgen/language_backend/mod.rs) - Implement all trait methods for your language's syntax rules (
src/bindgen/language_backend/clike.rs) - Register the new backend in the backend dispatcher (
src/bindgen/bindings.rs) - Add configuration option to select target language in config struct (
src/bindgen/config.rs) - Add backend-specific tests and expected outputs (
tests/)
Extend configuration options for code generation
- Add new field to the Config struct with serde derive attributes (
src/bindgen/config.rs) - Update the configuration loading logic to parse the new option from TOML (
src/bindgen/config.rs) - Thread the config value through to the code generation functions (
src/bindgen/bindings.rs) - Use the configuration value in the appropriate code generation backend (
src/bindgen/language_backend/clike.rs) - Document the new option in the user-facing configuration template (
template.toml)
Handle a new special attribute or annotation
- Define the annotation structure and parsing logic (
src/bindgen/ir/annotation.rs) - Parse the annotation from Rust attributes during IR construction (
src/bindgen/parser.rs) - Apply annotation logic during code generation (
src/bindgen/bindings.rs) - Add test cases verifying the annotation is properly applied (
tests/)
🔧Why these technologies
- syn + proc-macro2 — Parse Rust source code while preserving span information for accurate error reporting; de-facto standard in Rust ecosystem
- serde + toml — Declarative configuration loading from cbindgen.toml files with minimal boilerplate
- indexmap — Preserves insertion order for deterministic, readable C output (important for diffs and reproducibility)
- Cargo metadata API — Extracts crate dependency graphs and metadata without reimplementing Cargo's resolution logic
- log crate — Structured logging without hard dependency on specific log implementation; allows integration with any log backend
⚖️Trade-offs already made
-
IR-based architecture with two-pass processing (parse → generate)
- Why: Separates concerns and enables future backends for different languages without reparsing
- Consequence: Higher memory overhead and intermediate IR structures, but more maintainable and extensible than direct AST-to-code generation
-
Monomorphization of generic types at code generation time
- Why: C does not support generics, so all template instances must be expanded into concrete types
- Consequence: Potential code bloat if Rust code heavily uses generics, but matches C ABI semantics
-
Opaque pointer wrappers for private types
- Why: Allows exposing public functions that reference private internal types without violating privacy boundaries
- Consequence: Generates wrapper structs that are not directly usable from C, requiring accessor functions
-
Configuration-driven code generation (cbindgen.toml)
- Why: Users can customize output without modifying Rust code; single source of truth for bindings strategy
- Consequence: Configuration complexity grows with feature count; requires documentation of all options
🚫Non-goals (don't propose these)
- Does not generate Rust FFI wrappers for C code (unidirectional: Rust → C only)
🪤Traps & gotchas
Cargo.lock present in repo root—indicates pinned dependencies; may cause version conflicts if not synced. workspace exclusions in Cargo.toml exclude test crates (tests/rust/*) from workspace; running cargo test from repo root may not test those. Rust 1.74+ required (rust-toolchain.toml enforced); older rustc will fail. IR may be unstable (unstable_ir feature flag)—don't rely on IR types for external tools yet. cargo_expand path (cargo/cargo_expand.rs) invokes cargo expand externally; rustup nightly may be needed for macro expansion tests.
🏗️Architecture
💡Concepts to learn
- Intermediate Representation (IR) — cbindgen's core abstraction layer (src/bindgen/ir/) decouples Rust AST parsing from C/C++ output; understanding Item, Type, and Function IR variants is essential for any backend or codegen modification
- Monomorphization — cbindgen must resolve generic Rust types (e.g., Vec<T>) into concrete C types; src/bindgen/monomorph.rs handles this constraint—critical for FFI since C lacks generics
- Cargo Metadata & Macro Expansion — FFI bindings require knowledge of crate structure and proc-macro outputs; src/bindgen/cargo/cargo_expand.rs and cargo_metadata.rs invoke cargo's introspection to resolve dependencies and expand macros before IR construction
- ABI Compatibility & Type Layout — C FFI correctness depends on matching struct layout, calling conventions, and pointer sizes; cbindgen validates these guarantees in coordination with Rust compiler (hence 'Rust developers worked closely' claim in README)
- Visitor Pattern (AST/IR Traversal) — Code is structured around visiting IR nodes (e.g., walking structs, functions, types); understanding fold/visit traits in syn 2.0 is key to modifying codegen logic
- Declarative Type Resolution — src/bindgen/declarationtyperesolver.rs resolves forward declarations, opaque types, and circular dependencies in C—non-trivial constraint absent from Rust, requires careful ordering
- Language Backend Abstraction — clike.rs and cython.rs share IR but emit different syntax (C vs Cython annotations); trait-based backend design (src/bindgen/language_backend/mod.rs) allows plugging new output formats
🔗Related repos
dtolnay/cxx— Companion FFI approach: cxx uses procedural macros for inline C++ <-> Rust bindings instead of codegen, complementary use-case for tighter couplingrust-lang/rfcs— Tracking RFCs relevant to C ABI stability and FFI guarantees that inform cbindgen's design (e.g., RFC 1066)servo/rust-mozjs— Real-world consumer of cbindgen; demonstrates pattern of Rust wrapping C (SpiderMonkey) with generated bindingsPyO3/pyo3— Similar codegen philosophy for Python-Rust interop; shares syn/proc-macro2 stack and type-marshaling patternsgoogle/autocxx— Alternative C++ interop (hand-written Rust over C++ headers); more manual but supports two-way bindings unlike cbindgen's one-way generation
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for src/bindgen/language_backend/cython.rs
The Cython language backend exists but lacks dedicated test cases. Unlike the C-like backend which is heavily tested through integration tests, Cython-specific code generation (type mappings, function declarations, etc.) has no isolated unit tests. This is high-value because Cython is a distinct target language with different output requirements, and dedicated tests would catch regressions early.
- [ ] Create tests/cython_backend.rs with integration tests for Cython-specific features
- [ ] Add unit tests in src/bindgen/language_backend/cython.rs for individual methods
- [ ] Test Cython type conversions, function declarations, and struct handling against expected .pyx output
- [ ] Add test cases to the depfile test suite for Cython output validation
Refactor src/bindgen/ir/ty.rs - split Type enum handling into separate modules
The Type enum in ty.rs likely contains extensive match statements and conversion logic for handling Rust types. This file would benefit from modular organization (separate modules for primitives, templates, function pointers, etc.). Refactoring would improve maintainability, testability, and make it easier for contributors to understand type handling without navigating a massive file.
- [ ] Analyze src/bindgen/ir/ty.rs to identify logical groupings (primitives, generics, function pointers, etc.)
- [ ] Create src/bindgen/ir/ty/ subdirectory with modules: primitive.rs, generic.rs, function.rs
- [ ] Move relevant code and implementations into appropriate modules
- [ ] Update imports in src/bindgen/ir/mod.rs and dependent files
- [ ] Ensure all existing tests pass and add new module-level documentation
Add integration tests for config file parsing (src/bindgen/config.rs) with edge cases
The config.rs file handles TOML configuration parsing for cbindgen behavior (language selection, code generation options, etc.). Current test coverage appears minimal. Adding comprehensive integration tests for valid/invalid configs, deprecated fields, and feature interactions would catch configuration bugs early and serve as usage documentation.
- [ ] Create tests/config_parsing.rs with test fixtures for various cbindgen.toml configurations
- [ ] Add tests for: missing required fields, invalid enum values, deprecated config options, feature flag combinations
- [ ] Test config parsing from template.toml and various real-world scenarios
- [ ] Add tests for config merging behavior when using builder API (src/bindgen/builder.rs)
- [ ] Document expected config values and validation rules in tests/config_parsing.rs comments
🌿Good first issues
- Add regression tests for src/bindgen/bitflags.rs—no direct test file visible; create tests/bitflags_test.rs covering BitFlags enum C codegen (repr handling, visibility scoping)
- Enhance documentation in src/bindgen/declarationtyperesolver.rs with examples of how generic type resolution works for monomorphic C output (currently sparse comments relative to complexity)
- Add support for detecting and warning on
unsafe extern "C"function mismatches in src/bindgen/ir/function.rs (ABI safety audit feature)
⭐Top contributors
Click to expand
Top contributors
- @emilio — 31 commits
- @scovich — 11 commits
- @youknowone — 6 commits
- [@Daniil Klimov](https://github.com/Daniil Klimov) — 6 commits
- @NickeZ — 3 commits
📝Recent commits
Click to expand
Recent commits
b68b027— Allowpubaccess toReprTypefields (jakelishman)d458634— ci: Add a meta job to block the merge queue on it. (emilio)77d17a0— Check for CMSE ABI's as well (defermelowie)3620e88— Fix doc attribute parsing to properly handle block comments (sd-collins)ac824ec— Expose the line_endings config option to use with the builder (alloncm)11320ac— fix env in workflow file (fkiriakos07)712e396— use env to pass output parameters (fkiriakos07)76f41c0— Explicitly request serde's std features to avoid issues with newer toml versions. (emilio)eef1776— Account for master -> main rename. (emilio)8c39b09— Update changelog and bump version. (emilio)
🔒Security observations
cbindgen is a code generation tool with a relatively secure architecture. The primary dependencies (syn, serde, toml) are well-established Rust libraries. No hardcoded secrets, SQL injection risks, XSS vulnerabilities, or infrastructure misconfigurations were identified. Main concerns are moderate: (1) ensuring robust input validation for configuration files and generated output paths to prevent injection into C code, (2) monitoring syn for security updates given its parsing complexity, and (3) validating deserialization of untrusted TOML/JSON to prevent DoS. The project follows good practices with feature flags and minimal optional dependencies. The codebase appears well-maintained by Mozilla with active security oversight likely. No critical or high-severity vulnerabilities detected.
- Medium · Syn dependency with broad feature set —
Cargo.toml - syn dependency. The syn dependency (version 2.0.85) is imported with extensive features including 'full' and 'fold', which enables parsing and manipulation of all Rust syntax. While necessary for cbindgen's functionality, this increases the attack surface if vulnerabilities are discovered in syn's parsing logic. Fix: Monitor syn releases for security updates and maintain up-to-date dependencies. Consider evaluating if all features are truly necessary, though this is likely unavoidable for a code generation tool. - Low · Tempfile dependency without explicit security context —
Cargo.toml - tempfile dependency. The tempfile crate (version 3) is used for temporary file operations. While tempfile is generally secure, the codebase should ensure temporary files are created in secure directories and properly cleaned up to prevent information disclosure. Fix: Review code that uses tempfile to ensure: (1) temporary files are created with restrictive permissions, (2) sensitive data isn't exposed in temporary files, and (3) cleanup occurs even on error paths. - Low · Serialization library exposure —
Cargo.toml - serde, serde_json, toml dependencies. The project uses serde with JSON parsing (serde_json) and TOML parsing (toml). While these are standard libraries, deserializing untrusted input could lead to DoS attacks through deeply nested structures or malformed input. Fix: When parsing TOML config files or JSON input, implement size limits and depth limits. Validate input files before deserialization to prevent DoS attacks from maliciously crafted configuration files. - Low · No explicit input validation framework —
src/bindgen/config.rs, src/bindgen/parser.rs. The codebase parses Rust code through syn and generates C bindings. While syn handles Rust syntax validation, there's no visible comprehensive input validation strategy for configuration files or command-line arguments beyond what clap provides. Fix: Implement strict validation for all external inputs including: (1) configuration file paths, (2) output file paths (to prevent directory traversal), and (3) crate metadata to prevent injection attacks in generated C code. - Low · Potential path traversal in output generation —
src/bindgen/bindings.rs, src/bindgen/writer.rs. The project generates C header files based on configuration. Without explicit path sanitization, malicious configuration files could potentially specify output paths with directory traversal sequences (../). Fix: Implement strict path validation for output file paths. Use canonicalization and whitelist allowed output directories. Reject paths containing '..' or other traversal patterns.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.