Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Quickstart

This walkthrough takes you from an empty directory to a generated C header in about five minutes. It assumes you have already installed cheadergen.

1. Create a tiny Rust library

cargo new --lib distance
cd distance

Edit Cargo.toml so the crate compiles as a C-compatible static library:

[package]
name = "distance"
version = "0.1.0"
edition = "2024"

[lib]
# 👇 Change the crate type from the default `rlib` to `staticlib`
crate-type = ["staticlib"]

Replace src/lib.rs:

#![allow(unused)]
fn main() {
#[repr(C)]
pub struct Point {
    pub x: f64,
    pub y: f64,
}

#[unsafe(no_mangle)]
pub extern "C" fn distance(a: Point, b: Point) -> f64 {
    ((a.x - b.x).powi(2) + (a.y - b.y).powi(2)).sqrt()
}
}

Why these annotations? #[unsafe(no_mangle)] keeps the symbol name intact so a C linker can resolve it. extern "C" makes the function use the C calling convention so a C caller passes arguments and reads the return value the way Rust expects. Together they make distance callable from C. Without them, cheadergen has no signal that you intend the function to be reachable from C and skips it.

Same reasoning applies to Point: #[repr(C)] guarantees that the struct’s layout matches a C struct. Without it, cheadergen would refuse to emit a C definition for it.

2. Generate the header

cheadergen generate --output-dir include

You should see something like:

Generating headers for 1 crate(s) using toolchain `nightly-...`
Successfully loaded rustdoc JSON for `distance`: root module `distance`
`distance`: 1 function(s), 0 static(s), 0 constant(s)
Wrote target header: include/distance.h

3. Read the output

In include/distance.h you should see something along the lines of:

/* WARNING: this file was auto-generated by 
 * cheadergen from `distance`. 
 * Do not edit it manually. */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct {
    double x;
    double y;
} Point;

double distance(Point a, Point b);

That’s the whole loop. To understand how the generated C header is structured (and how to customise it), read Anatomy of a generated header.

Where to go next