The bindings are committed, and regeneration is what checks them

generated.flan carries the 253 declarations the importer reads out of raylib's
header, so a build needs libraylib linkable and no header at all. The opt-in
no longer decides how many bindings a package has — every build now gets all
425, they are greppable, and they diff when raylib moves.

What that gives up is the build-time check, so `flan generate-c` is the only
thing that writes the file and it compares first: every defstruct against the
header's record, every hand-written declare-c against the header's signature,
and it writes nothing when they disagree. Against the 5.1-dev header on this
machine that is ten real differences and no write.

The 172 hand-written lines stay, and not out of caution. Everything the
generator emits agrees with the header by construction, so diffing generated
output against its own source is a tautology; the hand-written lines were
transcribed by a person, so they are the only thing here a header can
contradict. All ten of those differences came from them.

`bindings` beside `headers` is what survives regeneration, because a hand-edit
to a committed generated file does not. Two directives: `exclude` drops
raylib's three allocator entry points, and `name` gives the 19 generated
predicates the `?` spelling the hand-written ones already use.
This commit is contained in:
Joseph Ferano 2026-09-13 08:07:40 +07:00
parent 82cf429906
commit 85ef56f657
7 changed files with 698 additions and 24 deletions

View File

@ -208,6 +208,10 @@ let () =
let imported, dump, env =
Flan.Cimport.header ~loc:(Flan.Loc.make header 0 0) ~header ~flags
~known_structs:(List.map fst structs) ~known_enums ~taken ~bound_syms
~config:
(match pkg with
| f :: _ -> Flan.Load.binding_config (Filename.dirname f)
| [] -> Flan.Cimport.no_config)
in
List.iter
(fun d -> print_endline (Flan.Cimport.decl_source d))
@ -254,6 +258,77 @@ let () =
x.Flan.Cimport.dflan x.Flan.Cimport.dsym x.Flan.Cimport.dwhy)
ds)
(* Regeneration. [import-c] prints what it would produce; this writes it, and
the difference between the two is that this one cannot skip the check.
It reads the header out of the package's own `headers`, not off the
command line, because the version that may be read is a property of the
package `headers` is where it says which one, and `link` is where it
says which library that has to match. And it reads every .flan in the
directory *except* the file it writes, so the hand-written declarations
still win and the generated ones are not mistaken for them on the next
run.
Non-zero and nothing written when the package and the header disagree.
That is the whole point: the committed file is the one thing here with no
second opinion, so the moment of writing it is the only moment left at
which the library can contradict it. *)
| _ :: "generate-c" :: dir :: _ ->
with_errors dir (fun () ->
let loc = Flan.Loc.make dir 0 0 in
let out = Filename.concat dir "generated.flan" in
let ds =
List.concat_map
(fun f -> Flan.Parse.program (Flan.Reader.read_file f))
(List.filter
(fun f -> not (String.equal f out))
(Flan.Load.entries dir ".flan"))
in
let config = Flan.Load.binding_config dir in
match Flan.Load.header_specs ~loc dir with
| [] ->
Printf.eprintf
"flan generate-c: %s/headers names no header that is there. \
Regeneration reads the library's own header, at the version \
%s/link names export it and run this again.\n" dir dir;
exit 2
| _ :: _ :: _ ->
Printf.eprintf
"flan generate-c: %s/headers names more than one header, and one \
generated file cannot come from several the declarations would \
depend on which was read last.\n" dir;
exit 2
| [ (h, flags) ] ->
let r = Flan.Cimport.regenerate ~loc ~header:h ~flags ~ds ~config ~out in
List.iter
(fun (n, why) -> Printf.printf ";; refused %s: %s\n" n why)
r.Flan.Cimport.ghidden;
List.iter
(fun (n, why) -> Printf.eprintf "DISAGREES %s: %s\n" n why)
r.Flan.Cimport.gstructs;
List.iter
(fun (x : Flan.Cimport.sig_diff) ->
Printf.eprintf "DIFFERS %s (%s): %s\n"
x.Flan.Cimport.dflan x.Flan.Cimport.dsym x.Flan.Cimport.dwhy)
r.Flan.Cimport.gsigs;
if r.Flan.Cimport.gwrote then
Printf.printf
"wrote %s: %d declarations, %d refused, of %d functions in %s.\n\
Every defstruct and every hand-written declare-c agrees with it.\n"
out r.Flan.Cimport.gdecls
(List.length r.Flan.Cimport.ghidden) r.Flan.Cimport.gfns h
else begin
Printf.eprintf
"flan generate-c: %s disagrees with %s — %d struct layouts and %d \
hand-written signatures. Nothing was written: a generated file \
made against a header the library does not match is the silent \
failure this check exists to prevent.\n"
dir h
(List.length r.Flan.Cimport.gstructs)
(List.length r.Flan.Cimport.gsigs);
exit 1
end)
(* The IR is target-independent — [Emit] writes no triple and no datalayout,
which is what lets one .ll serve both targets so there is nothing for a
target to change here. Refused rather than accepted and ignored: silently
@ -398,6 +473,7 @@ let () =
prerr_endline
"usage: flan (read|parse|check|emit|shim) <file.flan>...\n\
\ flan import-c <header.h> [package.flan...] [clang flags...]\n\
\ flan generate-c <package-dir>\n\
\ flan build <file.flan> [-o out] [--no-bounds-checks] [--dev] \
[--debug] [--sanitize] [--target=wasm32-wasi|web]\n\
\ flan run <file.flan> [args...]\n\

View File

@ -502,6 +502,102 @@ type imported = {
hidden : (string * string) list;
}
(* ── The config beside the header ──────────────────────────────────── *)
(* Why a config file exists at all, when the importer decides everything else
from the header.
Because the generated declarations are *committed*. A generated file that is
read at build time can be hand-corrected and the correction survives, since
nothing rewrites it. A generated file that is checked in is rewritten by the
next regeneration, so a hand-edit to it is destroyed without anybody being
told which is the worst shape an edit can have. The edits therefore have
to live somewhere regeneration *reads* rather than somewhere it writes, and
this is that place.
Two directives, which are the two things the header cannot decide:
- [exclude], a C symbol or a pattern of them, for what should not be
generated at all.
- [name], a C symbol and the Flan name it is to take, for where the kebab
rule gives something ugly.
A postprocessing transform pass over the generated file was the alternative
and was rejected: a second program to understand, run over text the
generator had already committed to. Both directives here are applied
*while* the declarations are made, so the file on disk is already what the
config says and nothing reads it twice. *)
type config = {
excludes : string list;
(* C symbol to Flan name. Keyed on the symbol and not on the kebab result,
because the symbol is the only spelling that is stable the whole point
of an override is that the kebab result is not what is wanted. *)
renames : (string * string) list;
}
let no_config = { excludes = []; renames = [] }
(* [*] stands for any run of characters and nothing else does anything. Enough
for [rl*] or [*Callback], and small enough to read at a glance; a package
that needs more than this wants a hand-written declare-c, which it has. *)
let matches (pat : string) (s : string) =
let np = String.length pat and ns = String.length s in
let rec go i j =
if i = np then j = ns
else if pat.[i] = '*' then
let rec from k = (k <= ns && go (i + 1) k) || (k < ns && from (k + 1)) in
from j
else j < ns && Char.equal pat.[i] s.[j] && go (i + 1) (j + 1)
in
go 0 0
let excluded cfg sym = List.exists (fun p -> matches p sym) cfg.excludes
(* The one place the kebab rule is consulted, so an override is not a special
case anywhere below: collisions are computed on the name a function will
actually take, which means renaming one of two colliding symbols resolves
the collision rather than leaving both refused. *)
let flan_name cfg sym =
match List.assoc_opt sym cfg.renames with Some n -> n | None -> kebab sym
(* The file, in the shape of [headers] and [link] beside it: one directive per
line, [#] comments, blank lines ignored. A line that is neither directive is
an error rather than a line quietly skipped the house rule against
swallowing things applies to a config as much as to a flag, and a typo in a
name override would otherwise show up as a binding under the wrong name. *)
let read_config path : config =
if not (Sys.file_exists path) then no_config
else begin
let ch = open_in path in
let excludes = ref [] and renames = ref [] in
let rec go n =
match input_line ch with
| line ->
let t = String.trim line in
if t <> "" && t.[0] <> '#' then begin
let ws =
String.split_on_char ' ' t
|> List.concat_map (String.split_on_char '\t')
|> List.filter (fun w -> w <> "")
in
match ws with
| [ "exclude"; p ] -> excludes := p :: !excludes
| [ "name"; sym; flan ] -> renames := (sym, flan) :: !renames
| _ ->
close_in ch;
fail (Loc.make path n 0)
"a line here is `exclude <C symbol or pattern>` or `name <C \
symbol> <flan-name>`, and this is neither: %s" t
end;
go (n + 1)
| exception End_of_file -> ()
in
go 1;
close_in ch;
{ excludes = List.rev !excludes; renames = List.rev !renames }
end
(* [taken] is every name the package already declares, which is what makes the
sidecar additive: a hand-written [(declare-c get-gamepad-name ...)] wins
over the header, and a C symbol already bound by hand is not bound twice
@ -510,7 +606,7 @@ type imported = {
[-c] as well as the name itself, because [Shim] generates [foo-c] beside a
[foo] whose signature has a struct in it, and a collision there is refused
for the whole program rather than for the one binding. *)
let of_dump ~env ~taken ~bound_syms (d : dump) : imported =
let of_dump ~env ~taken ~bound_syms ~config (d : dump) : imported =
let decls = ref [] and hidden = ref [] in
(* Collisions are found before anything is emitted, and they take *every*
name in the colliding group down with them.
@ -530,16 +626,32 @@ let of_dump ~env ~taken ~bound_syms (d : dump) : imported =
let candidates =
List.filter (fun f -> not (List.mem f.csym bound_syms)) d.fns
in
(* Excluded before anything else looks at them, so an excluded symbol is not
in a collision group either which is one of the things exclusion is for.
It still says why, under the name it would have taken: "there is no such
binding" and "the package decided against this binding" are different
answers and a reader deserves the second one. *)
let dropped, candidates =
List.partition (fun f -> excluded config f.csym) candidates
in
List.iter
(fun f ->
hidden :=
(flan_name config f.csym,
Printf.sprintf
"%s is excluded by the package's binding config, so no declaration is generated for it" f.csym)
:: !hidden)
dropped;
let groups = Hashtbl.create 512 in
List.iter
(fun f ->
let k = kebab f.csym in
let k = flan_name config f.csym in
Hashtbl.replace groups k (f.csym :: Option.value ~default:[]
(Hashtbl.find_opt groups k)))
candidates;
List.iter
(fun f ->
let flan = kebab f.csym in
let flan = flan_name config f.csym in
let skip why = hidden := (flan, why) :: !hidden in
match List.rev (Hashtbl.find groups flan) with
| _ :: _ :: _ as all ->
@ -547,7 +659,8 @@ let of_dump ~env ~taken ~bound_syms (d : dump) : imported =
(Printf.sprintf
"%s all kebab to %s, and which one got the name would depend on \
the order the header declares them in so none of them takes \
it. Bind the one you want with a hand-written declare-c"
it. Give the one you want a `name` in the binding config, or \
bind it with a hand-written declare-c"
(String.concat ", " all) flan)
| _ ->
if Hashtbl.mem taken flan || Hashtbl.mem taken (flan ^ "-c") then
@ -811,7 +924,8 @@ let dump_of ~loc ~header ~flags =
let env_of ~known_structs ~known_enums d = { known_structs; known_enums; d }
let header ~loc ~header:h ~flags ~known_structs ~known_enums ~taken ~bound_syms =
let header ~loc ~header:h ~flags ~known_structs ~known_enums ~taken ~bound_syms
~config =
let k =
(* Sorted, because neither the taken table nor the declaration order is a
fact about the package two loads of the same file that enumerate them
@ -822,14 +936,19 @@ let header ~loc ~header:h ~flags ~known_structs ~known_enums ~taken ~bound_syms
:: "\001" :: sorted known_structs
@ ("\001" :: sorted known_enums)
@ ("\001" :: sorted (Hashtbl.fold (fun n () acc -> n :: acc) taken []))
@ ("\001" :: sorted bound_syms))
@ ("\001" :: sorted bound_syms)
(* The config is part of the question: two loads that disagree about
what is excluded or renamed are different questions, and serving one
the other's answer is the bug this key exists to prevent. *)
@ ("\001" :: sorted config.excludes)
@ ("\001" :: sorted (List.map (fun (a, b) -> a ^ "=" ^ b) config.renames)))
in
match Hashtbl.find_opt imports k with
| Some r -> r
| None ->
let d = dump_of ~loc ~header:h ~flags in
let env = env_of ~known_structs ~known_enums d in
let r = (of_dump ~env ~taken ~bound_syms d, d, env) in
let r = (of_dump ~env ~taken ~bound_syms ~config d, d, env) in
Hashtbl.replace imports k r;
r
@ -955,3 +1074,116 @@ let diff_bound ~env ~(bound : (Ast.fn * string) list) (d : dump) =
(match want with None -> "nothing" | Some t -> ty_source t)
c.cret)))
bound
(* ── Regenerating the committed declarations ───────────────────────── *)
(* Generate once, commit the result, regenerate when the library moves.
What that buys is in DISCUSS.md item 6 and it is not caching the dump is
already cached on disk and in memory, so a build that reads the header pays
for it once either way. It is that no header is needed by *anybody*: the
declarations are in the repository, so they are greppable, they diff when
raylib moves, and a build needs libraylib linkable and nothing else. The
opt-in that used to decide whether a package had 172 bindings or 428 stops
deciding anything.
What it costs is the check. A header read at build time compared every
hand-written declaration against the library on every build; a committed
file compares nothing, because a file on disk has no second opinion. That
check is not decoration it verified all 172 hand-written declarations and
all 16 struct layouts against raylib 5.5 and found them exactly right, and
against a 5.1-dev header on the same machine it found ten real differences.
So regeneration runs it, and the check *gates the write*. There is no way to
ask for new declarations without comparing the package against the header
they come from, because the one function that writes the file is this one
and it refuses when the two disagree. A regeneration that quietly rewrote
the bindings against a header the library does not match would produce
exactly the failure BUILT.md warns about a permuted struct read as five
plausible numbers rather than as a link error and it would produce it in a
committed file that looks reviewed.
The hand-written declarations are what make the signature half of that check
mean anything, which is why they stay. Everything the generator emits agrees
with the header by construction, so diffing generated output against the
header it came from is a tautology; the hand-written lines were transcribed
from raylib's documentation by a person, so they are an independent second
opinion and the only thing here that the header can actually contradict. *)
type regen = {
gwrote : bool;
gdecls : int;
gfns : int;
ghidden : (string * string) list;
gstructs : (string * string) list;
gsigs : sig_diff list;
}
let banner h =
Printf.sprintf
";;;; Generated from %s by `flan generate-c`. Do not edit this file.\n\
;;;;\n\
;;;; Every line here was read out of the C header named by `headers`, and\n\
;;;; the next regeneration overwrites the file so a correction made here\n\
;;;; is destroyed without anybody being told. Corrections go in `bindings`\n\
;;;; beside it, which is read *while* these lines are made: `exclude` drops\n\
;;;; a function, `name` gives one a Flan name the kebab rule would not.\n\
;;;; Anything neither directive can express is a hand-written declare-c in\n\
;;;; the package's own .flan, which wins over this file and is left alone.\n\
;;;;\n\
;;;; Regenerating compares the package against the header first and\n\
;;;; refuses to write when they disagree, so this file and the\n\
;;;; hand-written declarations beside it agreed with %s when it was made.\n\n"
(Filename.basename h) (Filename.basename h)
(* [ds] is the package's *hand-written* declarations: every .flan in the
directory except the one being written. Reading the output back in would
make regeneration idempotent in the worst way every symbol would already
be bound, so the second run would generate nothing and cheerfully write an
empty file. *)
let regenerate ~loc ~header:h ~flags ~(ds : Ast.decl list) ~config ~out =
let taken = Hashtbl.create 64 in
List.iter
(fun d ->
match Ast.declared_name d with
| Some n -> Hashtbl.replace taken n ()
| None -> ())
ds;
let pick f = List.filter_map f ds in
let structs =
pick (fun (d : Ast.decl) ->
match d.Ast.d with Ast.Defstruct (n, fs) -> Some (n, fs) | _ -> None)
and known_enums =
pick (fun (d : Ast.decl) ->
match d.Ast.d with Ast.Defenum (n, _) -> Some n | _ -> None)
and bound_syms =
pick (fun (d : Ast.decl) ->
match d.Ast.d with
| Ast.Declare (_, s) | Ast.DeclareC (_, s) -> Some s
| _ -> None)
and bound =
pick (fun (d : Ast.decl) ->
match d.Ast.d with Ast.DeclareC (fn, s) -> Some (fn, s) | _ -> None)
in
let imported, dump, env =
header ~loc ~header:h ~flags ~known_structs:(List.map fst structs)
~known_enums ~taken ~bound_syms ~config
in
let gstructs = check_structs ~env ~structs dump in
let gsigs = diff_bound ~env ~bound dump in
let gwrote = gstructs = [] && gsigs = [] in
if gwrote then begin
let b = Buffer.create 65536 in
Buffer.add_string b (banner h);
List.iter
(fun d ->
Buffer.add_string b (decl_source d);
Buffer.add_char b '\n')
imported.decls;
let ch = open_out out in
output_string ch (Buffer.contents b);
close_out ch
end;
{ gwrote; gdecls = List.length imported.decls;
gfns = List.length dump.fns; ghidden = imported.hidden; gstructs; gsigs }

View File

@ -587,6 +587,16 @@ let header_specs ~loc dir =
else Some (h, flags)))
(read_lines path)
(* The binding config, beside [headers] and read for the same package: which
functions not to generate, and what to call the ones whose kebab name is
not wanted. Absent is the ordinary case and means neither.
It is read here rather than by the importer because it is a property of the
*package*, like [headers] and [link] the importer is given a header and a
config and has no directory to look in. See [Cimport.read_config] for why a
config exists at all once the generated declarations are committed. *)
let binding_config dir = Cimport.read_config (Filename.concat dir "bindings")
let real dir = try Unix.realpath dir with Unix.Unix_error _ -> dir
(* One package, and whatever it imports.
@ -758,7 +768,7 @@ let rec import ~seen ~open_ ~loc alias dir =
in
let r, dump, env =
Cimport.header ~loc ~header:h ~flags ~known_structs ~known_enums
~taken ~bound_syms
~taken ~bound_syms ~config:(binding_config dir)
in
(* The point of reading the header, and the reason it is not
enough to generate declarations out of it.

View File

@ -1318,7 +1318,7 @@ let () =
in
let i, d, e =
Cimport.header ~loc:Loc.unknown ~header:"headers/sample.h" ~flags:[]
~known_structs ~known_enums ~taken ~bound_syms:[]
~known_structs ~known_enums ~taken ~bound_syms:[] ~config:Cimport.no_config
in
(i, d, e, ds)
in

69
vendor/raylib/bindings vendored Normal file
View File

@ -0,0 +1,69 @@
# How the generated bindings in generated.flan are shaped. One directive per
# line, `#` comments, blank lines ignored. A line that is neither directive is
# an error rather than a line quietly skipped.
#
# exclude <C symbol or pattern> do not generate a binding for this
# name <C symbol> <flan-name> call it this instead of the kebab rule's
#
# `*` in an exclude pattern stands for any run of characters, and nothing else
# does anything.
#
# Why this file exists. generated.flan is committed, so it is not a build
# artefact anybody can hand-correct: the next `flan generate-c vendor/raylib`
# overwrites it, and an edit made there is destroyed without anybody being
# told. This file is read *while* those lines are made, so it is the edit that
# survives regeneration. A postprocessing pass over the generated text was the
# alternative and was rejected — a second program to understand, applied to
# output the generator had already committed to.
#
# What does NOT belong here. Anything neither directive can express is a
# hand-written `declare-c` in raylib.flan, which wins over the generated file
# and is left alone by the importer. That is the escape hatch for a signature
# the importer gets wrong and for a Flan face the header cannot describe —
# load-font-ex-raw and load-image-from-memory-raw are both that, each wrapped
# by a Flan defn of the same name without the suffix.
# ── raylib's allocator ──────────────────────────────────────────────
#
# raylib exports malloc, realloc and free under its own names. Flan's memory
# model is explicit — plan.org's rule is that an operation never falls back to
# a hidden allocator — so binding these would put a second, untracked heap
# behind three innocuous-looking Flan names, and a pointer from one freed by
# the other is the kind of bug that does not point at itself. Nothing in the
# package needs them: raylib's own Load*/Unload* pairs own everything raylib
# allocates.
exclude MemAlloc
exclude MemRealloc
exclude MemFree
# ── Predicates read as questions ────────────────────────────────────
#
# The kebab rule gives `is-window-ready`, which is C's phrasing wearing Flan's
# punctuation. The hand-written bindings in raylib.flan settled the convention
# years of Lisp settled first — a predicate ends in `?` and does not begin with
# `is` — and these are the generated half of the same set, so they follow it.
# key-pressed? and window-ready? being spelled differently would be the split
# this whole change exists to remove.
#
# The C symbol is kept verbatim in the declaration either way, so nothing here
# is lost: the name is the Flan face and `IsWindowReady` is still what is
# called and still what the check compares against.
name IsWindowReady window-ready?
name IsWindowFullscreen window-fullscreen?
name IsWindowHidden window-hidden?
name IsWindowMinimized window-minimized?
name IsWindowMaximized window-maximized?
name IsWindowFocused window-focused?
name IsWindowResized window-resized?
name IsWindowState window-state?
name IsCursorOnScreen cursor-on-screen?
name IsKeyUp key-up?
name IsKeyPressedRepeat key-pressed-repeat?
name IsMouseButtonUp mouse-button-up?
name IsFileDropped file-dropped?
name IsFileExtension file-extension?
name IsFileNameValid file-name-valid?
name IsPathFile path-file?
name IsAudioStreamValid audio-stream-valid?
name IsAudioStreamPlaying audio-stream-playing?
name IsAudioStreamProcessed audio-stream-processed?

267
vendor/raylib/generated.flan vendored Normal file
View File

@ -0,0 +1,267 @@
;;;; Generated from raylib.h by `flan generate-c`. Do not edit this file.
;;;;
;;;; Every line here was read out of the C header named by `headers`, and
;;;; the next regeneration overwrites the file — so a correction made here
;;;; is destroyed without anybody being told. Corrections go in `bindings`
;;;; beside it, which is read *while* these lines are made: `exclude` drops
;;;; a function, `name` gives one a Flan name the kebab rule would not.
;;;; Anything neither directive can express is a hand-written declare-c in
;;;; the package's own .flan, which wins over this file and is left alone.
;;;;
;;;; Regenerating compares the package against the header first and
;;;; refuses to write when they disagree, so this file and the
;;;; hand-written declarations beside it agreed with raylib.h when it was made.
(declare-c window-ready? [] bool "IsWindowReady")
(declare-c window-fullscreen? [] bool "IsWindowFullscreen")
(declare-c window-hidden? [] bool "IsWindowHidden")
(declare-c window-minimized? [] bool "IsWindowMinimized")
(declare-c window-maximized? [] bool "IsWindowMaximized")
(declare-c window-focused? [] bool "IsWindowFocused")
(declare-c window-resized? [] bool "IsWindowResized")
(declare-c window-state? [flag u32] bool "IsWindowState")
(declare-c set-window-state [flags u32] "SetWindowState")
(declare-c clear-window-state [flags u32] "ClearWindowState")
(declare-c toggle-fullscreen [] "ToggleFullscreen")
(declare-c toggle-borderless-windowed [] "ToggleBorderlessWindowed")
(declare-c maximize-window [] "MaximizeWindow")
(declare-c minimize-window [] "MinimizeWindow")
(declare-c restore-window [] "RestoreWindow")
(declare-c set-window-icon [image Image] "SetWindowIcon")
(declare-c set-window-icons [images (Ptr Image) count i32] "SetWindowIcons")
(declare-c set-window-title [title string] "SetWindowTitle")
(declare-c set-window-position [x i32 y i32] "SetWindowPosition")
(declare-c set-window-monitor [monitor i32] "SetWindowMonitor")
(declare-c set-window-min-size [width i32 height i32] "SetWindowMinSize")
(declare-c set-window-max-size [width i32 height i32] "SetWindowMaxSize")
(declare-c set-window-size [width i32 height i32] "SetWindowSize")
(declare-c set-window-opacity [opacity f32] "SetWindowOpacity")
(declare-c set-window-focused [] "SetWindowFocused")
(declare-c get-window-handle [] (Ptr u8) "GetWindowHandle")
(declare-c get-render-width [] i32 "GetRenderWidth")
(declare-c get-render-height [] i32 "GetRenderHeight")
(declare-c get-monitor-count [] i32 "GetMonitorCount")
(declare-c get-current-monitor [] i32 "GetCurrentMonitor")
(declare-c get-monitor-position [monitor i32] Vector2 "GetMonitorPosition")
(declare-c get-monitor-width [monitor i32] i32 "GetMonitorWidth")
(declare-c get-monitor-height [monitor i32] i32 "GetMonitorHeight")
(declare-c get-monitor-physical-width [monitor i32] i32 "GetMonitorPhysicalWidth")
(declare-c get-monitor-physical-height [monitor i32] i32 "GetMonitorPhysicalHeight")
(declare-c get-monitor-refresh-rate [monitor i32] i32 "GetMonitorRefreshRate")
(declare-c get-window-position [] Vector2 "GetWindowPosition")
(declare-c get-window-scale-dpi [] Vector2 "GetWindowScaleDPI")
(declare-c set-clipboard-text [text string] "SetClipboardText")
(declare-c get-clipboard-image [] Image "GetClipboardImage")
(declare-c enable-event-waiting [] "EnableEventWaiting")
(declare-c disable-event-waiting [] "DisableEventWaiting")
(declare-c enable-cursor [] "EnableCursor")
(declare-c disable-cursor [] "DisableCursor")
(declare-c cursor-on-screen? [] bool "IsCursorOnScreen")
(declare-c end-mode-3d [] "EndMode3D")
(declare-c end-shader-mode [] "EndShaderMode")
(declare-c begin-blend-mode [mode i32] "BeginBlendMode")
(declare-c end-blend-mode [] "EndBlendMode")
(declare-c begin-scissor-mode [x i32 y i32 width i32 height i32] "BeginScissorMode")
(declare-c end-scissor-mode [] "EndScissorMode")
(declare-c end-vr-stereo-mode [] "EndVrStereoMode")
(declare-c swap-screen-buffer [] "SwapScreenBuffer")
(declare-c poll-input-events [] "PollInputEvents")
(declare-c wait-time [seconds f64] "WaitTime")
(declare-c set-random-seed [seed u32] "SetRandomSeed")
(declare-c get-random-value [min i32 max i32] i32 "GetRandomValue")
(declare-c load-random-sequence [count u32 min i32 max i32] (Ptr i32) "LoadRandomSequence")
(declare-c unload-random-sequence [sequence (Ptr i32)] "UnloadRandomSequence")
(declare-c take-screenshot [file-name string] "TakeScreenshot")
(declare-c open-url [url string] "OpenURL")
(declare-c load-file-data [file-name string data-size (Ptr i32)] (Ptr u8) "LoadFileData")
(declare-c unload-file-data [data (Ptr u8)] "UnloadFileData")
(declare-c save-file-data [file-name string data (Ptr u8) data-size i32] bool "SaveFileData")
(declare-c export-data-as-code [data (Ptr u8) data-size i32 file-name string] bool "ExportDataAsCode")
(declare-c file-exists [file-name string] bool "FileExists")
(declare-c directory-exists [dir-path string] bool "DirectoryExists")
(declare-c file-extension? [file-name string ext string] bool "IsFileExtension")
(declare-c get-file-length [file-name string] i32 "GetFileLength")
(declare-c make-directory [dir-path string] i32 "MakeDirectory")
(declare-c change-directory [dir string] bool "ChangeDirectory")
(declare-c path-file? [path string] bool "IsPathFile")
(declare-c file-name-valid? [file-name string] bool "IsFileNameValid")
(declare-c file-dropped? [] bool "IsFileDropped")
(declare-c compress-data [data (Ptr u8) data-size i32 comp-data-size (Ptr i32)] (Ptr u8) "CompressData")
(declare-c decompress-data [comp-data (Ptr u8) comp-data-size i32 data-size (Ptr i32)] (Ptr u8) "DecompressData")
(declare-c decode-data-base-64 [data (Ptr u8) output-size (Ptr i32)] (Ptr u8) "DecodeDataBase64")
(declare-c compute-crc32 [data (Ptr u8) data-size i32] u32 "ComputeCRC32")
(declare-c compute-md5 [data (Ptr u8) data-size i32] (Ptr u32) "ComputeMD5")
(declare-c compute-sha1 [data (Ptr u8) data-size i32] (Ptr u32) "ComputeSHA1")
(declare-c set-automation-event-base-frame [frame i32] "SetAutomationEventBaseFrame")
(declare-c start-automation-event-recording [] "StartAutomationEventRecording")
(declare-c stop-automation-event-recording [] "StopAutomationEventRecording")
(declare-c key-pressed-repeat? [key i32] bool "IsKeyPressedRepeat")
(declare-c key-up? [key i32] bool "IsKeyUp")
(declare-c get-key-pressed [] i32 "GetKeyPressed")
(declare-c get-char-pressed [] i32 "GetCharPressed")
(declare-c set-exit-key [key i32] "SetExitKey")
(declare-c set-gamepad-mappings [mappings string] i32 "SetGamepadMappings")
(declare-c set-gamepad-vibration [gamepad i32 left-motor f32 right-motor f32 duration f32] "SetGamepadVibration")
(declare-c mouse-button-up? [button i32] bool "IsMouseButtonUp")
(declare-c get-mouse-x [] i32 "GetMouseX")
(declare-c get-mouse-y [] i32 "GetMouseY")
(declare-c get-mouse-delta [] Vector2 "GetMouseDelta")
(declare-c set-mouse-position [x i32 y i32] "SetMousePosition")
(declare-c set-mouse-offset [offset-x i32 offset-y i32] "SetMouseOffset")
(declare-c set-mouse-scale [scale-x f32 scale-y f32] "SetMouseScale")
(declare-c get-mouse-wheel-move-v [] Vector2 "GetMouseWheelMoveV")
(declare-c set-mouse-cursor [cursor i32] "SetMouseCursor")
(declare-c draw-line-strip [points (Ptr Vector2) point-count i32 color Color] "DrawLineStrip")
(declare-c draw-line-bezier [start-pos Vector2 end-pos Vector2 thick f32 color Color] "DrawLineBezier")
(declare-c draw-circle-sector [center Vector2 radius f32 start-angle f32 end-angle f32 segments i32 color Color] "DrawCircleSector")
(declare-c draw-circle-sector-lines [center Vector2 radius f32 start-angle f32 end-angle f32 segments i32 color Color] "DrawCircleSectorLines")
(declare-c draw-circle-gradient [center-x i32 center-y i32 radius f32 inner Color outer Color] "DrawCircleGradient")
(declare-c draw-rectangle-pro [rec Rectangle origin Vector2 rotation f32 color Color] "DrawRectanglePro")
(declare-c draw-rectangle-gradient-v [pos-x i32 pos-y i32 width i32 height i32 top Color bottom Color] "DrawRectangleGradientV")
(declare-c draw-rectangle-gradient-h [pos-x i32 pos-y i32 width i32 height i32 left Color right Color] "DrawRectangleGradientH")
(declare-c draw-rectangle-gradient-ex [rec Rectangle top-left Color bottom-left Color top-right Color bottom-right Color] "DrawRectangleGradientEx")
(declare-c draw-triangle-fan [points (Ptr Vector2) point-count i32 color Color] "DrawTriangleFan")
(declare-c draw-triangle-strip [points (Ptr Vector2) point-count i32 color Color] "DrawTriangleStrip")
(declare-c draw-poly [center Vector2 sides i32 radius f32 rotation f32 color Color] "DrawPoly")
(declare-c draw-poly-lines [center Vector2 sides i32 radius f32 rotation f32 color Color] "DrawPolyLines")
(declare-c draw-poly-lines-ex [center Vector2 sides i32 radius f32 rotation f32 line-thick f32 color Color] "DrawPolyLinesEx")
(declare-c draw-spline-linear [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineLinear")
(declare-c draw-spline-basis [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineBasis")
(declare-c draw-spline-catmull-rom [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineCatmullRom")
(declare-c draw-spline-bezier-quadratic [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineBezierQuadratic")
(declare-c draw-spline-bezier-cubic [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineBezierCubic")
(declare-c draw-spline-segment-linear [p-1 Vector2 p-2 Vector2 thick f32 color Color] "DrawSplineSegmentLinear")
(declare-c draw-spline-segment-basis [p-1 Vector2 p-2 Vector2 p-3 Vector2 p-4 Vector2 thick f32 color Color] "DrawSplineSegmentBasis")
(declare-c draw-spline-segment-catmull-rom [p-1 Vector2 p-2 Vector2 p-3 Vector2 p-4 Vector2 thick f32 color Color] "DrawSplineSegmentCatmullRom")
(declare-c draw-spline-segment-bezier-quadratic [p-1 Vector2 c-2 Vector2 p-3 Vector2 thick f32 color Color] "DrawSplineSegmentBezierQuadratic")
(declare-c draw-spline-segment-bezier-cubic [p-1 Vector2 c-2 Vector2 c-3 Vector2 p-4 Vector2 thick f32 color Color] "DrawSplineSegmentBezierCubic")
(declare-c get-spline-point-linear [start-pos Vector2 end-pos Vector2 t f32] Vector2 "GetSplinePointLinear")
(declare-c get-spline-point-basis [p-1 Vector2 p-2 Vector2 p-3 Vector2 p-4 Vector2 t f32] Vector2 "GetSplinePointBasis")
(declare-c get-spline-point-catmull-rom [p-1 Vector2 p-2 Vector2 p-3 Vector2 p-4 Vector2 t f32] Vector2 "GetSplinePointCatmullRom")
(declare-c get-spline-point-bezier-quad [p-1 Vector2 c-2 Vector2 p-3 Vector2 t f32] Vector2 "GetSplinePointBezierQuad")
(declare-c get-spline-point-bezier-cubic [p-1 Vector2 c-2 Vector2 c-3 Vector2 p-4 Vector2 t f32] Vector2 "GetSplinePointBezierCubic")
(declare-c load-image-raw [file-name string width i32 height i32 format i32 header-size i32] Image "LoadImageRaw")
(declare-c load-image-anim [file-name string frames (Ptr i32)] Image "LoadImageAnim")
(declare-c load-image-anim-from-memory [file-type string file-data (Ptr u8) data-size i32 frames (Ptr i32)] Image "LoadImageAnimFromMemory")
(declare-c load-image-from-texture [texture Texture2D] Image "LoadImageFromTexture")
(declare-c load-image-from-screen [] Image "LoadImageFromScreen")
(declare-c export-image-to-memory [image Image file-type string file-size (Ptr i32)] (Ptr u8) "ExportImageToMemory")
(declare-c export-image-as-code [image Image file-name string] bool "ExportImageAsCode")
(declare-c gen-image-gradient-linear [width i32 height i32 direction i32 start Color end Color] Image "GenImageGradientLinear")
(declare-c gen-image-gradient-radial [width i32 height i32 density f32 inner Color outer Color] Image "GenImageGradientRadial")
(declare-c gen-image-gradient-square [width i32 height i32 density f32 inner Color outer Color] Image "GenImageGradientSquare")
(declare-c gen-image-checked [width i32 height i32 checks-x i32 checks-y i32 col-1 Color col-2 Color] Image "GenImageChecked")
(declare-c gen-image-white-noise [width i32 height i32 factor f32] Image "GenImageWhiteNoise")
(declare-c gen-image-perlin-noise [width i32 height i32 offset-x i32 offset-y i32 scale f32] Image "GenImagePerlinNoise")
(declare-c gen-image-cellular [width i32 height i32 tile-size i32] Image "GenImageCellular")
(declare-c gen-image-text [width i32 height i32 text string] Image "GenImageText")
(declare-c image-copy [image Image] Image "ImageCopy")
(declare-c image-from-image [image Image rec Rectangle] Image "ImageFromImage")
(declare-c image-from-channel [image Image selected-channel i32] Image "ImageFromChannel")
(declare-c image-text [text string font-size i32 color Color] Image "ImageText")
(declare-c image-text-ex [font Font text string font-size f32 spacing f32 tint Color] Image "ImageTextEx")
(declare-c image-format [image (Ptr Image) new-format i32] "ImageFormat")
(declare-c image-to-pot [image (Ptr Image) fill Color] "ImageToPOT")
(declare-c image-alpha-crop [image (Ptr Image) threshold f32] "ImageAlphaCrop")
(declare-c image-alpha-clear [image (Ptr Image) color Color threshold f32] "ImageAlphaClear")
(declare-c image-alpha-mask [image (Ptr Image) alpha-mask Image] "ImageAlphaMask")
(declare-c image-alpha-premultiply [image (Ptr Image)] "ImageAlphaPremultiply")
(declare-c image-blur-gaussian [image (Ptr Image) blur-size i32] "ImageBlurGaussian")
(declare-c image-kernel-convolution [image (Ptr Image) kernel (Ptr f32) kernel-size i32] "ImageKernelConvolution")
(declare-c image-resize-canvas [image (Ptr Image) new-width i32 new-height i32 offset-x i32 offset-y i32 fill Color] "ImageResizeCanvas")
(declare-c image-mipmaps [image (Ptr Image)] "ImageMipmaps")
(declare-c image-dither [image (Ptr Image) r-bpp i32 g-bpp i32 b-bpp i32 a-bpp i32] "ImageDither")
(declare-c image-rotate [image (Ptr Image) degrees i32] "ImageRotate")
(declare-c image-rotate-cw [image (Ptr Image)] "ImageRotateCW")
(declare-c image-rotate-ccw [image (Ptr Image)] "ImageRotateCCW")
(declare-c image-color-tint [image (Ptr Image) color Color] "ImageColorTint")
(declare-c image-color-invert [image (Ptr Image)] "ImageColorInvert")
(declare-c image-color-grayscale [image (Ptr Image)] "ImageColorGrayscale")
(declare-c image-color-contrast [image (Ptr Image) contrast f32] "ImageColorContrast")
(declare-c image-color-brightness [image (Ptr Image) brightness i32] "ImageColorBrightness")
(declare-c image-color-replace [image (Ptr Image) color Color replace Color] "ImageColorReplace")
(declare-c load-image-colors [image Image] (Ptr Color) "LoadImageColors")
(declare-c load-image-palette [image Image max-palette-size i32 color-count (Ptr i32)] (Ptr Color) "LoadImagePalette")
(declare-c unload-image-colors [colors (Ptr Color)] "UnloadImageColors")
(declare-c unload-image-palette [colors (Ptr Color)] "UnloadImagePalette")
(declare-c get-image-alpha-border [image Image threshold f32] Rectangle "GetImageAlphaBorder")
(declare-c image-clear-background [dst (Ptr Image) color Color] "ImageClearBackground")
(declare-c image-draw-pixel-v [dst (Ptr Image) position Vector2 color Color] "ImageDrawPixelV")
(declare-c image-draw-line [dst (Ptr Image) start-pos-x i32 start-pos-y i32 end-pos-x i32 end-pos-y i32 color Color] "ImageDrawLine")
(declare-c image-draw-line-v [dst (Ptr Image) start Vector2 end Vector2 color Color] "ImageDrawLineV")
(declare-c image-draw-line-ex [dst (Ptr Image) start Vector2 end Vector2 thick i32 color Color] "ImageDrawLineEx")
(declare-c image-draw-circle [dst (Ptr Image) center-x i32 center-y i32 radius i32 color Color] "ImageDrawCircle")
(declare-c image-draw-circle-v [dst (Ptr Image) center Vector2 radius i32 color Color] "ImageDrawCircleV")
(declare-c image-draw-circle-lines [dst (Ptr Image) center-x i32 center-y i32 radius i32 color Color] "ImageDrawCircleLines")
(declare-c image-draw-circle-lines-v [dst (Ptr Image) center Vector2 radius i32 color Color] "ImageDrawCircleLinesV")
(declare-c image-draw-rectangle [dst (Ptr Image) pos-x i32 pos-y i32 width i32 height i32 color Color] "ImageDrawRectangle")
(declare-c image-draw-rectangle-v [dst (Ptr Image) position Vector2 size Vector2 color Color] "ImageDrawRectangleV")
(declare-c image-draw-rectangle-rec [dst (Ptr Image) rec Rectangle color Color] "ImageDrawRectangleRec")
(declare-c image-draw-rectangle-lines [dst (Ptr Image) rec Rectangle thick i32 color Color] "ImageDrawRectangleLines")
(declare-c image-draw-triangle [dst (Ptr Image) v-1 Vector2 v-2 Vector2 v-3 Vector2 color Color] "ImageDrawTriangle")
(declare-c image-draw-triangle-ex [dst (Ptr Image) v-1 Vector2 v-2 Vector2 v-3 Vector2 c-1 Color c-2 Color c-3 Color] "ImageDrawTriangleEx")
(declare-c image-draw-triangle-lines [dst (Ptr Image) v-1 Vector2 v-2 Vector2 v-3 Vector2 color Color] "ImageDrawTriangleLines")
(declare-c image-draw-triangle-fan [dst (Ptr Image) points (Ptr Vector2) point-count i32 color Color] "ImageDrawTriangleFan")
(declare-c image-draw-triangle-strip [dst (Ptr Image) points (Ptr Vector2) point-count i32 color Color] "ImageDrawTriangleStrip")
(declare-c image-draw [dst (Ptr Image) src Image src-rec Rectangle dst-rec Rectangle tint Color] "ImageDraw")
(declare-c image-draw-text [dst (Ptr Image) text string pos-x i32 pos-y i32 font-size i32 color Color] "ImageDrawText")
(declare-c image-draw-text-ex [dst (Ptr Image) font Font text string position Vector2 font-size f32 spacing f32 tint Color] "ImageDrawTextEx")
(declare-c load-texture-cubemap [image Image layout i32] Texture2D "LoadTextureCubemap")
(declare-c update-texture [texture Texture2D pixels (Ptr u8)] "UpdateTexture")
(declare-c update-texture-rec [texture Texture2D rec Rectangle pixels (Ptr u8)] "UpdateTextureRec")
(declare-c gen-texture-mipmaps [texture (Ptr Texture2D)] "GenTextureMipmaps")
(declare-c set-texture-filter [texture Texture2D filter i32] "SetTextureFilter")
(declare-c set-texture-wrap [texture Texture2D wrap i32] "SetTextureWrap")
(declare-c draw-texture-pro [texture Texture2D source Rectangle dest Rectangle origin Vector2 rotation f32 tint Color] "DrawTexturePro")
(declare-c color-is-equal [col-1 Color col-2 Color] bool "ColorIsEqual")
(declare-c color-to-int [color Color] i32 "ColorToInt")
(declare-c color-from-hsv [hue f32 saturation f32 value f32] Color "ColorFromHSV")
(declare-c color-tint [color Color tint Color] Color "ColorTint")
(declare-c color-brightness [color Color factor f32] Color "ColorBrightness")
(declare-c color-contrast [color Color contrast f32] Color "ColorContrast")
(declare-c color-alpha [color Color alpha f32] Color "ColorAlpha")
(declare-c color-alpha-blend [dst Color src Color tint Color] Color "ColorAlphaBlend")
(declare-c color-lerp [color-1 Color color-2 Color factor f32] Color "ColorLerp")
(declare-c get-pixel-color [src-ptr (Ptr u8) format i32] Color "GetPixelColor")
(declare-c set-pixel-color [dst-ptr (Ptr u8) color Color format i32] "SetPixelColor")
(declare-c get-pixel-data-size [width i32 height i32 format i32] i32 "GetPixelDataSize")
(declare-c load-font-from-image [image Image key Color first-char i32] Font "LoadFontFromImage")
(declare-c load-font-from-memory [file-type string file-data (Ptr u8) data-size i32 font-size i32 codepoints (Ptr i32) codepoint-count i32] Font "LoadFontFromMemory")
(declare-c load-font-data [file-data (Ptr u8) data-size i32 font-size i32 codepoints (Ptr i32) codepoint-count i32 type i32] (Ptr GlyphInfo) "LoadFontData")
(declare-c gen-image-font-atlas [glyphs (Ptr GlyphInfo) glyph-recs (Ptr (Ptr Rectangle)) glyph-count i32 font-size i32 padding i32 pack-method i32] Image "GenImageFontAtlas")
(declare-c unload-font-data [glyphs (Ptr GlyphInfo) glyph-count i32] "UnloadFontData")
(declare-c export-font-as-code [font Font file-name string] bool "ExportFontAsCode")
(declare-c draw-text-pro [font Font text string position Vector2 origin Vector2 rotation f32 font-size f32 spacing f32 tint Color] "DrawTextPro")
(declare-c draw-text-codepoints [font Font codepoints (Ptr i32) codepoint-count i32 position Vector2 font-size f32 spacing f32 tint Color] "DrawTextCodepoints")
(declare-c set-text-line-spacing [spacing i32] "SetTextLineSpacing")
(declare-c load-codepoints [text string count (Ptr i32)] (Ptr i32) "LoadCodepoints")
(declare-c unload-codepoints [codepoints (Ptr i32)] "UnloadCodepoints")
(declare-c get-codepoint-count [text string] i32 "GetCodepointCount")
(declare-c get-codepoint [text string codepoint-size (Ptr i32)] i32 "GetCodepoint")
(declare-c get-codepoint-next [text string codepoint-size (Ptr i32)] i32 "GetCodepointNext")
(declare-c get-codepoint-previous [text string codepoint-size (Ptr i32)] i32 "GetCodepointPrevious")
(declare-c text-is-equal [text-1 string text-2 string] bool "TextIsEqual")
(declare-c text-length [text string] u32 "TextLength")
(declare-c text-split [text string delimiter i8 count (Ptr i32)] (Ptr (Ptr i8)) "TextSplit")
(declare-c text-find-index [text string find string] i32 "TextFindIndex")
(declare-c text-to-integer [text string] i32 "TextToInteger")
(declare-c text-to-float [text string] f32 "TextToFloat")
(declare-c draw-grid [slices i32 spacing f32] "DrawGrid")
(declare-c load-wave-from-memory [file-type string file-data (Ptr u8) data-size i32] Wave "LoadWaveFromMemory")
(declare-c update-sound [sound Sound data (Ptr u8) sample-count i32] "UpdateSound")
(declare-c export-wave-as-code [wave Wave file-name string] bool "ExportWaveAsCode")
(declare-c load-music-stream-from-memory [file-type string data (Ptr u8) data-size i32] Music "LoadMusicStreamFromMemory")
(declare-c load-audio-stream [sample-rate u32 sample-size u32 channels u32] AudioStream "LoadAudioStream")
(declare-c audio-stream-valid? [stream AudioStream] bool "IsAudioStreamValid")
(declare-c unload-audio-stream [stream AudioStream] "UnloadAudioStream")
(declare-c update-audio-stream [stream AudioStream data (Ptr u8) frame-count i32] "UpdateAudioStream")
(declare-c audio-stream-processed? [stream AudioStream] bool "IsAudioStreamProcessed")
(declare-c play-audio-stream [stream AudioStream] "PlayAudioStream")
(declare-c pause-audio-stream [stream AudioStream] "PauseAudioStream")
(declare-c resume-audio-stream [stream AudioStream] "ResumeAudioStream")
(declare-c audio-stream-playing? [stream AudioStream] bool "IsAudioStreamPlaying")
(declare-c stop-audio-stream [stream AudioStream] "StopAudioStream")
(declare-c set-audio-stream-volume [stream AudioStream volume f32] "SetAudioStreamVolume")
(declare-c set-audio-stream-pitch [stream AudioStream pitch f32] "SetAudioStreamPitch")
(declare-c set-audio-stream-pan [stream AudioStream pan f32] "SetAudioStreamPan")
(declare-c set-audio-stream-buffer-size-default [size i32] "SetAudioStreamBufferSizeDefault")

50
vendor/raylib/headers vendored
View File

@ -4,29 +4,49 @@
# means "if it is there" — an optional line with nothing behind it is simply
# not read.
#
# Why this exists. The declare-c lines in raylib.flan were transcribed by
# hand from raylib's documentation, and until now nothing could check that
# any of them matched the real function — BUILT.md records that as trusted
# rather than guaranteed. Point this at raylib's own header and the compiler
# reads the signatures instead: every hand-written line is compared against
# the library's, every defstruct against the header's record, and any raylib
# function the package has not bound becomes available under its own name.
# What this is for, now that the bindings are committed. generated.flan holds
# every declaration the importer produced, in the repository, so a build needs
# libraylib linkable and no header at all. This line is read by two things:
#
# Why it is optional. A build needs libraylib linkable and *not* raylib-devel
# installed, which is a property worth keeping; requiring a header would take
# it from everyone to give the check to whoever has one. So the default build
# is unchanged and this is opt-in, the same shape as ${FLAN_RAYLIB_WEB} in
# `link`.
# 1. `flan generate-c vendor/raylib`, which is the only way generated.flan
# is written. It reads the header named here, compares the package
# against it, and refuses to write when they disagree — so it is not
# possible to regenerate the bindings without comparing them to the
# library they claim to bind.
#
# 2. an ordinary build, when the variable happens to be set. Every C symbol
# is bound already — by hand in raylib.flan or by generation in
# generated.flan — so the importer generates nothing and the header read
# is purely the check. That check is now over all 425 declarations rather
# than the 172 hand-written ones, because the generated file is a package
# file like any other and is checked like one.
#
# Why it is still optional. A build needs libraylib linkable and *not*
# raylib-devel installed, which is a property worth keeping; requiring a header
# would take it from everyone to give the check to whoever has one. Before the
# bindings were committed this marker also decided how many bindings a build
# got, which was the real cost of it being opt-in; it no longer decides that,
# and all it now withholds is a check that regeneration has already run once.
# Same shape as ${FLAN_RAYLIB_WEB} in `link`, and for the same reason.
#
# The version must match the shared library `link` names — 5.5, libraylib.so.550.
# Reading one version's header while linking another's library is exactly the
# silent disagreement this exists to prevent, and `flan import-c` will say so:
# against a 5.1-dev header it reports ten differences that are all real.
# silent disagreement this exists to prevent, and it is caught rather than
# described: against a 5.1-dev header, regeneration reports ten differences
# that are all real and writes nothing.
#
# export FLAN_RAYLIB_H=/path/to/raylib-5.5/src/raylib.h
#
# To see what it would do without building anything:
# vendor/raylib/build-web.sh already clones that exact tag to build the browser
# archive, so a tree that has built for web has the matching header at
# vendor/raylib/web/raylib-5.5/src/raylib.h.
#
# To see what regeneration would produce without writing anything:
#
# flan import-c $FLAN_RAYLIB_H vendor/raylib/raylib.flan
#
# What shapes the generated half — which functions are skipped, and what they
# are called — is `bindings` beside this file. See its comments for why a
# committed generated file needs a config at all.
#
?${FLAN_RAYLIB_H}