mkStandaloneApp: fail on a bundled dylib that loads outside the closure - #169
Draft
osmaczko wants to merge 1 commit into
Draft
mkStandaloneApp: fail on a bundled dylib that loads outside the closure#169osmaczko wants to merge 1 commit into
osmaczko wants to merge 1 commit into
Conversation
📊 Doc-test reportsThe four ways to wrap a C library plus the two cross-language composition tours — each scaffolded into real modules, built against this commit, loaded in logoscore, and driven — rendered alongside the commands actually run and their output (updated each run, commit Pages can take a minute to update after the run finishes. |
osmaczko
force-pushed
the
fix/darwin-bundle-dylib-closure
branch
4 times, most recently
from
July 29, 2026 13:37
5a2b06d to
01270c6
Compare
An app can build, cache and run while a module it ships cannot load at all. Modules reach an app inside LGX archives, and a tar is opaque to nix's reference scanning, so an absolute store path baked into a bundled Mach-O is never registered as a reference of anything: nix does not install it alongside the app, and dlopen fails wherever that path does not already exist. Such a path reaches a machine only as a side effect of building the module that names it, so the same unchanged module passes while CI still compiles it and starts failing once the binary cache serves it prebuilt, with nothing in any diff to point at. Linux has no equivalent hole, because autoPatchelfHook resolves and validates every DT_NEEDED at build time. This shipped, and cost a bisect over source revisions that could never have converged: a delivery module's librln named a libiconv nothing installed, and the missing module surfaced downstream as an intermittent crash in the module that waited on it. Building a standalone app now fails when a Mach-O it ships loads a store path outside the closure the app realises, naming both the file and the path it wants. The check reads LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB and LC_REEXPORT_DYLIB and compares them against closureInfo over exactly what `nix run` puts on the machine, so it asks the question the loader will ask. Testing it needs a macOS runner, and install-nix-action v27 cannot install there: its bundled installer aborts on the nixbld records the runner image already carries. Both jobs move to v31 so the repo keeps one installer at one pin.
osmaczko
force-pushed
the
fix/darwin-bundle-dylib-closure
branch
from
July 29, 2026 14:24
01270c6 to
209675d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An app can build, cache and run while a module it ships cannot load at all. Modules reach an app inside LGX archives, and a tar is opaque to nix's reference scanning, so an absolute store path baked into a bundled Mach-O is never registered as a reference of anything: nix does not install it alongside the app, and dlopen fails wherever that path does not already exist. Such a path reaches a machine only as a side effect of building the module that names it, so the same unchanged module passes while CI still compiles it and starts failing once the binary cache serves it prebuilt, with nothing in any diff to point at. Linux has no equivalent hole, because autoPatchelfHook resolves and validates every DT_NEEDED at build time.
This shipped, and cost a bisect over source revisions that could never have converged: a delivery module's librln named a libiconv nothing installed, and the missing module surfaced downstream as an intermittent crash in the module that waited on it.
Building a standalone app now fails when a Mach-O it ships loads a store path outside the closure the app realises, naming both the file and the path it wants. The check reads LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB and LC_REEXPORT_DYLIB and compares them against closureInfo over exactly what
nix runputs on the machine, so it asks the question the loader will ask.Testing it needs a macOS runner, and install-nix-action v27 cannot install there: its bundled installer aborts on the nixbld records the runner image already carries. Both jobs move to v31 so the repo keeps one installer at one pin.