GHC/Build/Link: relativize absolute rpaths + self-$ORIGIN (stacked on #378)#385
Draft
angerman wants to merge 5 commits into
Draft
GHC/Build/Link: relativize absolute rpaths + self-$ORIGIN (stacked on #378)#385angerman wants to merge 5 commits into
angerman wants to merge 5 commits into
Conversation
Add `package <stage>:*` project-file stanzas (e.g. `package build:*`, `package host:*`) so per-package configuration can target a single build stage. The same package can be built in both the build and host stages, so `package *`, top-level fields and `package <name>` cannot distinguish them; a stage qualifier can. - ProjectConfig gains projectConfigStagePackages :: MapMappend Stage PackageConfig (+ lens, parsec parser and field grammar). The legacy parser does not support the new syntax. - Per-package option lookup and the shared/profiling-lib downward-closed property in ProjectPlanning are made stage-aware, so e.g. `package build:* shared: False` keeps the build stage static even when the host stage is built dynamic. - Add a parser test (project-config-stage-packages). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
These are latent warnings that -Wincomplete-patterns / -Wunused-imports promote to errors only under validate's -Werror; they predate and are unrelated to the stage-qualified package configuration work below. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
depLibraryPaths returns absolute library paths whenever the dep's libdir is not under the package's own install prefix (i.e. almost always, in a cabal-store layout where each package gets its own hash-suffixed subdir). The previous getRPaths only prefixed `@loader_path` / `$ORIGIN` to already-relative paths, so those absolute store paths were baked directly into LC_RPATH (Mach-O) and DT_RUNPATH (ELF). On macOS up to and including Sonoma (macOS 14) dyld silently falls through to subsequent rpath entries when an absolute rpath does not exist. Sequoia (macOS 15) dyld treats the same condition as fatal and aborts the binary on launch. This affected the stable-haskell GHC bindist: a `/Volumes/WorkSpace/_work/ghc/ghc/ _build/stage2/store/host/aarch64-apple-darwin/lib` rpath baked in by the build runner caused `ghc --numeric-version` to SIGABRT when the bindist was installed on any macos-15 host. When the user has opted into relocatable mode (`--enable-relocatable`, or `relocatable: True` in a cabal project), this commit replaces such absolute rpaths with a `shortRelativePath`-computed relative form against the artifact's install directory. The relative form is well-formed (no `/Volumes` prefix to abort dyld on), and harmless when the bindist layout no longer matches the build store (dyld treats it as a normal missing rpath and falls through to subsequent entries). Non-relocatable builds (the default) are unchanged: absolute paths still pass through to preserve the existing semantics for non-relocated installs. The PackageDescription, InstallDirs, and shortRelativePath utility this needs are all already in scope or come from already-imported modules; only `bindir` and `libdir` field accessors are pulled in freshly from `Distribution.Simple.InstallDirs`. Companion to commit 010b365582c in stable-haskell/ghc, which strips the same leaked rpaths post-build with `install_name_tool` while this Cabal-side fix propagates through bindist rebuilds.
Initial version of this fix gated the new relativization on
`relocatable lbi` to keep non-relocatable builds byte-identical. The
gate doesn't help in practice:
* the stable-haskell GHC bindist build requires the new behavior
(else the darwin host binaries abort-trap on macOS 15);
* setting `relocatable: True` to flip the gate also triggers
`checkRelocatable` (which refuses cabal-store layouts whose deps
live in sibling prefixes) and changes how `library-dirs` are
written into .conf files — neither change is desirable for the
rpath fix, and the latter actively breaks the bindist
post-stage2 .conf rewriting in our Makefile pipeline.
The new always-on behavior is a strict improvement for every
relocatable scenario (cabal-store relocation, bindist relocation,
nix-style closure moves) and only a theoretical regression for the
"copy a single executable to an unrelated host and expect the same
absolute path to still resolve" case, which has never been part of
cabal's documented contract.
Companion to stable-haskell/ghc commit that drops the matching
`relocatable: True` flag from configure.ac.
…deps) The rpath relativization (added for the darwin LC_RPATH-leak fix) never adds the artifact's own directory to the runpath. depLibraryPaths can return the parent directory for a dependency installed in the same directory as the artifact, so that entry relativizes to "$ORIGIN/.." and the dependency is left unfound. glibc papers over this because GHC sets LD_LIBRARY_PATH at runtime before dlopen and glibc re-reads it per dlopen; musl reads LD_LIBRARY_PATH only at process startup and ignores the runtime change, so the missing self-rpath is fatal there. Concretely, a Backpack signature implementation (libHSp) installed next to the instantiated unit (libHSindef) fails to load under musl (GHC testsuite backpack/cabal/T14304 on Alpine), though it passes on every glibc platform. Always prepend the loader-relative self directory ($ORIGIN, or @loader_path on macOS) to the rpaths so a same-directory sibling is found. This is a relative entry, so it does not reintroduce the absolute build-host path the relativization removed (no macOS regression).
dc184ee to
e1b10cc
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.
Draft / stacked on #378 (
wip/andrea/stage-qualified-options).Forward-ports the absolute-rpath relativization onto the post-split
stage-qualified line and adds a self-
$ORIGINrpath entry. Stacking here (noton
master) so the result is the unified branch the stable-haskell GHCbuild needs — stage-qualified / host-only (#378) plus the rpath fixes — in
one place; it re-bases onto
masternaturally once #378 lands.Commits
--enable-relocatable$ORIGIN/@loader_pathin rpaths(1)+(2) are #368, currently stranded against the pre-split
feature/rebase-CI;this is the same change on the post-split line. (3) adds the artifact's own dir
to the runpath:
getRPathsnever did, so a same-dir dependency (a Backpacksignature impl
libHSpnext to the instantiatedlibHSindef) relativizes to$ORIGIN/..and isn't found. glibc hides this via the runtimeLD_LIBRARY_PATHGHC sets before
dlopen; musl reads it only at startup, so it's fatal there(testsuite
backpack/cabal/T14304on Alpine/musl). The new entry is relative,so it doesn't reintroduce the absolute path (1)+(2) remove (no macOS regression).
Status
Cherry-picks onto
stage-qualified-optionswith no conflicts (the Verbositysplit doesn't touch the rpath code). Not built locally — please let CI
confirm it typechecks against the post-split
LocalBuildInfo/InstallDirsAPI.Tracked in #384. Supersedes the master-targeting draft #383 (closed).