Sigil 0.17.7
A native-codegen correctness release. Native compilation now resolves module bindings the way the bytecode interpreter always has: a re-export through a cond-expand import, and a nested eval that begins while another eval is still on the stack, both used to fail only under native compilation and now work. Native WebAssembly builds export the full eval ABI again, and a build bug that could silently link stale object files into a mixed-ABI binary after a header change is fixed. Existing projects keep building without changes.
Facade re-exports resolve under native compilation
A library that re-exports a name it imports from a sibling, where that import sits inside a cond-expand branch (the usual shape for a platform facade that pulls in a different backend on WebAssembly than on native), used to bind only its own definitions under native compilation. The re-exported names came back unbound, on both eval and compiled cross-module calls, while the same code resolved correctly on bytecode. The cause was in how the native build computes a module's dependencies: it read only top-level import clauses and never looked inside cond-expand, so a facade whose import lived in a cond-expand WebAssembly branch recorded no dependency edge, and its module initializer ran before the module it re-exports from was ready. The dependency scan now descends into cond-expand, selecting the branch that matches the build's feature set the same way the compiler does. A facade re-export chain now resolves identically on bytecode, native desktop, and native WebAssembly.
A reentrant eval uses its own environment
When one eval was already running and a second eval began before it finished (for example, a browser event handler firing during a render that was itself driven by eval), the inner eval resolved its symbols against the outer, interrupted module rather than the environment it was handed. Bytecode keeps the module context per call frame, so it was never affected; the native backend tracked it in a single global that the interrupted call had left pointing at itself. The native path now pins each eval's environment across reentrancy while still honoring a deliberate eval-in-a-named-module, so a nested eval resolves where it should on every backend.
Native WebAssembly builds export the full eval ABI
Native web builds omitted the five eval-ABI symbols (sigil_wasm_eval and its companions) that the bytecode web build exports, so a native browser application that evaluates code at runtime could not reach the entry point. The native web export list now includes them, matching the bytecode ABI, so the eval surface is the same whichever backend you compile the browser build with.
Incremental builds no longer link stale objects after a header change
sigil build's C-compilation step had a shortcut: if an object file was newer than its .c source, it reused the object without checking anything else. But a C source includes headers, and a header can change without touching the .c file's timestamp. So after an edit to a widely-included header that changed a struct's layout, an incremental build silently reused objects compiled against the old layout and linked them alongside freshly compiled ones, producing a binary with a mixed, inconsistent ABI. The resulting compiler then miscompiled native builds in ways that looked like unrelated runtime failures. The C-compilation step now consults the content-addressed build cache, whose key includes the full header include-closure, before it falls back to the timestamp shortcut, so a header change correctly invalidates every dependent object. The timestamp-only path remains only for builds that have no cache available. As a backstop, a development binary built from a modified working tree now stamps -dirty into its reported version, so a binary that has drifted from its commit says so.