Skip to content

v0.5.0

Choose a tag to compare

@m3m0r7 m3m0r7 released this 21 Jun 04:46

Highlights

A type-layer and resolution release: generated PHP now models C structs and
enums as first-class typed values, native-library resolution gained .tbd and
linker-script handling, and the toolchain footprint shrank to libclang only.

Structs & enums in the generated API

  • Struct accessors. Each generated Types\<tag> wrapper exposes typed
    getField()/setField() accessors. Structs that embed another struct/union by
    value
    now render too (decided by a render-time fixpoint over the genuinely
    emittable aggregates), so a struct passed or returned by value works through
    PHP FFI — quickjs's JSValue round-trips by value end to end.
  • Enums. A C enum becomes an int-backed PHP enum. Parameters accept
    Enum|int; a return is mapped back with Enum::tryFrom() (Enum|null).

Fewer external tools — libclang is the only requirement

  • The export-symbol filter parses ELF / Mach-O / PE directly (the object
    crate) instead of shelling out to nm. This fixes a real failure on hosts without
    binutils, where unexported declarations (SDL's app-provided SDL_main) leaked into
    the cdef and broke FFI::cdef.
  • Local git-origin lookup goes through libgit2; the only pkg-config use (a test) is
    gone. No nm, git, or pkg-config binary is needed at install time.

Native-library resolution

  • Ordered fallback chain. library_names is tried in order; a virtual entry
    resolves to a real on-disk file when one exists (so the export filter can run) and
    only falls back to a bare-name load when none does.
  • macOS .tbd support. A new load_type (auto|elf|tbd|dll|dylib) plus a .tbd
    parser lets macOS system libraries resolve through the SDK text stub for their
    exports while the runtime loads the dylib by its install-name from the dyld
    shared cache. The active SDK is found via xcrun/xcode-select.
  • Linker scripts / split libraries. A GNU ld linker script
    (libncurses.soINPUT(libncurses.so.6 -ltinfo)) is parsed and its inputs are
    co-loaded, so a symbol split into a sibling .so (curses_version in libtinfo)
    resolves; a linker-script "exact match" is skipped in favour of the real soname.

Generator robustness

  • A qualifier macro (#define RESTRICT restrict) no longer leaks into a parameter.
  • An enum's own forward typedef no longer self-references when projected.
  • An empty-symbol_prefix (verbatim header) package still drops declarations the
    library does not export (glibc's atexit, in libc_nonshared.a).

Tooling

  • tests/docker-sweep/ — a committed, build-once, single-foreground-container,
    internally-parallel pnl install + EXAMPLES.md sweep across Alpine and Ubuntu,
    with agent rules for interpreting results.

Validation

Swept all packages without binutils on Alpine (musl) and Ubuntu (glibc): every
installable, non-hardware package's example runs, with zero cdef load-time errors
on both. The only remaining example failures are hardware-gated (an HID device, a
serial port). Rust (162) and PHP (65) suites green; clippy, php-cs-fixer, phpstan and
schema checks clean.