Home /
Input Output /
haskell.nix
May 14, 9-10 PM (0)
May 14, 10-11 PM (0)
May 14, 11-12 AM (0)
May 15, 12-1 AM (1)
May 15, 1-2 AM (0)
May 15, 2-3 AM (0)
May 15, 3-4 AM (0)
May 15, 4-5 AM (2)
May 15, 5-6 AM (0)
May 15, 6-7 AM (0)
May 15, 7-8 AM (0)
May 15, 8-9 AM (0)
May 15, 9-10 AM (0)
May 15, 10-11 AM (1)
May 15, 11-12 PM (1)
May 15, 12-1 PM (0)
May 15, 1-2 PM (0)
May 15, 2-3 PM (2)
May 15, 3-4 PM (0)
May 15, 4-5 PM (0)
May 15, 5-6 PM (0)
May 15, 6-7 PM (0)
May 15, 7-8 PM (0)
May 15, 8-9 PM (0)
May 15, 9-10 PM (0)
May 15, 10-11 PM (0)
May 15, 11-12 AM (0)
May 16, 12-1 AM (1)
May 16, 1-2 AM (0)
May 16, 2-3 AM (0)
May 16, 3-4 AM (0)
May 16, 4-5 AM (0)
May 16, 5-6 AM (0)
May 16, 6-7 AM (0)
May 16, 7-8 AM (0)
May 16, 8-9 AM (0)
May 16, 9-10 AM (0)
May 16, 10-11 AM (0)
May 16, 11-12 PM (0)
May 16, 12-1 PM (0)
May 16, 1-2 PM (0)
May 16, 2-3 PM (0)
May 16, 3-4 PM (0)
May 16, 4-5 PM (0)
May 16, 5-6 PM (0)
May 16, 6-7 PM (0)
May 16, 7-8 PM (0)
May 16, 8-9 PM (0)
May 16, 9-10 PM (0)
May 16, 10-11 PM (0)
May 16, 11-12 AM (0)
May 17, 12-1 AM (1)
May 17, 1-2 AM (0)
May 17, 2-3 AM (0)
May 17, 3-4 AM (0)
May 17, 4-5 AM (0)
May 17, 5-6 AM (0)
May 17, 6-7 AM (0)
May 17, 7-8 AM (0)
May 17, 8-9 AM (0)
May 17, 9-10 AM (1)
May 17, 10-11 AM (2)
May 17, 11-12 PM (0)
May 17, 12-1 PM (2)
May 17, 1-2 PM (0)
May 17, 2-3 PM (0)
May 17, 3-4 PM (0)
May 17, 4-5 PM (0)
May 17, 5-6 PM (0)
May 17, 6-7 PM (0)
May 17, 7-8 PM (0)
May 17, 8-9 PM (0)
May 17, 9-10 PM (0)
May 17, 10-11 PM (0)
May 17, 11-12 AM (1)
May 18, 12-1 AM (3)
May 18, 1-2 AM (0)
May 18, 2-3 AM (1)
May 18, 3-4 AM (2)
May 18, 4-5 AM (1)
May 18, 5-6 AM (0)
May 18, 6-7 AM (0)
May 18, 7-8 AM (0)
May 18, 8-9 AM (0)
May 18, 9-10 AM (0)
May 18, 10-11 AM (0)
May 18, 11-12 PM (0)
May 18, 12-1 PM (2)
May 18, 1-2 PM (1)
May 18, 2-3 PM (0)
May 18, 3-4 PM (0)
May 18, 4-5 PM (0)
May 18, 5-6 PM (0)
May 18, 6-7 PM (0)
May 18, 7-8 PM (0)
May 18, 8-9 PM (0)
May 18, 9-10 PM (0)
May 18, 10-11 PM (0)
May 18, 11-12 AM (1)
May 19, 12-1 AM (1)
May 19, 1-2 AM (0)
May 19, 2-3 AM (2)
May 19, 3-4 AM (1)
May 19, 4-5 AM (0)
May 19, 5-6 AM (0)
May 19, 6-7 AM (2)
May 19, 7-8 AM (0)
May 19, 8-9 AM (0)
May 19, 9-10 AM (0)
May 19, 10-11 AM (0)
May 19, 11-12 PM (1)
May 19, 12-1 PM (0)
May 19, 1-2 PM (0)
May 19, 2-3 PM (0)
May 19, 3-4 PM (0)
May 19, 4-5 PM (0)
May 19, 5-6 PM (0)
May 19, 6-7 PM (0)
May 19, 7-8 PM (0)
May 19, 8-9 PM (0)
May 19, 9-10 PM (0)
May 19, 10-11 PM (0)
May 19, 11-12 AM (1)
May 20, 12-1 AM (1)
May 20, 1-2 AM (0)
May 20, 2-3 AM (0)
May 20, 3-4 AM (0)
May 20, 4-5 AM (0)
May 20, 5-6 AM (0)
May 20, 6-7 AM (0)
May 20, 7-8 AM (0)
May 20, 8-9 AM (0)
May 20, 9-10 AM (1)
May 20, 10-11 AM (0)
May 20, 11-12 PM (0)
May 20, 12-1 PM (0)
May 20, 1-2 PM (0)
May 20, 2-3 PM (0)
May 20, 3-4 PM (0)
May 20, 4-5 PM (0)
May 20, 5-6 PM (0)
May 20, 6-7 PM (0)
May 20, 7-8 PM (0)
May 20, 8-9 PM (0)
May 20, 9-10 PM (0)
May 20, 10-11 PM (0)
May 20, 11-12 AM (1)
May 21, 12-1 AM (1)
May 21, 1-2 AM (0)
May 21, 2-3 AM (1)
May 21, 3-4 AM (2)
May 21, 4-5 AM (0)
May 21, 5-6 AM (2)
May 21, 6-7 AM (1)
May 21, 7-8 AM (2)
May 21, 8-9 AM (2)
May 21, 9-10 AM (0)
May 21, 10-11 AM (0)
May 21, 11-12 PM (0)
May 21, 12-1 PM (0)
May 21, 1-2 PM (0)
May 21, 2-3 PM (0)
May 21, 3-4 PM (0)
May 21, 4-5 PM (0)
May 21, 5-6 PM (0)
May 21, 6-7 PM (0)
May 21, 7-8 PM (0)
May 21, 8-9 PM (0)
May 21, 9-10 PM (0)
48 commits this week
May 14, 2026
-
May 21, 2026
v1 builder: fix coverage installPhase hpc-dir lookup on Windows hosts
The doCoverage installPhase tried
`${testExecutable}-tmp/extra-compilation-artifacts` which expands
to `dist/build/<cname>/<cname><exeExt>-tmp/...`. On Windows hosts
`exeExt = ".exe"`, so the path becomes
`dist/build/<cname>/<cname>.exe-tmp/...` — a path cabal never
creates. The fallback `cp -r dist/hpc $out/share` then errors with
"No such file or directory" and the slice fails.
cabal's per-component tmp dir is `dist/build/<cname>/<cname>-tmp`
regardless of platform, so use that path directly (and drop the
broken `${testExecutable}-tmp` case — it was only ever right when
`exeExt == ""`, which the new path also covers).
Confirmed `tests.coverage.run` on ucrt64 builds; native still passes.
v1 builder: pick up `--enable-debug-info` from plan.json's configure-args
`cabal.project` `debug-info: 2` becomes `--enable-debug-info` in each affected unit's `configure-args` in plan.json (cabal-install records the boolean form regardless of the level). v1's comp-builder reads `enableDWARF` per-component to swap in the `.dwarf` GHC variant and pass `-g3` — picking the flag up here lets a project's cabal.project debug-info stanza flow through to v1 without per-component module overrides. Three pieces: 1. `modules/component-options.nix`: surface `enableDWARF` as a per-component option (matches `enableProfiling`). 2. `builder/comp-builder.nix`: read the default from `component.enableDWARF` instead of hard-coding `false`. 3. `modules/install-plan/configure-args.nix`: map `--enable-debug-info` in plan.json to `enableDWARF = true`. While here, rename the `--enable-*` predicate to `hasEnableFlag` and the resulting attrset to `enableFlags` so the helper now covers debug-info too without misleading naming. Confirmed `tests.cabal-simple-debug.run` on native ghc9141 builds again with the project default `builderVersion = 1`.
test/sublib-docs: accept both v1 and v2 haddock html layouts
The test's `find -path '*/share/doc/html/Lib.html'` only matched v2's flat unit-store layout (`share/doc/html/<Module>.html`). v1 puts haddock html under `share/doc/<pkg>/html/<Module>.html`, so the test failed on the musl64 / cross targets that fall back to v1. Drop the `-path` anchor and switch to `find -name 'Lib.html'` (and `*Slib.html` for the sublib). Both layouts are now accepted.
test/with-packages: skip withHoogle on static (no `.dyn_hi` for TH)
`withHoogle = true` (the default) makes `shellFor` haddock-build
each package's deps so the bundled hoogle DB has docs. On
musl-static the ghc compiler tree ships no `.dyn_hi` files (only
`.hi` and `.p_hi`), and packages like `OneTuple` need
`Language.Haskell.TH.dyn_hi` at haddock-time for their TH eval —
the build fails with:
Exception when reading interface file
.../template-haskell-2.24.0.0-inplace/Language/Haskell/TH.dyn_hi:
does not exist (No such file or directory)
Mirror `test/cabal-simple`: set `withHoogle = !isStatic`. Native
and other non-static targets keep their hoogle bundle.
Merge remote-tracking branch 'origin/master' into hkm/builder-v2
project: revert default builderVersion to 1
Switch the project-level `builderVersion` default back to `1` (Setup.hs / comp-builder) so v1 is exercised by all targets that don't explicitly opt in to `builderVersion = 2`. Lets us confirm the branch hasn't regressed v1 while v2 work continues. Projects that want the v2 slicing builder can set `builderVersion = 2` on their project module.
test/ghc-lib-reinstallable-cabal: disable on aarch64-multiplatform{,-musl}
Cross from x86_64 to aarch64-linux currently breaks the `useLocalGhcLib = true` slicing path. Disable the cabal flavour of the reinstallable-ghc-lib test on both the glibc and musl aarch64 multiplatform targets; native and other cross targets remain enabled.
test/annotations: disable on armv7a-android
`qemu-arm` segfaults running `iserv-proxy-interpreter` when ghc spawns iserv for the annotations TH eval, so the build can't proceed past `Compiling Lib`. The same chain works on `aarch64-android-prebuilt` (qemu-aarch64), so the issue is specific to the 32-bit ARM qemu / iserv interaction rather than something haskell.nix can sidestep. Disable on `isAndroid && isAarch32` — same shape as the existing `th-dlls` guard.
v2 builder: round-trip cabal.project per-pkg extra-lib-dirs / extra-include-dirs
cabal hashes per-package `extra-lib-dirs:` and `extra-include-dirs:`
into `pkgHashExtraLibDirs` / `pkgHashExtraIncludeDirs`. If the user
puts them in `cabalProjectLocal` to point cabal at a C library that
lives outside the standard `lib/` layout (e.g. mingw-w64 import libs
under `bin/`), plan-nix records the corresponding `--extra-lib-dirs=`
/ `--extra-include-dirs=` flags in plan.json's `configure-args` — but
v2 wasn't pulling those flags through to the slice's own
`cabal.project`, so the slice's cabal recomputed the package's
unit-id without them, diverged from plan-nix, and downstream
consumers couldn't reuse the slice.
Three pieces:
1. `modules/package-options.nix`: new per-package `extraLibDirs` and
`extraIncludeDirs` options.
2. `modules/install-plan/configure-args.nix`: extract
`--extra-lib-dirs=PATH` and `--extra-include-dirs=PATH` from
plan.json's `configure-args` into the new options.
3. `builder/comp-v2-builder.nix`: emit a `package <pkg>\n
extra-lib-dirs: ...\n extra-include-dirs: ...\n` block per
sliced package in the slice's `cabal.project`.
Also update `test/th-dlls-minimal/default.nix` to demonstrate the
pattern: spell test-clib's lib dirs out in `cabalProjectLocal` so
plan-nix's `extra-lib-dirs:` matches the slice's, AND keep
`components.library.libs = [test-clib]` so haskell.nix's module
system can resolve the `extra-libraries: test-clib` entry in
test-lib.cabal (without it, eval fails with
"The Nixpkgs package set does not contain the package: test-clib").
Confirmed:
* x86_64-linux ucrt64 th-dlls-minimal.build (was failing with
`Cabal-4345 Missing (or bad) C library: test-clib`)
* x86_64-linux musl64 githash.run, th-dlls.build
* x86_64-linux native with-packages.run
* x86_64-linux armv7a-android cabal-22.run, c-ffi.run
v2 builder: overlay cross build-tool binaries with build-platform variant
cabal v2-build prepends `<unit>/bin/` to PATH when invoking ghc for
any package whose `build-tool-depends:` refers to that unit. In our
cross-compilation setup we compose the build-tool's cross-target
`targetSlice` into the slice's cabal-store (so cabal recognises the
unit-id plan-nix recorded as "already installed") — but that means
the binary cabal prepends to PATH is for the cross-target arch.
ghc's `-pgmF hspec-discover` PATH lookup then resolves to the
cross-arch binary and `posix_spawnp` returns ENOEXEC ("Exec format
error") on the build host.
`withProgFlags` already passes
`--configure-option=--with-<tool>=<buildSlice>/bin/<tool>` so Setup
configure picks up the build-platform variant — but cabal v2-build's
own PATH-prepend for ghc preprocessor invocations bypasses that.
After lndir-composing the cabal-store, walk
`<storeDir>/<ghc>/*-e-<name>-*/bin/<name>` for each transitive
build-tool entry and replace the symlink with a copy of
`${buildSlice}/bin/${name}` (the build-platform binary). The
cross-target unit-id directory stays intact (so cabal's solver
still recognises it), but the executable inside is one that
actually runs on the build machine.
Native builds have an empty `buildToolBinOverlays`, so the overlay
block emits an empty string and other slices' drv hashes are
unchanged.
Confirmed:
* x86_64-linux armv7a-android cabal-22.run (was failing with
`hspec-discover: posix_spawnp: invalid argument (Exec format error)`)
* x86_64-linux musl64 githash.run, th-dlls.build
* x86_64-linux native with-packages.run
* x86_64-linux armv7a-android c-ffi.run
v2 builder: scope musl iserv libgcc env via ghc-shim; use host git on native-musl
Two coupled changes that fix musl64 TH targets that invoke external
binaries from compile-time code.
1. Move the `LD_LIBRARY_PATH=<musl-gcc-libs>/lib` workaround (so
iserv-dyn finds `libgcc_s.so.1` transitively from
`libstdc++.so` at TH-eval time) from a derivation-wide env attr
to a `makeWrapper --prefix LD_LIBRARY_PATH` on the ghc shim's
ghc binaries. v1 sets it derivation-wide; that env then leaks
into every glibc subprocess cabal/ghc spawn — `git`, in
particular, segfaults loading the musl libc as glibc's libc
("invalid ELF header"). Scoping to the ghc wrapper means iserv
still inherits it (so TH eval works) but glibc tools cabal
invokes directly (e.g. `git` for `source-repository-package`)
don't see it. Gated on `isNativeMusl` (build-arch == host-arch).
2. iserv-dyn also forks subprocesses for TH callbacks (e.g.
`githash`'s `$$tGitInfoCwd` runs `git rev-parse`), and those
children inherit `LD_LIBRARY_PATH` through the ghc-shim wrap.
Match what `test/githash/default.nix` already does on
`isNativeMusl`: pick the host-platform (musl) `git` instead of
the build-platform (glibc) one — a musl `git` ignores the
musl-gcc lib path harmlessly. Reach through
`pkgs.pkgsHostHost.gitReallyMinimal` to bypass `mkDerivation`'s
`nativeBuildInputs` auto-splicing, which otherwise resolves
`pkgs.gitReallyMinimal` back to the build-platform variant.
`gitReallyMinimal` rather than `gitMinimal`: gitMinimal's musl
cross-build runs the full git test suite (which fails);
gitReallyMinimal skips `doInstallCheck` and is what
`test/githash` already uses. Unified to `gitReallyMinimal` on
the non-musl branch too — smaller closure, same role.
Also tighten `test/githash/default.nix` to gate on
`haskellLib.isNativeMusl` rather than its prior `isMusl && cross`
heuristic.
Confirmed:
* x86_64-linux musl64 githash.run (was failing with
`git: invalid ELF header`)
* x86_64-linux musl64 cabal-source-repo.run
* x86_64-linux musl64 th-dlls.build
* x86_64-linux native with-packages.run
* x86_64-linux armv7a-android-prebuilt c-ffi.run
* x86_64-darwin native exe-lib-dlls.build-profiled
v2 builder: fix musl iserv-dyn libgcc lookup; restrict rpath rewrite walk
Two changes that unblock musl64 TH builds:
1. Set `LD_LIBRARY_PATH=<musl-gcc-libs>/lib` on `stdenv.hostPlatform.isMusl`
so iserv-dyn can resolve `libgcc_s.so.1` from `libstdc++.so` at TH-eval
time. Same workaround `comp-builder.nix` has carried for v1; without
it, `musl64.tests.th-dlls.build` fails with `Error loading shared
library libgcc_s.so.1` because musl's `libstdc++.so` only carries
`RUNPATH=<musl libc dir>` (not the gcc lib dir) and musl's dyld only
consults the immediate library's RUNPATH when resolving its deps.
That same `LD_LIBRARY_PATH` leaks into every subprocess we spawn,
including patchelf — a glibc binary built against glibc's
`libgcc_s.so.1`. Letting patchelf dlopen the musl libgcc segfaults
it (which was also the source of the `shrink-rpath` segfaults in
fixupPhase we'd see on musl). Prepend `unset LD_LIBRARY_PATH` to the
rpath rewrite block on musl; nothing in the rest of installPhase or
fixupPhase needs the iserv search path.
2. Restrict the rpath-walk's `find` to ELF / Mach-O candidates — `.so*`,
`.dylib*`, and any file under `bin/` — so the rewrite functions
don't have to defend against `.hi`, `.a`, `cabal-hash.txt`, etc.
The only remaining defence on the elf side is `|| return 0` on
`patchelf --print-rpath`, which the filter doesn't help with: musl exe
slices link statically (`executable-static: True`) and patchelf bails
with `cannot find section '.dynamic'` on those — comment notes it.
Confirmed:
* x86_64-linux musl64 th-dlls.build (previously failing with both
`libgcc_s.so.1` and the dep-resolution dyld error)
* x86_64-linux native with-packages.run
* x86_64-darwin native exe-lib-dlls.build-profiled
v2 builder: don't kill darwin installPhase on otool-of-non-Mach-O
The darwin rpath rewriter pipes `otool -l` into `awk`. Under `set -euo pipefail`, when otool errors on a non-Mach-O input (static `.a` archives, the cabal-store `.conf` files etc.), pipefail propagates otool's non-zero exit through the awk pipeline, the command substitution's exit status is non-zero, and `set -e` kills installPhase mid-step — silently, since stderr is redirected to /dev/null. Mirror the ELF branch's pattern: `|| return 0` on the assignment so non-Mach-O files just skip the function quietly.
v2 builder: rewrite RPATH to dep-slice targets before wiping dep dirs
The cleanup that follows `cabal v2-build` walks the slice's `$out` and
deletes the lndir-composed dep-slice content — those symlinks are
pure overhead (NAR scan, fixupPhase walk, reference scan all stat
them) and downstream consumers compose dep slices directly from
`nix-support/transitive-deps`.
GHC bakes `<this-slice>/store/.../<dep-uid>/lib` into the slice's own
shared libraries' DT_RUNPATH / LC_RPATH so iserv-dyn / dyld can find
each dep's transitive `.so` at TH-eval time. Plain "wipe dep dirs"
breaks this: stdenv's `shrink-rpath` (Linux fixupPhase) sees the
entry's dir is empty / missing and drops it, and on Darwin
install_name_tool wasn't touching them either — at runtime dyld
fails with `No such file or directory`.
Before wiping, walk every ELF / Mach-O file in the slice's own
unit dirs and rewrite its rpath: for each entry pointing into
`$out/store/`, follow a symlink under it via `readlink -f` to find
the dep slice's actual `/nix/store/<dep-slice>/store/.../<dep-uid>/lib`
and substitute that. Linux uses `patchelf --set-rpath`; Darwin uses
`install_name_tool -rpath`. After the rewrite, `shrink-rpath` sees
populated dirs and keeps the entries.
Confirmed:
* x86_64-linux native with-packages.run (paired with the awk fix
in the v2-shell env-file generator)
* x86_64-linux musl64 js-template-haskell.build — previously
failed with `Error loading shared library libHSth-abstraction-…
.so: No such file or directory` because shrink-rpath had
stripped the dep-slice path
* x86_64-linux native cabal-sublib-shell.run
* armv7a-android-prebuilt c-ffi.run (cross)
v2 shell: read multi-line `id:` values from composed-store .conf files
Cabal pretty-prints long `id:` hashes onto a separate indented line:
id:
lens-5.3.6-9653fc7a...
The awk pattern `/^id:[[:space:]]/ { print $2 }` only matched the
boot-db single-line form (`id: base-4.22.0.0-inplace`), so every
composed-store conf was silently skipped — the `package-id` lines for
lens, transformers, ... never made it into the env file even though
their `.conf`s were in the package-db, so ghc reported them as
hidden:
>>> Could not load module `Control.Lens'.
>>> It is a member of the hidden package `lens-5.3.6'.
Read the next line when `id:` has no value on the same line.
v2 shell: always run cabal-project-local-sync, even with no defaults
`haskell-nix-cabal-project-local-sync` was previously included in the shell's `nativeBuildInputs` and shellHook only when the project's effective `cabalProjectLocal` had non-empty content. For targets where none of the platform mkIfs fire and the user hasn't set anything (e.g. ghcjs), the script was missing from PATH — so any test that called it directly errored with `command not found`, and the test's `import: cabal.project.<targetPrefix>local` then failed because the file didn't exist either. Always include the script and always run the shellHook. When the project's `cabalProjectLocal` is empty, the script writes an empty `cabal.project.<targetPrefix>local`, which cabal imports harmlessly (no-op). Removes the empty-content gate, so the shape is the same across all targets. Verified the ghcjs cabal-sublib-shell test now passes (`aarch64-darwin.unstable.ghc9141.ghcjs.tests.cabal-sublib-shell.run`) and the existing native/musl64/wasi32 paths are unchanged.
dummy-ghc: report armv7a as armv7 / ArchARM ARMv7
Real `armv7a-unknown-linux-androideabi-ghc-9.14.1` reports:
,("Target platform","armv7-unknown-linux")
,("target arch","ArchARM ARMv7 [VFPv3,NEON] SOFTFP")
,("target platform string","armv7-unknown-linux")
while dummy-ghc was emitting `armv7a-unknown-linux` / `ArchAArch32`,
diverging the dummy and real `--info` outputs and failing
`x86_64-linux.unstable.ghc9141.armv7a-android-prebuilt.tests.dummy-ghc-info`.
Two normalisations:
* `platformString`: map `cpu.name == "armv7a"` → `armv7`, mirroring
the existing `i686 → i386` map.
* `target arch`: emit `ArchARM ARMv7 [VFPv3,NEON] SOFTFP` for
`cpu.name == "armv7a"`, before the generic `isAarch32 →
ArchAArch32` fallback.
Verified that the dummy-ghc-info test passes on
`armv7a-android-prebuilt` and is unchanged on aarch64-multiplatform,
aarch64-multiplatform-musl, aarch64-android-prebuilt, musl64,
ucrt64, and wasi32.
scripts: add build-failing-from-eval.sh
Takes a Hydra eval ID (e.g. 1542) or full URL, curls the eval page's `?full=1` view, extracts the failing `x86_64-linux.*` job names from the `Still Failing` / `Newly Failing` tab panes, and runs `nix build` for each with `--builders ''` so they exercise the build locally instead of being dispatched to a remote builder. Useful for iterating on PR CI runs without waiting for hydra slot scheduling.
v2 shell: auto-write project's cabalProjectLocal at shell startup
Move the platform-specific cabal.project pragmas back into
`modules/cabal-project.nix`'s `cabalProjectLocal` mkIfs (so
plan-nix's elaboration records the matching configure-args) and
expose them to the v2 shell so users get them in their
`cabal.project.local` automatically — no more hand-maintained
`shared: True` / `library-for-ghci: True` / `executable-static: True`
blocks duplicated between the shell and the slice.
Mechanism:
* `lib/call-cabal-project-to-nix.nix`: drop `platformCabalProjectPragmas`
(which injected the defaults directly into the rawCabalProject
text); rewrite the `cabalProjectLocal != null` check to also
skip `""`, so internal projects can switch from
`cabalProjectLocal = null` to `cabalProjectLocal = ""` without
changing the rawCabalProject hash.
* `modules/cabal-project.nix`: replace `platformCabalProjectPragmas`
with four `mkIf` blocks targeting `cabalProjectLocal`:
- musl → `package * executable-static: True`
- x86_64-darwin → `package * library-for-ghci: True`
- android → `package * ghc-options: -optl-static
-optl-ldl
[-optl-no-pie]`
- wasm 9.12+ → `package * shared: True`
(The wasm case is new — previously handled only by
`comp-v2-builder.nix`'s `forceShared` rewrite in the slice;
surfacing it at the project level makes plan-nix's elaboration
match without the slice having to paper over a `--disable-shared`
mismatch.)
* `overlays/ghc-packages.nix`, `compiler/ghc/default.nix`: switch
`cabalProjectLocal = null` to `cabalProjectLocal = ""` so the
`nullOr lines` option's merge accepts the mkIf injections. The
rawCabalProject hash is preserved by the `!= ""` skip above.
* `modules/component-driver.nix`, `overlays/haskell.nix`,
`builder/default.nix`: thread `cabalProjectLocal` from the
project module through to `shellForV2`.
* `builder/shell-for-v2.nix`: add a `haskell-nix-cabal-project-local-sync`
script (modeled after `haskell-nix-cabal-store-sync`). If
`cabal.project.<targetPrefix>local` is missing it writes it
from a `/nix/store` `writeText` of the merged
`cabalProjectLocal`; if present and equal it does nothing; if
present and different it prints the diff plus a
`haskell-nix-cabal-project-local-sync --force` invocation to
replace it. Invoked from the shell's shellHook and exposed on
`env.passthru.cabalProjectLocalSync`. For native shells the
target file is `cabal.project.local` (auto-picked by cabal);
for cross shells the filename has the target prefix and tests
pull it in with `import: cabal.project.<targetPrefix>local`.
* `test/cabal-sublib-shell/default.nix`: drop the hand-rolled
platform-conditional blocks from the inline `cabal.project`;
instead call `haskell-nix-cabal-project-local-sync` from the
test's buildCommand and, on cross targets, `import:` the
prefixed file. Also stop reading `../cabal.project.local` —
this test doesn't actually need any of its content, and the
`head.hackage` repository definition there triggered a
bootstrap that the sandbox's unpatched cabal couldn't satisfy
(`user error (https not supported)`).
Verified:
x86_64-darwin.unstable.ghc9141.native.tests.cabal-sublib-shell.run
x86_64-linux.unstable.ghc9141.musl64.tests.cabal-sublib-shell.run
aarch64-darwin.unstable.ghc9141.wasi32.tests.cabal-sublib-shell.run
all reuse the shell's prebuilt provider unit-ids and pass.
cabal-sublib-shell test: add musl `package * executable-static: True`, drop `with-compiler:`
Two changes:
* musl64 needs `executable-static: True` in `package *` to match
the slice's prebuilt provider unit-ids. The slice emits this
inside `package *` (via `comp-v2-builder.nix`'s pragmasOf), which
cabal hashes as `pkgHashFullyStaticExe` for every component —
libraries included. Without it the test's rebuilt provider lib's
`cabal-hash.txt` is missing the `fully-static-exe: True` line and
the unit-id forks from the slice.
* Drop the explicit `with-compiler: ghc-<version>` line. The
`${prefix}cabal` wrapper already passes `--with-compiler=` on
the CLI, so the project-level entry is redundant — and on cross
targets it was actively wrong (slice writes `<prefix>ghc`, test
was writing `ghc-<version>`). Empirically the line wasn't
needed for unit-id alignment either; both wasi32 and musl64
tests now reuse the shell's slices without it.
Verified locally on `x86_64-linux.unstable.ghc9141.musl64` and
`aarch64-darwin.unstable.ghc9141.wasi32`.
js-template-haskell, th-dlls: disable on android-aarch32 for ghc9124, ghc9141
iserv-proxy-interpreter segfaults under qemu-arm during TH eval on android-aarch32 with these GHCs: qemu: uncaught target signal 11 (Segmentation fault) - core dumped iserv-proxy: hFlush: resource vanished (Broken pipe) External interpreter terminated (1) Same failure mode the existing `ghc9102 / ghc9103` exclusion catches. Extend the exclusion to ghc9124 and ghc9141 (and their llvm variants) so these TH-using tests don't fail on this fragile combo while the underlying qemu / iserv interaction is investigated. (`th-dlls-minimal` is gated to Windows only and is unaffected.)