Home /
Input Output /
haskell.nix
May 07, 1-2 AM (0)
May 07, 2-3 AM (0)
May 07, 3-4 AM (0)
May 07, 4-5 AM (0)
May 07, 5-6 AM (1)
May 07, 6-7 AM (0)
May 07, 7-8 AM (1)
May 07, 8-9 AM (0)
May 07, 9-10 AM (0)
May 07, 10-11 AM (4)
May 07, 11-12 PM (0)
May 07, 12-1 PM (0)
May 07, 1-2 PM (0)
May 07, 2-3 PM (0)
May 07, 3-4 PM (0)
May 07, 4-5 PM (0)
May 07, 5-6 PM (0)
May 07, 6-7 PM (0)
May 07, 7-8 PM (0)
May 07, 8-9 PM (0)
May 07, 9-10 PM (0)
May 07, 10-11 PM (0)
May 07, 11-12 AM (1)
May 08, 12-1 AM (2)
May 08, 1-2 AM (2)
May 08, 2-3 AM (3)
May 08, 3-4 AM (1)
May 08, 4-5 AM (1)
May 08, 5-6 AM (0)
May 08, 6-7 AM (1)
May 08, 7-8 AM (1)
May 08, 8-9 AM (2)
May 08, 9-10 AM (1)
May 08, 10-11 AM (0)
May 08, 11-12 PM (0)
May 08, 12-1 PM (0)
May 08, 1-2 PM (0)
May 08, 2-3 PM (0)
May 08, 3-4 PM (0)
May 08, 4-5 PM (0)
May 08, 5-6 PM (0)
May 08, 6-7 PM (0)
May 08, 7-8 PM (0)
May 08, 8-9 PM (0)
May 08, 9-10 PM (1)
May 08, 10-11 PM (0)
May 08, 11-12 AM (1)
May 09, 12-1 AM (1)
May 09, 1-2 AM (0)
May 09, 2-3 AM (0)
May 09, 3-4 AM (1)
May 09, 4-5 AM (1)
May 09, 5-6 AM (0)
May 09, 6-7 AM (0)
May 09, 7-8 AM (0)
May 09, 8-9 AM (0)
May 09, 9-10 AM (0)
May 09, 10-11 AM (2)
May 09, 11-12 PM (0)
May 09, 12-1 PM (0)
May 09, 1-2 PM (0)
May 09, 2-3 PM (0)
May 09, 3-4 PM (0)
May 09, 4-5 PM (0)
May 09, 5-6 PM (0)
May 09, 6-7 PM (0)
May 09, 7-8 PM (0)
May 09, 8-9 PM (0)
May 09, 9-10 PM (0)
May 09, 10-11 PM (0)
May 09, 11-12 AM (0)
May 10, 12-1 AM (3)
May 10, 1-2 AM (0)
May 10, 2-3 AM (0)
May 10, 3-4 AM (0)
May 10, 4-5 AM (0)
May 10, 5-6 AM (0)
May 10, 6-7 AM (0)
May 10, 7-8 AM (0)
May 10, 8-9 AM (1)
May 10, 9-10 AM (0)
May 10, 10-11 AM (2)
May 10, 11-12 PM (0)
May 10, 12-1 PM (0)
May 10, 1-2 PM (4)
May 10, 2-3 PM (0)
May 10, 3-4 PM (0)
May 10, 4-5 PM (0)
May 10, 5-6 PM (0)
May 10, 6-7 PM (0)
May 10, 7-8 PM (0)
May 10, 8-9 PM (3)
May 10, 9-10 PM (1)
May 10, 10-11 PM (4)
May 10, 11-12 AM (0)
May 11, 12-1 AM (2)
May 11, 1-2 AM (0)
May 11, 2-3 AM (0)
May 11, 3-4 AM (0)
May 11, 4-5 AM (0)
May 11, 5-6 AM (0)
May 11, 6-7 AM (0)
May 11, 7-8 AM (0)
May 11, 8-9 AM (0)
May 11, 9-10 AM (0)
May 11, 10-11 AM (0)
May 11, 11-12 PM (0)
May 11, 12-1 PM (1)
May 11, 1-2 PM (0)
May 11, 2-3 PM (0)
May 11, 3-4 PM (0)
May 11, 4-5 PM (0)
May 11, 5-6 PM (0)
May 11, 6-7 PM (0)
May 11, 7-8 PM (0)
May 11, 8-9 PM (0)
May 11, 9-10 PM (0)
May 11, 10-11 PM (0)
May 11, 11-12 AM (0)
May 12, 12-1 AM (0)
May 12, 1-2 AM (0)
May 12, 2-3 AM (0)
May 12, 3-4 AM (0)
May 12, 4-5 AM (2)
May 12, 5-6 AM (0)
May 12, 6-7 AM (0)
May 12, 7-8 AM (0)
May 12, 8-9 AM (7)
May 12, 9-10 AM (6)
May 12, 10-11 AM (3)
May 12, 11-12 PM (1)
May 12, 12-1 PM (0)
May 12, 1-2 PM (1)
May 12, 2-3 PM (1)
May 12, 3-4 PM (0)
May 12, 4-5 PM (0)
May 12, 5-6 PM (0)
May 12, 6-7 PM (0)
May 12, 7-8 PM (0)
May 12, 8-9 PM (0)
May 12, 9-10 PM (0)
May 12, 10-11 PM (1)
May 12, 11-12 AM (0)
May 13, 12-1 AM (3)
May 13, 1-2 AM (0)
May 13, 2-3 AM (0)
May 13, 3-4 AM (0)
May 13, 4-5 AM (0)
May 13, 5-6 AM (2)
May 13, 6-7 AM (0)
May 13, 7-8 AM (0)
May 13, 8-9 AM (0)
May 13, 9-10 AM (0)
May 13, 10-11 AM (0)
May 13, 11-12 PM (0)
May 13, 12-1 PM (0)
May 13, 1-2 PM (0)
May 13, 2-3 PM (0)
May 13, 3-4 PM (0)
May 13, 4-5 PM (0)
May 13, 5-6 PM (0)
May 13, 6-7 PM (0)
May 13, 7-8 PM (0)
May 13, 8-9 PM (0)
May 13, 9-10 PM (0)
May 13, 10-11 PM (0)
May 13, 11-12 AM (0)
May 14, 12-1 AM (0)
May 14, 1-2 AM (0)
76 commits this week
May 07, 2026
-
May 14, 2026
Add test/cabal-sublib-shell demonstrating sublib-in-shell bug
This test builds a haskell.nix dev shell for a consumer package that depends on a public sublib of another local package (provider:slib). Inside the shell it runs `cabal v2-build --offline` against a minimal cabal.project (only consumer), so cabal must satisfy provider and provider:slib from the shell's pre-populated ghc-pkg database. The test currently fails because cabal-install's solver rejects the installed provider with: rejecting: provider-0.1.0.0/installed-… (does not contain library 'slib', which is required by consumer) Root cause is in Cabal's cabal-install-solver/src/Distribution/Solver/Modular/IndexConversion.hs (`convIP`), which annotates every InstalledPackageInfo with only `LMainLibName` and never exposes sublibs registered as separate InstalledPackageInfo entries (as haskell.nix does for multi-library packages). A fix in cabal-install-solver is required before this test can pass.
comp-v2-builder: pass pname/version to slice mkDerivation, not name
The cross-aware nixpkgs naming convention inserts the host platform's `config` BETWEEN `pname` and `version` when both are set, giving store-path names like `<pkg>-<ctype>-<cname>-<crossSuffix>-<version>` (matching v1's `comp-builder.nix:528-530` shape). Setting `name` directly appends the cross suffix at the END instead, producing `<pkg>-<ctype>-<cname>-<version>-<crossSuffix>`, which is silently incompatible with consumers that mirror v1's naming — in particular `tests.coverage.run`'s per-package coverage report expects `pkgb-test-tests<crossSuffix>-0.1.0.0-check<crossSuffix>` (the cover.nix output dir is keyed off the check derivation's `.name`). Switch `buildCabalStoreSlice` to accept `pname` + `version` separately (replacing the single `name` parameter) so v2 slice names match v1's cross-aware shape. The doc slice puts `-doc` in `version` so the resulting drv name is `<pkg>-<ctype>-<cname>-<crossSuffix>-<version>-doc` — same prefix shape as the regular slice plus a distinguishing suffix. Verified `tests.coverage.run` on `ghc984.musl32` (previously failed on missing `.tix` path) plus `tests.dummy-ghc-info` on `ghc9141` native + aarch64-multiplatform, `ghc9124` musl32 + ucrt64, and `ghc967` native + musl64 (all still pass).
comp-v2-builder: wrap --with-PROG build-tool flags in --configure-option=
`cabal v2-build` only accepts `--with-PROG=PATH` for a fixed set of GHC-toolchain programs (`--with-ghc`, `--with-ghc-pkg`, `--with-gcc`, ...); arbitrary `--with-<build-tool-exe>=PATH` is rejected with "unrecognized 'v2-build' option". Threading each flag through `--configure-option=` makes cabal pass it to per-package `Setup configure`, which DOES accept arbitrary `--with-PROG=PATH` for any program declared as a build-tool. This unblocks cross builds of slices whose deps have `build-tool-depends:` on a non-GHC-toolchain executable (e.g. `pkgb test-suite tests` depending on `pkga:pkga-exe` in `tests.coverage.run` on `ghc984.musl32`). Kept the flag at the cabal-CLI level rather than emitting a `package * configure-options:` block in cabal.project — the latter enters EVERY package's `pkgHashConfigureOptions` and forks the UnitId for packages that don't declare the build-tool from what their own slice computed. CLI-level flags only contribute to the hash of packages that actually invoke the program.
dummy-ghc: fix RTS-ways set for 9.8 native and add ld response-files filter
Verified `ghc --info` directly on each nixpkgs cross/native GHC derivation; the boundary between the 12-way set (with `v`, `p`, `_dyn` but no `_p_dyn`) and the full 16-way set is actually at 9.12, not 9.8 — and 9.8 still uses the 10-way 9.6-style ordering (no `v`/`p`, no `_dyn`). Updated branches: * < 9.10 non-musl: 10-way set. * < 9.12 musl OR 9.10 anything: 12-way set. * >= 9.12: 16-way set. `ld supports response files` shows up in 9.8+ native but cabal doesn't drive UnitId hashing from it; add to ignoredFields. Verified by `tests.dummy-ghc-info` on linux-0 for: ghc967/984 native + musl, ghc9103 native + static, ghc9124 musl32 + ucrt64, ghc9141 native + aarch64-multiplatform, ghc983 musl32.
dummy-ghc: align --info with real GHC across more compiler/cross variants
Extend `lib/dummy-ghc.nix` and the `tests.dummy-ghc-info` filter
list so the dummy's `--info` matches the real cross/native GHC
`--info` for the variants tested in hydra:
* aarch64-multiplatform (linux-gnu cross, Stage 1, no `_dyn`
RTS ways) — add a cross-linux-gnu branch alongside
android/static, keyed off cpu mismatch so libc-only crosses
(musl64) fall through to the native branch.
* `cross compiling` field now compares cpu + kernel rather
than the full platform triple, matching what GHC itself
reports (libc differences alone are not cross).
* musl32 (i686-linux-musl) and ucrt64 (x86_64-w64-mingw32):
`platformString` normalises `i686 -> i386` and the
Windows vendor/kernel pair to `unknown/mingw32`, matching
real GHC's `Target platform` / `target platform string`.
* ghc967 native and musl64: branch the RTS-ways string on
GHC version (9.6 uses a smaller, differently-ordered set
than 9.8+) and on libc (the 9.6 musl bootstrap reports a
12-way set while stock nixpkgs 9.6.7 reports 10).
Test-side: add a small set of per-version cosmetic fields to
`ignoredFields` (`GCC extra via C opts`, `LLVM clang command`,
`ld command`/flags, `dllwrap`, `touch command`,
`target RTS linker only supports shared libraries`) that don't
drive cabal-install elaboration.
Verified `tests.dummy-ghc-info` passes on linux-0 (with
`--builders ''`) for: ghc9141 native + aarch64-multiplatform,
ghc9124 musl32 + ucrt64, ghc967 native + musl64.
iserv-proxy: route android static-linking flags via cabalProjectLocal
v2 ignores the `setupBuildFlags` + `enableDebugRTS = true` mechanism that v1 used to give the cross-compiled iserv-proxy-interpreter its `-optl-static -optl-ldl -debug` (and `-optl-no-pie` on aarch32) at link time. Express the equivalent through cabal.project so plan-nix records the flags in the slice's UnitId-relevant configure-args. The inner `pkgs.stdenv.hostPlatform.isAndroid` guard scopes the stanza to the cross-host evaluation only; the build-platform iserv-proxy (`exes final.pkgsBuildBuild`) does not pick it up and links normally. Known issue: the resulting binary still SIGSEGVs under qemu-aarch64 at startup — see `project_v2_aarch64_android_iserv.md` in `.claude/memory`. Tracking separately.
iserv-proxy: add -v to android ghc-options for build diagnostics
Forces a fresh build with the GHC linker invocation visible in the log so we can compare the v2 link line with v1's.
iserv-proxy: add cabal static/shared flags to android cabalProjectLocal
Belt-and-braces alongside the existing -optl-static ghc-option, and changes the slice hash to force a clean rebuild on linux-0 (avoiding a possibly-tainted binary cached from nix-linux-builder).
iserv-proxy: drop executable-static cabal flag (match v1 exactly)
v1's iserv-proxy build only uses `-optl-static -optl-ldl` to drive static linking; it does NOT set cabal's `executable-static`. The `executable-static` flag forces ghc to use a specific static link flow that combined with `-optl-static` may have led to subtle binary differences (the strace showed v2 segfaulting in early RTS init while v1 mmap'd its GC arena correctly). Drop `executable-static` to mirror v1.
iserv-proxy: drop -debug from android ghc-options
The static aarch64-android iserv binary segfaulted under qemu before reaching argv parsing — the strace shows it hit the stack guard page during RTS init. The debug RTS variant (`-debug`) does more setup work at startup and pushed stack usage past qemu's mapped guard. v1 set `enableDebugRTS = true` via the haskell.nix module option but apparently never actually ran under qemu with the recent qemu / RTS versions — or v1's `Setup build --ghc-option=-debug` doesn't propagate quite the same way as `ghc-options: -debug` in cabal.project's pkgHash. Without -debug the binary runs to args parsing under qemu, so this is what we want. -optl-static / -optl-ldl stays.
linux-cross: add -optc-fPIC project-wide on aarch64
v1's armv6l-linux.nix injects `--gcc-option=-fPIC` into every package's setupBuildFlags on aarch64 (work-around for GHC #15275). The wrapGhc consumes `linux-cross.ghcOptions` so adding `-optc-fPIC` there makes the C bits of all cross-compiled packages get -fPIC just like v1. Without it the static aarch64-android iserv binary segfaulted under qemu even with all the cabal flags matching v1. Also clean up the per-package iserv-proxy block (executable-static: True is enough; static/ shared/executable-dynamic flow from there).
iserv-proxy: use cabal executable-static, drop redundant -optl-static
`executable-static: True` is cabal's first-class way to ask for a static executable; it tells ghc to pass `-static -optl-static` at the right points, gets dependency static-libs right, and doesn't interact badly with `-fPIC` the way the standalone `-optl-static` ghc-option did (which left us with a successfully-linked but segfaulting binary under qemu-aarch64).
iserv-proxy: force static/non-shared on Android (match v1 cabal flags)
v1 invokes Setup configure with `--disable-shared --enable-static --disable-executable-dynamic` for iserv-proxy on android (via the project's default cabal-pkg flags), so all iserv artifacts are static — necessary for qemu to run the binary on the build host without Android's dynamic loader. v2's default cabal.project has `shared: True`, `static: False`, `executable-dynamic: False`; adding the explicit override for the iserv-proxy package on android gets the same effect: static lib + static exe. Avoids the segfault under qemu that was hitting after `-optl-static` alone left the linker fighting between a shared lib and static exe.
iserv-proxy: also pass -optc-fPIC on aarch64 Android (matches v1)
v1's armv6l-linux.nix `addPackageKeys` injects `--gcc-option=-fPIC` into `setupBuildFlags` for every package on aarch64 cross builds (work-around for GHC #15275). For iserv-proxy specifically this means the cbits get compiled with -fPIC, which the qemu-emulated static aarch64-android binary needs at runtime — without it the binary segfaults inside qemu before iserv even initialises. v2 ignores `setupBuildFlags`, so route -fPIC through cabal.project as `-optc-fPIC` (passes -fPIC to gcc via ghc).
iserv-proxy: add -debug to Android ghc-options (matches enableDebugRTS)
v1's android override included `enableDebugRTS = true` alongside `-optl-static -optl-ldl` — the haskell.nix module translates that to `--ghc-option=-debug`, picking the debug RTS variant. Without it the statically-linked iserv-proxy-interpreter segfaulted under qemu-aarch64. Add `-debug` to the cabal.project ghc-options block so v2 picks up the same combination.
iserv-proxy: key Android static-link guard off the INNER pkgs
The cabalProjectLocal closure is shared between two `cabalProject'` instantiations of the iserv-proxy project — one under `pkgsBuildBuild` (build host iserv-proxy) and one under `final` (cross-target iserv-proxy-interpreter). Guarding on `final.stdenv.hostPlatform.isAndroid` matched both because `final` is the OUTER cross context (android). The build-host iserv-proxy then got `-optl-static` and the link of its shared library failed with `requires dynamic R_X86_64_32 reloc against '__TMC_END__' which may overflow at runtime`. Use the INNER `pkgs.stdenv.hostPlatform.isAndroid` (the lambda's own `pkgs` arg) so each instantiation sees its own platform. The Windows case is fine as-is because it has a cabal-level `if os(mingw32)` guard inside the project file.
iserv-proxy: drop `if os(android)` guard (isAndroid Nix check is enough)
The `final.lib.optionalString final.stdenv.hostPlatform.isAndroid` already keeps the flags out of the build-platform iserv-proxy build (different cabalProject' instantiation under pkgsBuildBuild). Drop the redundant `if os(android)` so the block parses cleanly — cabal's project-file conditional may not have matched the android os name we use here, leaving the ghc-options block inert.
iserv-proxy: link statically on Android in cabal.project for v2
v1's iserv-proxy-interpreter.override added `--ghc-option=-optl-static --ghc-option=-optl-ldl` (and `-optl-no-pie` on aarch32) via `setupBuildFlags` so the cross-compiled binary is self-contained — necessary because qemu-user-mode on the build host can't satisfy Android's dynamic loader (`/system/bin/linker64` / `/system/bin/linker`). v2 ignores `setupBuildFlags`, so the slice's binary came out dynamically linked and qemu refused to launch it with `qemu-aarch64: Could not open '/system/bin/linker64'`, breaking cross-TH for any package that touched iserv on android. Express the same flags in the iserv-proxy project's cabalProjectLocal under `if os(android)`. plan-nix now records them in the slice's UnitId-relevant configure-args, so the slice's cabal v2-build picks them up — same outcome as v1.
flake.lock: bump iserv-proxy to 3d649af (more aarch64-android stubs)
flake.lock: bump iserv-proxy to 0b8d6f6 (aarch64-android stubs)
linux-cross: provide `wrapGhc` for v2 cross-TH
v2 builder's slice cabal v2-build doesn't consume v1's `setupBuildFlags`, so the cross-TH iserv ghc-options (`-fexternal-interpreter -pgmi <qemu-wrapper>` etc.) never reached the cross GHC and slices for packages with TH (e.g. th-orphans, th-lift) failed with "Couldn't find a target code interpreter. Try with -fexternal-interpreter" on aarch64-android-prebuilt, aarch64-multiplatform, and other linux-cross targets. Mirror `overlays/mingw_w64.nix`'s `wrapGhc`: a derivation that `--add-flags`-wraps every ghc / ghci binary with the linux-cross `ghcOptions` (already used by v1 via `setupBuildFlags`). Cabal still sees the unwrapped `ghc --info` output (compiler-id, target platform, capabilities) so UnitId hash inputs are unchanged and plan-nix's recorded UnitIds keep matching the slice's computation. Other GHC binaries (`ghc-pkg`, `hsc2hs`, `runghc`, `haddock`, …) are symlinked through unchanged. The v2 comp-v2-builder already consumes `templateHaskell.wrapGhc` when set (see `sliceGhc`), so wiring this through is purely additive — windows already had it.
docs+v2: route DWARF via compilerSelection and debug-info, document the migration
v2 splits v1's monolithic `.dwarf` overlay into two pieces:
* `debug-info:` in cabal.project for DWARF in the user's source
(plan-nix records it → matching UnitIds).
* `compilerSelection` swap to `c.dwarf` for DWARF in the RTS /
`ghc-internal` (every plan/slice/dummy-ghc derives from the
same GHC, so UnitIds stay consistent).
* `docs/dev/debug-info.md` — parallel to docs/dev/profiling.md.
* `builder/comp-v2-builder.nix` — `.dwarf` now throws with both
knobs in the migration hint and a pointer to the new doc.
* `test/cabal-simple-debug/default.nix` — uses both knobs and
queries `.exePath` instead of `.dwarf.exePath`.
v2 builder: error on \`.dwarf\` with migration hint; route DWARF via cabal.project
Mirrors the existing \`.profiled\` treatment. v1's \`.dwarf\` was an overlay rebuild with \`enableDWARF = true\`, which would diverge from plan-nix's UnitId in v2 (the overlay toggles aren't in plan-nix's hash). Express DWARF in cabal.project's \`debug-info:\` instead — the slice itself carries DWARF when that's set, and \`<slice>.exePath\` gives the debug-info exe directly. Updated test/cabal-simple-debug to add \`debug-info: 2\` to cabalProjectLocal and use \`.exePath\` instead of \`.dwarf.exePath\`.