include/ #
effects.h is the C ABI of ../rust/cdylib, as a header. It is generated — cbindgen reads the crate's #[no_mangle] pub extern "C" functions and their doc comments and writes this file — and it is checked in.
Why generated #
The prototypes used to be typed by hand in each host (cgo's preamble, Panama's FunctionDescriptors). That is a second copy of the ABI that nothing checks against the first. cbindgen makes the header from the Rust, so a changed signature changes the header, and every host that compiles against it notices. ../ABI.md describes the contract in prose; this file is the part of it a compiler can hold you to.
Why checked in #
Two hosts consume it at their own compile time, not at ours:
| consumer | how |
|---|---|
../go/cgo |
#include "effects.h" in the cgo preamble; cgo generates Go bindings from it |
../java/jextract |
jextract effects.h generates effects_h.java, one static method per export |
If the header lived in target/, every host build would first need cargo and cbindgen on the path and a build step to run. Checked in, go run . and jextract just work, and the header is readable in the tree — it is the shortest complete statement of what the cdylib exports.
The cost is a hand-sync obligation: after changing an export, run
../rust/cdylib/gen-header.sh
and commit the diff. A CI check that the committed header matches a fresh generation is the missing piece (see TODO). Do not edit the header directly; edit the Rust.
Why include/ #
C convention: the directory you pass to -I. Nothing more.