An acceptance case for bindings nobody wrote

The same boundary the raylib FFI case covers, reached from declarations
generated out of the header instead of transcribed into raylib.flan. The
package binds none of the four functions by hand, so the program running at all
is the claim.

What it prints pins more than that, by the argument the GetColor case already
makes: handing a struct over and reading it back proves nothing, since storing
and returning is symmetric and a permuted layout comes back permuted the same
way. ColorToInt of {17,34,51,68} is 0x11223344, so exchanging any two fields
changes the number, and ColorTint by white hands the four bytes back
separately. TextLength of "hello" is 5 only if the wrapper NUL-terminated the
copy.

At -O0 as well, for the reason the rest of the table is: every struct here
crosses as (addr v) on a local, which is the alloca mem2reg would launder
before anyone noticed it was wrong.

Skipped without FLAN_RAYLIB_H, since the import is opt-in. The importer's own
table does not skip — it runs against test/headers/sample.h, which is
committed.
This commit is contained in:
Joseph Ferano 2026-09-12 16:13:28 +07:00
parent e12e3e11c5
commit 6c28529838

View File

@ -658,6 +658,39 @@ let () =
else
print_endline "acceptance: skipping the raylib FFI case (no libraylib)";
(* The same boundary, from declarations nobody wrote. Every binding this
program calls came out of raylib's header through vendor/raylib/headers;
the package binds none of the four by hand, so if it runs at all the
importer produced working declarations.
What it prints pins more than that. ColorToInt of {17,34,51,68} is
0x11223344 the four fields read in r,g,b,a order, so exchanging any
two changes the number and ColorTint by white is the identity, which
hands the four bytes back separately. That is the same argument the
GetColor case makes and for the same reason: handing a struct over and
reading it back proves nothing, because storing and returning is
symmetric and a permuted layout comes back permuted the same way.
TextLength of "hello" is 5, which is only true if the generated wrapper
NUL-terminated the copy.
Skipped without FLAN_RAYLIB_H, because the import is opt-in a build
needs libraylib linkable and not raylib-devel installed, and that is a
property worth keeping. The importer's own table does not skip: it runs
against test/headers/sample.h, which is committed. *)
(match Sys.getenv_opt "FLAN_RAYLIB_H" with
| Some h when Sys.file_exists h
&& Sys.command "ldconfig -p 2>/dev/null | grep -q libraylib" = 0 ->
let out = "10\n5\n287454020\n17\n34\n51\n68\n" in
outputs "raylib, bindings read from the header" "programs/raylib-imported.flan" out;
(* At -O0 too, for the reason the rest of the table is: every struct
here crosses as (addr v) on a local, which is the alloca mem2reg
would launder before anyone noticed it was wrong. *)
outputs ~opt:"-O0" "raylib, bindings read from the header, -O0"
"programs/raylib-imported.flan" out
| _ ->
print_endline
"acceptance: skipping the imported-bindings case (FLAN_RAYLIB_H unset)");
(* raylib's Image family, headless, and the strongest FFI case here: an
Image is pixels in RAM, so raylib *computes* with it rather than
storing and returning it.