declare-c generates the wrapper, the typedefs and the prototype from one declaration, so they cannot disagree with each other. What nothing checked was whether the declaration matched the library — BUILT.md records that as trusted rather than guaranteed, because no header was ever read. This reads one. clang is asked for a JSON AST dump of the header and shelled out to, not linked: -Xclang -ast-dump=json is the same binary on PATH that every build already runs, which is plan.org's "Why LLVM IR as text" applied a second time. Zig's old @cImport linked clang as a library and that is precisely the dependency plan.org rejected. cjson.ml is enough JSON to read the dump and no more, so this adds no opam package to parse it. What comes out of the header is signatures and nothing else — not structs, not enums, not macros. The bound on how much is imported is the package's own defstructs: a function whose signature mentions a struct the package has not described is refused with that reason, so vendor/raylib describing thirteen structs is what makes the import thirteen structs wide. Keeping the layouts hand-written is also what makes checking them against the header's records worth doing — a _Static_assert was rejected in BUILT.md as circular, and this is not, because the two sides have different authors. Refusals are demotions, taken from Zig's translator: it never drops a declaration it cannot handle, it binds the name to a @compileError carrying the reason so the failure lands at the use site. Load.refuse_hidden is already that mechanism. So a returned char * does not kill the header — it makes one name unavailable, with the reason attached. flan import-c prints what it would produce, what it refused, how the package's defstructs compare with the header's records, and how the hand-written declare-c lines compare with the header's signatures. Against raylib 5.5, the version whose .so vendor/raylib/link names: all 16 defstructs and all 172 hand-written declare-c agree exactly. Against the 5.1-dev header installed in /usr/local it reports ten differences, nine functions that version does not have and one that gained a parameter — so the check has teeth and the clean run is not a vacuous one.
Description
Languages
OCaml
67.2%
Emacs Lisp
15.2%
C
10.4%
HTML
2.9%
Standard ML
2.8%
Other
1.5%