Update cardano-api for Dijkstra queries in cardano-cli
May 21, 5-6 AM (27)
May 21, 6-7 AM (14)
May 21, 7-8 AM (22)
May 21, 8-9 AM (34)
May 21, 9-10 AM (45)
May 21, 10-11 AM (37)
May 21, 11-12 PM (27)
May 21, 12-1 PM (63)
May 21, 1-2 PM (68)
May 21, 2-3 PM (60)
May 21, 3-4 PM (53)
May 21, 4-5 PM (20)
May 21, 5-6 PM (27)
May 21, 6-7 PM (27)
May 21, 7-8 PM (25)
May 21, 8-9 PM (23)
May 21, 9-10 PM (3)
May 21, 10-11 PM (29)
May 21, 11-12 AM (10)
May 22, 12-1 AM (16)
May 22, 1-2 AM (6)
May 22, 2-3 AM (8)
May 22, 3-4 AM (4)
May 22, 4-5 AM (11)
May 22, 5-6 AM (10)
May 22, 6-7 AM (21)
May 22, 7-8 AM (13)
May 22, 8-9 AM (38)
May 22, 9-10 AM (12)
May 22, 10-11 AM (18)
May 22, 11-12 PM (25)
May 22, 12-1 PM (24)
May 22, 1-2 PM (34)
May 22, 2-3 PM (56)
May 22, 3-4 PM (13)
May 22, 4-5 PM (29)
May 22, 5-6 PM (13)
May 22, 6-7 PM (19)
May 22, 7-8 PM (20)
May 22, 8-9 PM (12)
May 22, 9-10 PM (12)
May 22, 10-11 PM (41)
May 22, 11-12 AM (12)
May 23, 12-1 AM (9)
May 23, 1-2 AM (0)
May 23, 2-3 AM (3)
May 23, 3-4 AM (1)
May 23, 4-5 AM (1)
May 23, 5-6 AM (4)
May 23, 6-7 AM (12)
May 23, 7-8 AM (1)
May 23, 8-9 AM (3)
May 23, 9-10 AM (1)
May 23, 10-11 AM (1)
May 23, 11-12 PM (5)
May 23, 12-1 PM (1)
May 23, 1-2 PM (6)
May 23, 2-3 PM (5)
May 23, 3-4 PM (5)
May 23, 4-5 PM (4)
May 23, 5-6 PM (0)
May 23, 6-7 PM (3)
May 23, 7-8 PM (23)
May 23, 8-9 PM (1)
May 23, 9-10 PM (9)
May 23, 10-11 PM (21)
May 23, 11-12 AM (27)
May 24, 12-1 AM (9)
May 24, 1-2 AM (0)
May 24, 2-3 AM (1)
May 24, 3-4 AM (1)
May 24, 4-5 AM (0)
May 24, 5-6 AM (3)
May 24, 6-7 AM (1)
May 24, 7-8 AM (2)
May 24, 8-9 AM (2)
May 24, 9-10 AM (4)
May 24, 10-11 AM (4)
May 24, 11-12 PM (1)
May 24, 12-1 PM (7)
May 24, 1-2 PM (46)
May 24, 2-3 PM (5)
May 24, 3-4 PM (3)
May 24, 4-5 PM (18)
May 24, 5-6 PM (2)
May 24, 6-7 PM (4)
May 24, 7-8 PM (13)
May 24, 8-9 PM (10)
May 24, 9-10 PM (15)
May 24, 10-11 PM (34)
May 24, 11-12 AM (42)
May 25, 12-1 AM (9)
May 25, 1-2 AM (5)
May 25, 2-3 AM (6)
May 25, 3-4 AM (1)
May 25, 4-5 AM (6)
May 25, 5-6 AM (14)
May 25, 6-7 AM (17)
May 25, 7-8 AM (17)
May 25, 8-9 AM (32)
May 25, 9-10 AM (43)
May 25, 10-11 AM (64)
May 25, 11-12 PM (33)
May 25, 12-1 PM (43)
May 25, 1-2 PM (40)
May 25, 2-3 PM (20)
May 25, 3-4 PM (27)
May 25, 4-5 PM (16)
May 25, 5-6 PM (6)
May 25, 6-7 PM (7)
May 25, 7-8 PM (11)
May 25, 8-9 PM (12)
May 25, 9-10 PM (16)
May 25, 10-11 PM (44)
May 25, 11-12 AM (26)
May 26, 12-1 AM (12)
May 26, 1-2 AM (11)
May 26, 2-3 AM (8)
May 26, 3-4 AM (11)
May 26, 4-5 AM (6)
May 26, 5-6 AM (9)
May 26, 6-7 AM (26)
May 26, 7-8 AM (43)
May 26, 8-9 AM (39)
May 26, 9-10 AM (42)
May 26, 10-11 AM (45)
May 26, 11-12 PM (59)
May 26, 12-1 PM (34)
May 26, 1-2 PM (50)
May 26, 2-3 PM (50)
May 26, 3-4 PM (18)
May 26, 4-5 PM (20)
May 26, 5-6 PM (13)
May 26, 6-7 PM (20)
May 26, 7-8 PM (12)
May 26, 8-9 PM (15)
May 26, 9-10 PM (15)
May 26, 10-11 PM (35)
May 26, 11-12 AM (30)
May 27, 12-1 AM (16)
May 27, 1-2 AM (8)
May 27, 2-3 AM (9)
May 27, 3-4 AM (5)
May 27, 4-5 AM (32)
May 27, 5-6 AM (9)
May 27, 6-7 AM (49)
May 27, 7-8 AM (63)
May 27, 8-9 AM (37)
May 27, 9-10 AM (74)
May 27, 10-11 AM (83)
May 27, 11-12 PM (30)
May 27, 12-1 PM (50)
May 27, 1-2 PM (38)
May 27, 2-3 PM (53)
May 27, 3-4 PM (37)
May 27, 4-5 PM (6)
May 27, 5-6 PM (17)
May 27, 6-7 PM (18)
May 27, 7-8 PM (24)
May 27, 8-9 PM (13)
May 27, 9-10 PM (13)
May 27, 10-11 PM (29)
May 27, 11-12 AM (27)
May 28, 12-1 AM (9)
May 28, 1-2 AM (3)
May 28, 2-3 AM (4)
May 28, 3-4 AM (2)
May 28, 4-5 AM (8)
May 28, 5-6 AM (6)
3,337 commits this week
May 21, 2026
-
May 28, 2026
cardano-tracer, grafana-datasource: extend series labels, rename node-state endpoint, misc
- Acceptors/Utils.hs: include node_name alongside node_id in SeriesIdentifier - Component.hs: generalise insert to accept SeriesIdentifier directly; fix pruning period default (was 3600 ms ≈ 3.6 s, now 15 min) - Component/Trace.hs: update TimeseriesTraceInsert to carry SeriesIdentifier; emit query_text/query_result only at DDetailed; lower Prune severity to Debug - TimeseriesServer.hs: rename node/state → node/sync-progress; remove #if RTVIEW guard (endpoint is now unconditionally available) - Utils.hs: move NodeStateWrapper (and its FromJSON instance) here from RTView/Update/NodeState.hs so it can be shared without the RTVIEW flag; move vector from rtview-only to unconditional build-depends - RTView/Update/NodeState.hs: remove NodeStateWrapper definition (now in Utils) - grafana-datasource: rename node-state → node-sync-progress throughout (QueryEditor, datasource, types, dashboard); rename dashboard to rtview-port - grafana-datasource: add README with build and run instructions
Enable Dijkstra era ledger queries
Makeshift changes to the the constraints to enable ledger queries in Dijkstra. This undid some TODO stubs, but the changes to registration certificates required some stubbing further down the line. Queries that should work at least: query protocol-parameters query utxo query ledger-state
Cleanup Foreign/ modules in favour of this in agda-stdlib-meta
Update from 31f9198577c24905439aaafe0ac6f6d370882495
Artifacts generated from 379377c30032f10ace18f986940018da70e0899c
hedgehog-extras/0.10.1.0: Bump base dependency (#1381)
Add Certs PoV: per-step ≡ᵐᵗ + coin bridges, RTC lift
New modules under src/Ledger/Dijkstra/Specification/Certs/Properties/: + PoVLemmas.lagda.md (CERT-level) + PoV.lagda.md (CERTS-level) PoVLemmas exports: + CERT-pov: preservation of value at one CERT step + CERT-pots-≡ᵐᵗ: per-step ≡ᵐ-componentwise triple bridge + CERT-coinFromDeposits-step: per-step coin bridge (derived) + Triple machinery: pots, coinFromDeposits-pots, updateCertDeposit-list, pots-updateCertDeposits + PoolDepositsAligned, Is-just-isPoolRegistered⇒∈-dom PoV exports a bundled Certs-PoV module parameterised by indexedSumᵛ'-∪ and PoolDepositsAligned-CERT, providing: + CERTS-pov: preservation across the closure + CERTS-Deposits-Bridge.CERTS-coinFromDeposits-updateCertDeposits: the closed-form coin bridge consumed by LEDGER-pov The triple-form per-step bridge from the previous Ledger-PoV branch required a deferred propositional equation m ∪ˡ ❴ k , v ❵ ≡ m (when k ∈ dom m). This PR drops that parameter, using instead the upstream ≡ᵐ-componentwise singleton-∈-∪ˡ plumbed through the closed form via ∪⁺-cong-r, ∪ˡ-cong, restrict-cong, and collapsed to a coin equality via ≡ᵉ-getCoin. Refs #1185
hedgehog-extras/0.10.1.0: Bump base dependency
build: update logback-classic to 1.5.33 (#663)
Signed-off-by: Hyperledger Bot <[email protected]> Co-authored-by: Hyperledger Bot <[email protected]>
chore(deps): bump tmp from 0.2.5 to 0.2.7 in the npm_and_yarn group across 1 directory (#653)
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Add Certs PoV: per-step ≡ᵐᵗ + coin bridges, RTC lift
New modules under src/Ledger/Dijkstra/Specification/Certs/Properties/: + PoVLemmas.lagda.md (CERT-level) + PoV.lagda.md (CERTS-level) PoVLemmas exports: + CERT-pov: preservation of value at one CERT step + CERT-pots-≡ᵐᵗ: per-step ≡ᵐ-componentwise triple bridge + CERT-coinFromDeposits-step: per-step coin bridge (derived) + Triple machinery: pots, coinFromDeposits-pots, updateCertDeposit-list, pots-updateCertDeposits + PoolDepositsAligned, Is-just-isPoolRegistered⇒∈-dom PoV exports a bundled Certs-PoV module parameterised by indexedSumᵛ'-∪ and PoolDepositsAligned-CERT, providing: + CERTS-pov: preservation across the closure + CERTS-Deposits-Bridge.CERTS-coinFromDeposits-updateCertDeposits: the closed-form coin bridge consumed by LEDGER-pov The triple-form per-step bridge from the previous Ledger-PoV branch required a deferred propositional equation m ∪ˡ ❴ k , v ❵ ≡ m (when k ∈ dom m). This PR drops that parameter, using instead the upstream ≡ᵐ-componentwise singleton-∈-∪ˡ plumbed through the closed form via ∪⁺-cong-r, ∪ˡ-cong, restrict-cong, and collapsed to a coin equality via ≡ᵉ-getCoin. Refs #1185
Merge branch 'main' into develop
add ghcXX-minimal-ghc-web flavor: wasm + JS backend dev tooling
The wasm and JavaScript backends need a small set of dev-time tools
that aren't part of a stock Haskell shell:
* nodejs_22 — required for utils/jsffi/post-link.mjs (uses
import.meta.filename added in Node 20.11; Ubuntu's
apt nodejs is 18.x and silently breaks the post-link
step) and for JSFFI host execution at test time
* wabt — wasm-objdump for inspecting custom sections (e.g.
detecting ghc_wasm_jsffi imports) in wasm modules
* wasmtime — pure-WASI runtime, when a wasm module has no JSFFI
imports and can run standalone
* emscripten — the JavaScript backend's C toolchain (emcc / em++ /
emar / emnm / emranlib / emstrip)
Currently downstream consumers (e.g. stable-haskell/ghc's wasm
cross-compiler CI) bootstrap these per-platform via apt + NodeSource +
nix-env + curl installers, plus PATH workarounds for devx scrubbing
/usr/bin. Shipping them in the flavor collapses ~70 lines of
platform-shell to one `shell:` line in user workflows.
Deliberately NOT bundled: wasi-sdk. Its version needs to match the
wasm32-wasi-ghc cross-compiler bundle that ghc-wasm-meta
(https://gitlab.haskell.org/ghc/ghc-wasm-meta) owns, so keeping that
pin in ghc-wasm-meta avoids version drift across two trees. Users
still bootstrap wasi-sdk via ghc-wasm-meta for wasm32-wasi builds.
Closure cost on aarch64-darwin (paired with the prior trim commit):
ghc98-minimal-ghc (current master) : 6.12 GB
ghc98-minimal-ghc (after trim PR) : 4.00 GB (-2.12 GB)
ghc98-minimal-ghc-web (this commit) : 5.99 GB (+1.99 GB)
Net: the web flavor with the full toolchain ends up SMALLER than the
current untrimmed minimal-ghc, because the trim commit removed
ghc-9.10.3 and emscripten's LLVM/apple-sdk now dedupes against the
shell's base nixpkgs pin (no version fragmentation).
Comfortably under the 10 GB GitHub Actions per-repo cache cap on
both Darwin and Linux (Linux delta is similar magnitude — emscripten
+ closure-compiler are the heavy hitters on both).
Verified inside the patched shell:
$ ghc --version # 9.8.4
$ cabal --version # 3.17.0.0
$ happy --version # 2.1.7
$ alex --version # 3.5.4.0
$ git --version # 2.51.2 (gitMinimal)
$ node --version # v22.21.1
$ wasm-objdump --version # 1.0.37
$ wasmtime --version # 38.0.3
$ emcc --version # 4.0.12-git
All on the expected store paths.
chore(deps): bump tmp in the npm_and_yarn group across 1 directory
Bumps the npm_and_yarn group with 1 update in the / directory: [tmp](https://github.com/raszi/node-tmp). Updates `tmp` from 0.2.5 to 0.2.7 - [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md) - [Commits](https://github.com/raszi/node-tmp/compare/v0.2.5...v0.2.7) --- updated-dependencies: - dependency-name: tmp dependency-version: 0.2.7 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <[email protected]>
trim -minimal-ghc closure: build happy/alex with the shell's GHC
The `withGHCTooling` block in dynamic.nix sourced `happy` and `alex` from nixpkgs's `pkgs.haskellPackages`, which builds them with a different GHC than the shell's `compiler` (currently ghc-9.10.3 in nixpkgs vs ghc-9.8.4 in our shell). The Haskell library outputs of both packages live under `lib/ghc-<other-ver>/lib/*.dylib`; their .dylib path strings anchor the foreign GHC in the closure via Nix's reference scanner. On aarch64-darwin this dragged in ghc-9.10.3 (1.40 GB) and ghc-9.10.3-doc (753 MB) — ~2.15 GB of essentially-unused payload. Switch to haskell.nix's `tool` builder (same pattern as cross-js.nix and cross-windows.nix), which builds happy/alex with the shell's `compiler-nix-name`. The resulting library outputs reference the GHC that's already in the closure rather than dragging in a second one. While here: * swap `git` → `gitMinimal` — drops the heavyweight perl-modules and git-doc that aren't useful inside the dev shell (~150 MB cascade). * tool-map.nix: drop `inherit cabalProjectLocal` from happy/alex. They're standard mainline packages and build cleanly from regular hackage; the inherited cabalProjectLocal pinned a head.hackage SHA that was stale and broke fresh evaluations of `(tool "happy")` / `(tool "alex")`. While there, bump happy 1.20.1.1 → 2.1.7 and alex 3.2.7.3 → 3.5.4.0 to match what nixpkgs.haskellPackages was shipping previously, so users see no behavioural change. Measured on aarch64-darwin (ghc98-minimal-ghc): before: 6.12 GB / 228 paths after : 4.00 GB / 196 paths saved : 2.12 GB (34.7% smaller) Top removed paths: ghc-9.10.3 1399 MB ghc-9.10.3-doc 753 MB git-2.51.2 49 MB git-2.51.2-doc 15 MB perl5.40.0-SSLeay/Mozilla/IO-Socket-SSL (gitMinimal cascade) Verified inside the patched shell: $ ghc --version # 9.8.4 $ cabal --version # 3.17.0.0 $ happy --version # 2.1.7 (same as before) $ alex --version # 3.5.4.0 (same as before) $ git --version # 2.51.2
Cosmetic commits, docs and tracing::info optimization
adopt Ledger.Prelude helper lemmas from earlier PR
Make sizes of off-diagonal inputs similar to on-diagonal ones
Add cabal v2-build-based component builder ("v2 builder") (#2513)
* v2 builder: cabal v2-build slicing, dev shell, plan-nix matching
Adds the v2 component builder alongside v1 and a project-level
`builderVersion` switch that picks between them. Where v1 runs
`Setup.hs configure / build` per component, v2 runs `cabal
v2-build` against a per-slice slicing repo and pre-composed
starting store, registers each new unit under
`$out/store/ghc-<ver>[-inplace]/...`, and emits a plan-entry
diff against plan-nix when something diverges.
Highlights:
* `builder/comp-v2-builder.nix` — per-component slice builder.
Drives a per-slice cabal.project (constraints pinned from
plan-nix's `depends`, `extra-packages:` listing every
transitive dep, per-pkg `flags:` / `ghc-options:` /
`configure-options:` blocks) and a per-slice slicing repo
of source tarballs and a `00-index.tar.gz` so cabal's solver
hits a closed package set. Hands the cabal.project plus
the slice's direct dep slices off to `build-cabal-slice.nix`
to actually run cabal.
* `builder/build-cabal-slice.nix` — generic runner the per-
component builder calls into. Composes the starting store
via `lndir` from every dep slice (walks `pkgsHostTarget`
for direct deps and follows each entry's
`$out/nix-support/transitive-deps` for the rest of the
closure, so transitive dep slices stay out of nix-side
`buildInputs`), runs `cabal v2-build`, captures every newly
installed unit back into `$out/store`, writes the slice's
own `nix-support/transitive-deps` for downstream consumers,
and on `dryRunOnly` emits a per-entry diff between cabal's
planned `plan.json` and plan-nix's expectations.
* `builder/compose-store.nix` — `lndir`-based store
composition with the same direct + transitive-deps walk.
Used by `comp-v2-builder` for the `passthru.store` exposed
on each slice and by `shell-for-v2.nix` for the dev shell's
composed dep store.
* `builder/cabal-install-patches/{prune-unreachable-sublibs*,
skip-installed-revdeps-in-completed}.patch` — three
cabal-install patches the v2 slice solver needs to keep its
plan in sync with plan-nix.
* `builder/shell-for-v2.nix` — v2 dev shell. Resolves each
selected component's direct external `component.depends` to
its library (via `haskellLib.dependToLib`, so sublib
references resolve to their sublib slices), composes those
into a starting cabal store via `composeStore` (the
transitive closure is materialised at build time from each
slice's `nix-support/transitive-deps`), exposes the result
via `~/.cabal/store/<ghc>-inplace/` (the default
`exposePackagesVia = "cabal-store"`) or via a
`GHC_ENVIRONMENT`-wrapped ghc (`exposePackagesVia =
"ghc-pkg"`), and merges `passthru.depSlices` from
`inputsFrom` so cross + native shells both see each other's
slices.
* `builder/{default,hspkg-builder}.nix` — dispatch on
`builderVersion`: the per-component derivation at
`hsPkgs.<pkg>.components.<kind>.<n>` is whichever builder
the project selects (no per-component opt-in).
`hspkg-builder.nix` also resolves `homeDependIds` and the
`packageRefersOwnExe` flag from `config.plan-json-by-id`
(the project-level index) so these per-component lookups
are O(log N) attrset hits instead of linear scans over the
install-plan.
* `modules/{component-driver,project-common,shell}.nix` —
`builderVersion`, `crossTemplateHaskellSupport`,
`exposePackagesVia` options.
* `modules/install-plan/configure-args.nix` — filter
`--ghc-option=-hide-all-packages` out of `ghcOptions` for
the v2 builder (cabal injects it on every Setup configure
call, and round-tripping it through cabal.project would
duplicate it in `pkgHashProgramArgs`); extract
`--configure-option=...` entries into a new dedicated
`package.configureOptions` option (declared in
`modules/package-options.nix`) so the v2 builder can emit
them back into its own cabal.project.
* `modules/install-plan/non-reinstallable.nix` — gate the
ghcjs/wasm `ghci`-related `non-reinstallable` set on
`builderVersion != 2`; under v2 the slice solver follows
cabal's install plan literally.
* `lib/check.nix` — `passthru.isSlice` branch that runs the
slice-built exe directly instead of going through v1's
`setup test` pipeline.
* `lib/default.nix` — `uniqueWithNameKey` prefers
`identifier.unit-id` when present so two `foo-1.2.3` slices
with different inputs partition into different buckets.
* `lib/call-cabal-project-to-nix.nix` — set
`CABAL_INSTALLED_PACKAGE_ID_OS = pkgs.stdenv.buildPlatform.parsed.kernel.name;`
on the plan-to-nix derivation so the patched cabal-install
(#2501) actually fires; without the env var the patch is a
no-op.
* `compiler/ghc/default.nix`, `overlays/{bootstrap,tools}.nix`
— pin GHC, `hscolour`, and the boot tools to
`builderVersion = 1` so v2 churn doesn't trigger GHC
rebuilds while v2 is still settling.
* `overlays/{windows,mingw_w64}.nix` — v2-builder-aware
Windows-cross TH wrapper: `mingw_w64.nix` exposes
`wrapGhc :: ghc -> ghc` and `iservRuntimeLibs`;
`overlays/windows.nix` plumbs the build-platform
`runCommand` / `makeWrapper` / `libffi` through to that
module.
* `overlays/haskell.nix` — project-level shell dispatch
(`shellForV1` / `shellForV2`), `crossTemplateHaskellSupport`
plumbing, and `cabalProjectLocal` refactored so the
Windows-host iserv-proxy linker flags can be additive.
* `test/cabal-sublib-shell/` — new test exercising a sublib
consumer in the v2 dev shell. Other test wiring tweaks
(`test/{th-dlls,th-dlls-minimal,cabal-sublib}/default.nix`,
`test/cabal.project.local`, `test/{setup-deps,
shell-for-setup-deps}/pkg/pkg.cabal`, `test/default.nix`)
to keep things passing under v2.
* `ci.nix` — pin `evalSystem` default to `x86_64-linux` so
cross derivations evaluate consistently.
* `docs/dev/builder-v{1,2}.md` (+ `docs/SUMMARY.md` entry) —
design notes for the two builders.
Performance notes:
* `transitiveTarballs` is exposed as the deduped values of
`depTarballsDeduped`. The un-deduped concat (which sticks
every direct dep's full transitive list onto each consumer
unfiltered) grows exponentially with depth in a typical
Haskell graph (every package shares `base` / `bytestring` /
`text` / ...) and materialises multi-GiB blocks in the
evaluator on cardano-wallet-sized projects.
* `homeDepSliceOf` / `depTransitiveTarballsOf` fall through
to any sublib's slice when a dep package defines only
`library <name>` stanzas (no main library — e.g.
`cardano-wallet-ui:{common,shelley}`).
* `propagated` keeps `libs` Windows-only (matching v1):
cross-target slices land in the v2 dev shell's
`inputsFrom`, and unconditionally propagating `libs` would
drag e.g. `pkgs.liburing` from a Linux-target slice into a
Darwin consumer's `pkgsHostTarget`. Each slice gathers its
own transitive sysLibs (deduped) into `extraBuildInputs`
via `transitiveDepLibs` instead.
* v2 builder: open the cardano-wallet dev shell end-to-end
A cluster of fixes that together let the v2 dev shell evaluate, build,
and reuse prebuilt slices for cardano-wallet on aarch64-darwin. Most
fixes are independent in spirit but interact at the slice level — they
are bundled here to keep the cardano-wallet shell green in a single
commit.
- Sublib reachability env var (`HASKELLNIX_EXTRA_SUBLIB_SEEDS`)
threaded through both the solver-side and install-plan cabal-install
patches. Slices that target a sublib (or transitively depend on
one) seed the patched reachability walk from `pkgLibDepClosure` so
unrelated sublibs (e.g. `lib:testlib`'s deps) stay pruned.
- Source-repository-package handling in slices. Each
`pkg-src.type = "source-repo"` package gets a per-slice minimal git
repo (`git init -b minimal && git add . && git commit`) wrapped
around `${src}` and emitted as a `source-repository-package` block
in the slice's `cabal.project` — the same shape
`lib/call-cabal-project-to-nix.nix` produces at project level — so
cabal hashes the same source bytes plan-nix saw and the slice's
UnitId matches. Build-tools (`alex`, `happy`, `hsc2hs`, ...)
composed via `transitiveBuildToolSlices` so consumers find them in
the cabal-store instead of rebuilding.
- Plan-nix flag honouring for source-repo packages. Module-level
flag overrides (e.g. cardano-wallet's `flags.release = true`) don't
reach cabal at plan time, so plan-nix records cabal-file defaults.
`flagBlockFor` now reads from plan-json for source-repo pkgs so the
slice's `pkgHashFlagAssignment` matches plan-nix.
- Custom-build packages skip the UnitId check. Plan-nix carries a
single shared `id` per Custom-build package; cabal-install splits
them into per-component UnitIds that can never match. Detected via
missing `component-name` on the plan entry.
- `propagatedBuildInputs` for `depSlices` (was `buildInputs`) so
pkg-config deps and other propagated inputs chain transitively
via stdenv. Splice handles the cross-compilation case for normal
nixpkgs deps; slice $outs themselves don't auto-swap but cardano-
wallet's native shell doesn't trip that.
- `cp -rL` for local-package tarballs to inline out-of-bounds
symlinks like cardano-wallet's `lib/wallet/specifications ->
../../specifications` that cabal-install 3.16+ rejects as
[Cabal-7125] "Unsafe link target in tar archive".
- `$out/store` cleanup at end of installPhase. When the expected
UnitId is known, keep only `<uid>/`, `package.db/<uid>.conf` and
`lib/libHS<uid>-*` — `rm -rf $ghcDir` drops everything else
(including the lndir-composed dep symlink tree, which on a deep
graph was 10k+ entries that fixupPhase + NAR serialisation walked
for nothing). Falls back to `find -type l -delete` when the UnitId
isn't known (source-repo or `style: "local"`). Cache files
(`package.cache{,.lock}`) dropped from every slice — stale on
arrival downstream and a major source of "Keeping existing link"
spam at lndir time.
- `find -type d` instead of `ls -d */` for the unitdirs-before
snapshot. bash expands `*/` into args including OS-prefix
unit-ids (`-clsss-1.8.0.1-...`), and `ls` interprets the leading
`-` as flags. Same root cause as the earlier `grep -qx --` fix.
- v2 shell: walk through local packages transitively, collecting
external deps at every step. Local packages are excluded from the
composed cabal-store so cabal compiles them on demand from the
user's tree; their (transitive) external deps go in. Build-tool
exes that resolve to local packages are similarly excluded.
- v2 shell: `pkgs.gitMinimal` on PATH so `git --version` works
inside the shell. On Darwin the apple-sdk overlay sets
`DEVELOPER_DIR` to the SDK path (no tools), so `/usr/bin/git`'s
xcrun shim fails with "tool 'git' not found"; nix-managed git
bypasses the shim.
- Slice cabal: `--jobs=$NIX_BUILD_CORES` (capped at 4, mirrors v1)
on the `cabal v2-build` invocation, which passes through to
`Setup build -jN` for ghc per-module parallelism. Build-phase
flag, so it stays out of `pkgHashConfigureOptions` and UnitIds
remain stable.
* v2 builder: pass `-jN` through to `Setup build` via env var
cabal-install 3.16's `setupHsBuildFlags` deliberately leaves
`buildNumJobs = mempty` (TODO: [nice to have] upstream), so neither
`cabal v2-build --jobs=N` nor `--ghc-options=-jN` actually parallelise
per-module compilation:
* `--jobs=N` is package-level (one slice = one package) and is
*not* threaded through to Setup build.
* `--ghc-options=-jN` would land in `pkgHashConfigureOptions` and
fork the slice's UnitId from plan-nix.
`setup-build-num-jobs-env.patch` adds a small read of
`HASKELLNIX_BUILD_NUM_JOBS` at the call site that constructs
BuildFlags, feeding it into `buildNumJobs`. Build-phase flag, so
UnitIds stay stable. build-cabal-slice.nix exports the env var
capped at 4 (mirrors v1's `-j$(($NIX_BUILD_CORES > 4 ? 4 : ...))`),
so `Setup build` invokes `ghc --make -j4` and per-module compilation
parallelises again.
Verified end-to-end: io-classes slice's GHC response file now shows
`-j4` while the captured UnitId still matches plan-nix's
`-clsss-1.8.0.1-14f3d66e`.
* v2 dev shell: pre-build SRPs, filter project pkgs, dedup by unit-id
Three fixes to `builder/shell-for-v2.nix` so the shell's cabal
store matches the user's intuition (project packages built from
the working tree, everything else pre-built):
1. Switch the default `packages` from `selectLocalPackages` to
`selectProjectPackages`, and rename `pkgIsLocal` →
`pkgIsProject` to use `isProject` instead of `isLocal`.
`isLocal` covers source-repository-packages too, but SRPs are
pinned upstream code the user doesn't iterate on — they belong
in the shell's pre-built store, not excluded from it.
2. Filter project-package exes out of `buildToolDrvs`. Without
this, any project exe listed as `build-tool-depends` of another
project package gets pre-built and dragged into the shell
closure, along with all of its lib slices' deps (~25 stray
slices in the cardano-wallet shell). Mirrors v1's
`removeSelectedInputs` and the existing `ownBuildToolSlices`
filter.
3. Dedup the `projectPkgClosure` walk by `identifier.id` (cabal
unit-id), not `identifier.name`. v2 plan-nix splits each
unit-id component into its own `hsPkgs` entry — components are
spread across siblings — so deduping by package name dropped
every sibling after the first and lost their deps (e.g. the
`unit` test's `x509`/`pem` deps when `test-common` was visited
first).
* test/cabal.project.local: bump head.hackage SHA
The `--sha256` pin for the head.hackage tar no longer matched
upstream — CI was failing with `hash mismatch in fixed-output
derivation`. Update to the current sha256 reported by nix.
* v2 dev shell: exclude only `selectedPackages`, not all project pkgs
The previous commit treated every project package as "iterated on
from the working tree" and excluded them all from the shell's
cabal store. That broke `tests.cabal-sublib-shell.run`, which
intentionally selects just `consumer` and expects `provider` (a
sibling project package) to be pre-built — so an unpatched cabal
inside the shell can reuse provider's lib/sublib instead of
rebuilding from source.
Mirror v1's `removeSelectedInputs` semantics: only exclude packages
in `selectedPackages` itself. With the default
`packages = selectProjectPackages` every project pkg is selected
(so the cardano-wallet UX is unchanged); with an explicit
`packages = ps: [ ps.foo ]`, only `foo` is excluded and sibling
project pkgs land in the store.
Also drops the project-pkg closure walk — `selectedPackages`
already enumerates every unit-id fragment, so a straight
`concatMap getAllComponents` covers all components without the
walk.
* test/shell-for-setup-deps: use `ghc-pkg` exposure mode
The test runs `runghc conduit-test.hs` inside the v2 shell; that
needs `Conduit` visible to plain `ghc`/`runghc`. Default
`exposePackagesVia = "cabal-store"` only seeds `~/.cabal/store`
(which `cabal v2-build` reads), so plain ghc still misses the
setup-deps. Switch to `"ghc-pkg"` so the wrapped ghc stacks the
composed package.db via `GHC_ENVIRONMENT`.
* test/cabal-simple-prof: enable profiling via cabalProjectLocal
The test sets `enableProfiling = true` / `enableLibraryProfiling
= true` via haskell.nix modules. Under v1 those translate
directly to per-component `--enable-profiling` configure flags,
but under v2 (now the default) the slice reads its toggles from
plan.json's recorded `configure-args` — and plan.json was
generated from cabal.project alone, where neither flag is set.
The slice therefore built without `-prof`, and `+RTS -p` failed
with "the flag -p requires the program to be built with -prof".
Inject `profiling: True` / `library-profiling: True` at project
level via `cabalProjectLocal` so plan-nix records
`--enable-profiling` / `--enable-library-profiling`, matching the
slice's actual build and keeping the slice's UnitId
reproducible. The module-level overrides are kept so v1 still
builds with profiling too.
* v2 builder: support per-package configure-args
Previously `projectConfigPragmas` read configure-args off the
first configured plan entry and emitted them under a single
`package *` block, on the assumption that "the same flags appear
in every configured plan entry's configure-args". That holds for
project-wide toggles (--enable-optimization, --disable-shared,
...) but breaks the moment a user sets something per-package —
e.g. `package cabal-simple\n profiling: True`. The setting only
landed on cabal-simple's plan entry; if the first configured
entry was a transitive dep, the slice's cabal.project never saw
`profiling: True` and the exe built without `-prof`.
Group plan entries by `pkg-name`, take the union of pragmas
across each pkg's units (cabal.project only supports per-package
granularity), then split into:
* `package *` — pragmas common to *every* pkg-name. The slice's
`cabal v2-build` resolves transitive hackage deps fresh, so
these have to land project-wide for the deps' UnitIds to line
up with plan-nix.
* `package <name>` — for each pkg-name with pragmas extending
the baseline (e.g. `package cabal-simple` getting
`profiling: True` from
`packages.cabal-simple.enableProfiling = true` mirrored into
cabal.project).
`tests.cabal-simple-prof.run` now uses the per-package shape that
mirrors haskell.nix's modules:
package *
library-profiling: True
package cabal-simple
profiling: True
* v2 builder: run hpack on local hpack-using packages
When a project has `supportHpack = true` and a local package
ships only `package.yaml` (no `.cabal`), v1 ran hpack at the
component-build phase to generate the `.cabal`. v2 never ran
it, so the v2 source tarball had no `.cabal` and the
`v2-exe-repo` pre-build step failed with `tar:
<pkg>-<ver>/<pkg>.cabal: Not found in archive`.
Thread `cabal-generator` through `hspkg-builder.nix` to
`comp-v2-builder.nix` and run hpack inside the staged source
dir before tarballing, mirroring v1's
`comp-builder.nix:485` invocation. Skipped when the package
isn't local (hackage tarballs already contain a generated
`.cabal`) or when `cabalFile` is set (e.g. an X-revision from
`package-description-override`, which provides its own `.cabal`).
Verified against `tests.cabal-hpack.run`.
* test/cabal-sublib: restore ghcjs `broken` marker
Re-enables the `broken = isGhcjs && ghc >= 9.6.1` guard that
commit 19b9a5110 commented out while bringing up v2. The
underlying failure is in ghcjs/emscripten wasm-ld ("section too
large" linking the `-O`-optimized C-backend objects), which
predates v2 and isn't a slicer issue. Skip the test on ghcjs
again so CI doesn't fail on a pre-existing upstream limitation.
* test: move HsOpenSSL pointer-types workaround to cabal.project.local
`packages.HsOpenSSL.ghcOptions` previously held a
`-optc=-Wno-incompatible-pointer-types` workaround. v2's slices
read configure-args from plan.json; module-level `ghcOptions`
never reach plan-nix's plan.json, so under v2 the slice picked up
the flag (via comp-v2-builder's per-package ghcOptions block) but
plan-nix did not — and the resulting UnitIds diverged
(`HsOpnSSL-0.11.7.10-9ebdbccd` expected vs `-ecc34d19` produced).
Move the workaround into `test/cabal.project.local` under
`package HsOpenSSL ghc-options:` so plan-nix and the slice agree.
Drop the now-unneeded `HsOpenSSL` entry from `package-keys` in
`test/modules.nix`.
Verified against `tests.exe-dlls.build`.
* test/shell-for: use `ghc-pkg` exposure for runghc
The test runs `runghc conduit-test.hs` against `env.ghc` /
`envDefault.ghc`. With v2's default
`exposePackagesVia = "cabal-store"` only `~/.cabal/store` is
seeded; plain `runghc` doesn't read the cabal store, so it failed
with "Could not find module 'Conduit'". Switch the three shells
to `"ghc-pkg"` so `env.ghc` is wrapped to stack the composed
package.db via `GHC_ENVIRONMENT`. Mirrors the earlier fix in
`tests.shell-for-setup-deps`.
* v2 dev shell: speed up haskell-nix-cabal-store-sync
The script ran a per-conf `diff -q` and a per-unit `diff -qr` on
every shell entry — for cardano-wallet's ~240 slices that meant
forking hundreds of `diff` invocations and walking each unit's
file tree. Two short-circuits:
* Per-composedStore marker file at
`~/.cabal/store/.haskell-nix-shell-markers/<basename-of-src>`,
written after a successful run. On re-entry the marker is
present and the script exits before the scan. Different
shells have distinct basenames, so alternating shells don't
invalidate each other's markers.
* Readlink fast-path in the scan: confs and lib files are
installed as symlinks to `$src/...`, and unit dirs are lndir
trees of symlinks under `$src/$ghcName/$unitId/`. When the
target is already in the right shape, skip the per-file `diff`
fork. Only when the cheap check fails does the script fall
back to `diff -q` / `diff -qr` to detect genuine conflicts.
Measured on cardano-wallet's shell (~240 slices, fresh CABAL_DIR):
first run 24.5s, second run 0.012s.
* v2 builder: surface HPC artefacts and src dir for cover.nix
Three incremental improvements toward making `lib/cover.nix` work
against v2 lib/test slices. The end-to-end coverage test still
fails because v2's lib slices use a hashed UnitId
(`pkgb-0.1.0.0-<hash>`) while a sibling test slice rebuilds the
lib inplace and emits `.tix` referencing `pkgb-0.1.0.0-inplace`,
so HPC can't match them up. That alignment is a deeper change;
land the supporting plumbing first:
* Add `srcSubDir` / `srcSubDirPath` to v2 slice passthru so
`lib/cover.nix:19`'s `map (l: l.srcSubDirPath) mixLibraries`
no longer hits "attribute missing".
* Library slices now copy each `extra-compilation-artifacts/hpc/<way>/{mix,tix}`
subdir up to `$out/share/hpc/<way>/{mix,tix}/<pkg>-<ver>/`
(the predictable name `lib/cover.nix` and the cover-report
tests expect — v1 does this too in `comp-builder.nix:831`).
* v2's `lib/check.nix` branch copies `<exeName>.tix` from the
test run to `$out/share/hpc/vanilla/tix/<exeName>/`, mirroring
v1's `lib/check.nix:119`.
* v2 builder: error on `.profiled` with migration hint
v1 slices provided `.profiled` as an overlay rebuild with
`enableLibraryProfiling = true`. v2 reads configure-args from
plan.json, so an overlay would emit `--enable-profiling` toggles
that plan-nix doesn't know about and the slice's UnitId would
diverge.
Replace the (missing) attribute with a `throw` that points users
at `cabal.project` / `cabalProjectLocal`:
package <pkgname>
profiling: True
library-profiling: True
so plan-nix records the toggles and the slice's UnitId stays
aligned. Set the `throw` at both the top level and inside
`passthru` because mkDerivation only lifts passthru → top level at
derivation creation time; post-hoc `// { passthru = ... }` doesn't
re-lift.
Adds `docs/dev/profiling.md` with the migration recipe.
* configure-args: pick up profiling/coverage from plan.json
Plan-to-nix's `modules/install-plan/configure-args.nix` already
translates `--ghc-option=` and `--configure-option=` entries from
plan.json's per-pkg `configure-args` into haskell.nix module
options. Extend it to also pick up the `--enable-{profiling,
library-profiling, coverage}` toggles so v1's `comp-builder`
(which reads `enableProfiling`, `enableLibraryProfiling`,
`doCoverage` straight off the component) honours
`package <pkg>\n profiling: True` set in cabal.project — without
needing module-level overrides.
v2 already reads these from plan.json directly via its own
`projectConfigPragmas`; the picked-up values are merely
consistent there.
Migrate the `tests.{exe,exe-lib,th}-dlls.{check-,build-}profiled`
variants to a sibling project whose `cabalProjectLocal` enables
profiling — the v2 builder no longer ships `.profiled` as an
overlay rebuild (see `docs/dev/profiling.md`).
* v2 builder: align slice/check derivation names with v1
Drops the `cabal-slice-` prefix and reorders the slice's `name`
attribute from `<pkg>-<ver>-<ctype>-<cname>` to v1's shape
`<pkg>-<ctype>-<cname>-<ver>` (mirrors `comp-builder.nix:268`).
Same for the auxiliary `check-*` and `store-*` derivations.
Callers that hardcoded v1 derivation names — most prominently
`tests.coverage.run`, which checks for
`tix/pkgb-test-tests-0.1.0.0-check/tests.tix` — keep working
without per-test edits when projects flip
`builderVersion = 1 → 2`.
Also surface the lib slice's `.mix` files under
`<pkg>-<ver>-inplace/<Module>.mix` so they line up with the
inplace UnitId that test-slice-built `tests.tix` files reference
(`Tix [ TixModule "<pkg>-<ver>-inplace/<Module>" … ]`); the .mix
content itself is byte-identical between the lib slice's
hash-named UnitId build and the test slice's inplace rebuild.
Move the coverage-test's `doCoverage` modules into
`cabalProjectLocal` (`package <pkg>\n coverage: True`) so v2's
plan-nix records `--enable-coverage` and the slice actually
produces .mix/.tix output. The module-level overrides are kept
for the v1 builder.
Verified against `tests.coverage.run`.
* v2 builder: drop \`.jsexe/all.js\` exeExt under cabal v2-build
v1 (Setup.hs install) for ghcjs preserves the
\`bin/<exe>.jsexe/all.js\` directory layout, which is why
\`comp-builder.nix:450\` appends \`.jsexe/all.js\` to the exe name
for \`isGhcjs && ghc < 9.8\`. v2 builds via \`cabal v2-build\`,
whose install step bundles the \`.jsexe/\` contents into a single
self-contained \`#!/usr/bin/env node\` script at \`bin/<cname>\` —
there is no \`.jsexe/\` directory in the slice's output. Use
the bundled-file path so v2's \`exePath\` / \`find\` lookup land
on the file cabal actually produced.
Verified against \`aarch64-darwin.unstable.ghc967.ghcjs.hello\`
(slice surfaced \`bin/hello\` cleanly, no placeholder fallback).
* v2 builder: trim dist-newstyle/ from slice $out
The slice's `$out/dist-newstyle/` carried cabal's source tarballs
and the build tree — hundreds of MB to GB per slice for nontrivial
projects. Nothing downstream of a successfully-built slice reads
it: subsequent slices only pull from `$out/store/`, and the
diagnostic `checkAgainstPlan` is a separate derivation with its
own dist-newstyle.
Trim it at the end of `installPhase`, after
`comp-v2-builder.nix`'s test/bench install step (which does need
to find the unpinged binary in `dist-newstyle/build/.../<exe>`).
Lift `cache/plan.json` to `$out/plan.json` so it stays available
for human debugging — the rest of `cache/` is internal.
Verified on the ghc967.ghcjs.hello slice: $out shrinks from
~7.9GB to ~1MB, with `bin/`, `store/`, `plan.json`, `unit-ids`,
and `nix-support/` retained.
* test/with-packages: use \`project.shellFor\` instead of \`comp.shell\`/\`comp.env\`
v2 slices don't expose v1's per-component \`.shell\` / \`.env\`
attributes — \`shell\` is provided at the project level via
\`project.shellFor\`, and that mode covers what this test needs
(a wrapped \`ghc\` / \`runghc\` that can see the package's deps).
\`exposePackagesVia = "ghc-pkg"\` makes \`shell.ghc\` a wrapped
GHC stacking the composed package.db via \`GHC_ENVIRONMENT\`, so
\`runghc ./Point.hs\` and \`ghc Point.hs\` resolve the deps the
same way v1's \`library.env\` did.
Works under both v1 and v2 — no per-component shell required.
* test: migrate `.profiled` callers to sibling cabal.project
v2 slices no longer ship `.profiled` as an overlay rebuild — see
`docs/dev/profiling.md`. Migrate the remaining tests that
referenced `…components.<kind>.<name>.profiled`
(`js-template-haskell`, `th-dlls-minimal`, `gi-gtk`) to a sibling
project whose `cabalProjectLocal` enables profiling, matching the
shape already used by `exe-dlls` / `exe-lib-dlls` / `th-dlls`.
Expose each new project's `plan-nix` under a distinct
`ifdInputs` key so the materialised plan-nix expressions are
covered by CI:
plan-nix — non-profiled (default)
plan-nix-ei — externalInterpreter variant (th-dlls /
th-dlls-minimal)
plan-nix-profiled — profiled
plan-nix-profiled-ei — profiled + externalInterpreter
* plan-nix: gate `-inplace` on GHC ≥ 9.8
GHC 9.8 added an `-inplace` suffix to its boot-package UnitIds
(`base-4.19.2.0-inplace` vs `base-4.18.3.0` on 9.6) and started
emitting a `Project Unit Id` field in `ghc --info`. The dummy
ghc/ghc-pkg in `lib/call-cabal-project-to-nix.nix` was hardcoding
both, so cabal computed UnitIds against the dummy with
`-inplace` even on GHC 9.6. When the slice's real ghc 9.6 then
returned ids without `-inplace`, the slice's UnitId for any
package depending on a boot package (`colour` ↔ `base`) diverged
from plan-nix and the slice failed its UnitId check.
Verified empirically that `-inplace` appears starting at GHC 9.8:
ghc967 → id: base-4.18.3.0
ghc984 → id: base-4.19.2.0-inplace
ghc9103 → id: base-4.20.2.0-inplace
ghc9124 → id: base-4.21.2.0-inplace
ghc9141 → id: base-4.22.0.0-inplace
Make both the `Project Unit Id` field and the `-inplace` suffix
conditional on `versionAtLeast ghc.version "9.8"`.
Verified against `tests.shell-for.env` on ghc967 (which exercises
the colour slice that was failing in CI).
* v2 builder: expose `.doc` via sibling `cabal v2-haddock` slice
Under v1 every component's `.doc` was a sibling Setup haddock
derivation that shared the lib's UnitId. Under cabal v2-build
this no longer holds: `cabal v2-haddock` flips
`elabBuildHaddocks` (and the haddock-html / haddock-hscolour /
... family) on every unit's `ElaboratedConfiguredPackage`, which
all land in `pkgHashConfigInputs`. Calling `cabal v2-haddock`
against a plan that didn't already have `documentation: True`
forks every UnitId in the closure and triggers a from-source
rebuild.
Round-tripping `documentation: True` through plan.json's
`--ghc-option=-haddock` / `configure-args.nix` /
`ghc-options: -haddock` is NOT equivalent: the ghc-option keeps
haddock comments in `.hi` files but doesn't set the haddock-config
booleans, so the slice's `pkgHashConfigInputs` diverges from
plan-nix's and the dep closure's UnitIds fork (observed on
OneTuple in `tests.sublib-docs`: plan-nix `9a847723` vs slice
`f546bd36`).
Approach:
* `comp-v2-builder.nix` detects per-package `--ghc-option=-haddock`
in plan.json (the `documentation: True` signal cabal-install
surfaces) and emits `package <pkg>\n documentation: True\n`
in the slice's cabal.project for every documented package.
`-haddock` is filtered out of the per-pkg `ghc-options:` block
so cabal doesn't see it twice in `pkgHashGhcOptions`.
* Each library slice exposes `.doc`, a sibling derivation that
runs `cabal v2-haddock` against the already-built unit (no
closure rebuild). `.doc` throws with a migration hint when
documentation isn't in the project's plan-json — that's the
only shape where the UnitIds align.
* Doc slices propagate `(map d: d.doc)` for `docEnabled` deps
only, so cross-package hyperlinks resolve. Mixed projects
(some packages docs, others not) keep working because non-doc
deps come in as plain slices.
* `build-cabal-slice.nix` keeps cabal's native unit-dir layout
(`$out/store/<ghc>/<unit-id>/share/doc/html/`) so doc slices
`lndir` into `~/.cabal/store/` as drop-in replacements, and
cross-package hyperlinks (absolute
`file:///nix/store/<doc-slice>/store/<ghc>/<dep-uid>/...`)
resolve back into the slice's own tree. Non-target unit
haddocks are stripped from `$out` to keep each slice lean —
deps' html lives in the deps' own `.doc` slices.
`docs/dev/haddock.md` documents the v2 semantics, the
`documentation: True` requirement, and why there's no
`slice.haddockDir` (local plan-nix UnitIds use `<pkg>-<ver>-inplace`
form while the slice's cabal-store uses cabal's mangled hash form,
so there's no eval-time-stable html path — callers `find` it
under the doc slice).
Verified `tests.sublib-docs.run` builds Lib.html and Slib.html
under `slice.doc`, and OneTuple's UnitId in plan.json matches
plan-nix's recorded id.
* v2 builder: fix `ghcShim` collision when cross GHC ships unprefixed tools
GHC 9.14.1's `armv7a-android` cross GHC ships *both*
`<prefix>deriveConstants` and an unprefixed `deriveConstants` in
its `bin/` (the latter for build-host use). `ghcShim`'s
single-pass loop iterated `${ghc}/bin/*` alphabetically, hit
`armv7a-...-deriveConstants` first, and the case branch
synthesised an unprefixed-fallback alias
`$out/bin/deriveConstants -> <prefix>deriveConstants` (the
`[ -e ]` guard was for that fallback, not the raw link). When
the loop later reached the real `deriveConstants`, the raw
`ln -s "$f" "$out/bin/$base"` crashed with "File exists".
Earlier cross GHCs only shipped `<prefix>deriveConstants`, so
the fallback was the sole producer of `$out/bin/deriveConstants`
and never collided. GHC 9.14.1 added the unprefixed sibling and
exposed the race.
Switch to a two-pass shape: pass 1 links every source bin/ entry
under its own name, pass 2 synthesises unprefixed aliases only
for prefixed names that have no real unprefixed sibling. Real
files always win; aliases only fill genuine gaps.
Same fix in both `builder/build-cabal-slice.nix` and
`builder/shell-for-v2.nix` (which carries an identical shim for
the dev shell's cross-cabal wrapper).
* Replace post-plan ghc.src override with project-level useLocalGhcLib
`modules/configuration-nix.nix` used to unconditionally `mkForce`
`packages.ghc.src` to a symlinkJoin of `(configured-src + generated)`
under `compiler/`, redirecting `lib:ghc`'s source to the local GHC
tree *after* plan-nix had been computed against hackage's
`ghc-X.Y.Z.tar.gz`. v1 (Setup.hs) didn't care — it builds whatever
`src` it's given. v2 forks the slice's UnitId from plan-nix's
recorded one (the slice rebuilds from a different source than the
planner saw) and the slice fails its UnitId check.
Replace with an opt-in project-level flag, `useLocalGhcLib`, that
exposes the GHC compiler tree to the planner up-front. Mechanism
differs by project type:
* Cabal projects (modules/cabal-project.nix) inject a
`source-repository-package` block + `allow-boot-library-installs:
True` into `cabalProjectLocal`, with an `inputMap` entry keyed
by `<url>/<ref>` (string-context-stripped) so haskell.nix
short-circuits the `builtins.fetchGit` path. Plan-to-nix and
the v2 slice both see the same wrapped repo, cabal hashes the
same content into `pkg-src-sha256`, and UnitIds align.
* Stack projects (modules/stack-project.nix) re-add the
`packages.ghc.src` override as a contributed module, gated on
`useLocalGhcLib`. Stack-to-nix's input shape doesn't fit the
cabal source-repo path; instead we lean on stack only supporting
v1 for now (`builderVersion = mkForce 1` in stack-project.nix's
config) — v1 doesn't enforce UnitId alignment, so the post-plan
swap is fine.
The option itself lives in `modules/project-common.nix` so both
project types see it without duplication.
`builder/comp-v2-builder.nix` emits `allow-boot-library-installs:
True` in the slice's cabal.project whenever the target or any non-
pre-existing lib dep is on cabal-install's hard-coded
non-reinstallable list (`ghc`, `template-haskell`, `Cabal`,
`Cabal-syntax`, `ghc-prim`, `ghc-bignum`, `ghc-boot`,
`ghc-boot-th`, `ghc-heap`, `base`, `ghci`, `ghc-internal`, `rts`).
Without it the slice's solver rejects the source instance with
"constraint from non-reinstallable package requires installed
instance" once `ghc` is being source-built.
`test/ghc-lib-reinstallable/cabal.nix` and
`test/ghc-lib-reinstallable/stack.nix` opt in via
`useLocalGhcLib = true`. The stack test's resolver is bumped to
`nightly-2026-05-03` (latest known to the pinned stackage.nix at
the time of this commit).
Verified end-to-end:
* `tests.ghc-lib-reinstallable-cabal.run` (v2, ghc9141) — passes
* `tests.ghc-lib-reinstallable-cabal.run` (v1, ghc9141) — passes
* `tests.ghc-lib-reinstallable-stack.run` (v1, ghc9124) — passes
* cabal-project: inject `executable-static: True` for musl hosts
Plan-to-nix's cabal-install records `--disable-executable-static`
in `configure-args` for every component when the project hasn't
explicitly enabled it. v1's `builder/comp-builder.nix:384`
papered over this by injecting `--ghc-option=-optl=-static` (and
`-optl=-pthread`) at comp-builder time — outside plan.nix's view.
v1 doesn't enforce UnitId alignment with plan.json, so the
post-plan flag insertion is harmless there.
Under v2 the slice mirrors plan.json's `configure-args` exactly,
so without something at the project level the slice links
dynamically and the `tests.c-ffi.run` musl assertion (`grep "not
a"` on glibc-ldd output) fails.
Inject `executable-static: True` into `cabalProjectLocal` when
`stdenv.hostPlatform.isMusl`. Plan-to-nix then records
`--enable-executable-static`, v2's
`comp-v2-builder.nix:projectConfigPragmas` round-trips it through,
and cabal links the executable statically. v1 is unaffected — its
post-plan `-optl=-static` injection still fires, redundant but
harmless.
Verified by running `tests.c-ffi.run` on the
`x86_64-linux.unstable.ghc9141.musl64` jobset
(commit `d027fbe4e` + this patch in a fresh worktree).
* dummy-ghc: add Android branch matching real cross-ghc capabilities
`dummy-ghc` is the eval-time stand-in cabal-install runs against
during plan-to-nix. Its `--info` output shapes plan.json's
per-unit `configure-args` (which feed `pkgHashConfigInputs` and
therefore the UnitId). When the dummy reports different
capabilities than the real cross-ghc the slice rebuilds with,
plan-nix and slice compute different UnitIds and the slice's
expected-package check fails.
The "otherwise" branch (Linux / Darwin / native) reports
`Support shared libraries: YES`, `GHC Dynamic: YES`, RTS ways
including the full `_dyn` family, and `Stage: 2`. Real Android
cross-ghc (`aarch64-unknown-linux-android-ghc 9.14.1`) is a
stage-1 NDK build with no `_dyn` ways and no `Support shared
libraries` field at all (its `GHC Dynamic` is `NO`). Falling
through to "otherwise" made plan-nix record `--enable-shared`
for Android packages while the slice's real ghc silently flipped
to `--disable-shared`, forking the UnitId on
`pkgHashSharedLib`.
Add an explicit Android branch. Reference values cross-checked
against `aarch64-unknown-linux-android-ghc --info` on the live
9.14.1 cross GHC derivation; key fields:
* Support dynamic-too: YES (GHC's flag, kept like real ghc)
* GHC Dynamic: NO (was YES — drove --enable-shared)
* RTS ways: no `_dyn` family
* Stage: 1
* No `Support shared libraries` field (cabal interprets
absence as no-shared-libs, matching real ghc)
Verified `tests.extra-hackage` slices for
`x86_64-linux.unstable.ghc9141.aarch64-android-prebuilt` no
longer fail the slice's UnitId-alignment check. (The `.run`
step still fails because qemu-aarch64 can't load Android's
`/system/bin/linker64` to actually exec the binary — that's a
pre-existing runtime issue, not a v2 alignment problem.)
For musl, real and dummy ghc already agree
(`Support dynamic-too: YES, GHC Dynamic: YES`); the
`executable-static: True` injection in
`modules/cabal-project.nix` stays — it's a user-opt-in flag,
not capability-derived from `ghc --info`.
* shellFor: route through buildPackages so cross targets evaluate
`shellFor` (both v1 and v2) ran into "no C compiler provided for
this platform" under cross targets where the host stdenv has no
cc — most visibly ghcjs, also wasm and android-prebuilt. Three
distinct issues, all fixed here:
1. `mkShell` itself was `pkgs.mkShell` (host-stdenv-bound).
`pkgs.bashInteractive`'s eval reads `stdenv.cc.isClang`, and
under ghcjs cross there is no cc → throw. Pass
`mkShell = pkgs.buildPackages.mkShell` to both shellForV1 and
shellForV2 so the shell drv lives on the build platform
regardless of the host (the user opens the shell on their
build host anyway).
2. `pkgs.runCommand` was building `packageEnv` and `wrappedGhc`
(the wrapped GHC the shell exports as `shell.ghc`) against
the cross stdenv. Once these landed in the shell's
`nativeBuildInputs`, mkShell's dep-splicing eventually
re-evaluated the cross stdenv's bash via setup hooks, hitting
the same cc.isClang. Switch both to
`pkgs.pkgsBuildBuild.runCommand` and `pkgs.pkgsBuildBuild.makeWrapper`
so the wrappers themselves are build-platform drvs. (Native
builds are unaffected — `pkgsBuildBuild == pkgs` there.)
3. `store = composedStore` was a top-level attr to mkShell.
Recent nixpkgs's `mkDerivation` folds unknown top-level attrs
into `env` and type-checks each value, and `isDerivation
composedStore` forces evaluation of the cross stdenv's bash
the same way. Move `store` into `passthru.store` — mkDerivation
lifts passthru into the result drv anyway, so `shell.store`
continues to resolve.
Verified `tests.with-packages.test-shell` now evaluates under both
the `aarch64-darwin.unstable.ghc9141.ghcjs` (cross) and `.native`
jobsets, and `shell.store` still resolves on both.
* dummy-ghc: extend Android branch to cover pkgsStatic
The Android dummy-ghc branch added in 491a91d13 reports a stage-1
GHC built without dynamic support: no `_dyn` RTS ways,
`GHC Dynamic: NO`, no `Support shared libraries` field. The same
shape applies to nixpkgs's `pkgsStatic` (the haskell.nix `static`
jobset) — its real GHC is also built without dynamic support.
The only difference is `Stage`: Android cross is stage-1, the
static GHC is stage-2.
Without this branch, plan-to-nix records `--enable-shared` for
static-target packages while the slice's real ghc silently flips
to `--disable-shared`, forking the UnitId on `pkgHashSharedLib`
and breaking the slice's expected-package check.
Extend the Android branch's predicate to
`isAndroid || isStatic` and emit the right `Stage` per platform.
Reference: `pkgsStatic.haskell-nix.compiler.ghc9141 --info` on
the live `x86_64-unknown-linux-musl` derivation.
Verified: `tests.js-template-haskell.check` on
`x86_64-linux.unstable.ghc9141.static` builds end-to-end (slices
align, the test exe links statically as expected, the `.check`
derivation completes).
* dummy-ghc: extract to its own file + add cross-compiling field + test
Move the eval-time `dummy-ghc` script construction from
`lib/call-cabal-project-to-nix.nix` to a standalone
`lib/dummy-ghc.nix` so it can be tested independently.
Add a new test `tests.dummy-ghc-info` that diffs `dummy-ghc --info`
against the real GHC's `--info` (after stripping nix-store paths
and a hand-curated list of fields cabal-install does not consult
for elaboration / unit-id hashing). The test fails on any
remaining divergence, surfacing where `dummy-ghc.nix` needs to
mirror real GHC more closely.
Two divergences caught and fixed by the new test on the native
ghc9141 jobset:
* Real GHC always emits `("cross compiling","YES"/"NO")`; dummy
didn't. Cabal-install reads this field to decide whether to
apply cross-toolchain detection. Add it, gated on
`buildPlatform.config != targetPlatform.config`.
* Real GHC 9.14.1 omits the legacy `Support shared libraries`
field on native targets — cabal infers shared-lib support from
`Support dynamic-too` + `RTS ways`. Dummy was emitting
`("Support shared libraries","YES")` in its "otherwise" branch,
creating a phantom field real GHC doesn't have. Drop it.
Plus minor cosmetic: dummy emitted the alist's first entry as
`("target os", "OSDarwin")` (with a space after the comma); real
GHC omits the space. Tighten dummy to match.
`tests.dummy-ghc-info` is registered alongside other tests in
`test/default.nix` so it runs across every cross-target jobset
(armv7a-android, x86_64-musl, ghcjs, wasi, mingwW64, …). Future
divergences land as test failures rather than silent UnitId forks
between plan-nix and the v2 slice.
* dummy-ghc: report Host=buildPlatform; fix ghcjs/wasm interpreter
Driven by `tests.dummy-ghc-info` failures. Two fixes:
* Real cross-GHC reports `Host platform = buildPlatform` (where
ghc itself runs), NOT the cross-target platform. `pkgs.stdenv.hostPlatform`
in a cross-pkgs context IS the cross target, so the previous
`Host platform = pkgs.stdenv.hostPlatform` was wrong. Use
`buildPlatform` for both `Build platform` and `Host platform` —
`Target platform` carries the cross target.
* ghcjs / wasm cross-GHCs report `Have interpreter: NO`,
`Use interpreter: NO` (the JS / WASM backends don't have a
GHCi-style bytecode interpreter). Dummy was emitting `YES`
for both. Flip them to match.
Verified `tests.dummy-ghc-info` passes on the
`aarch64-darwin.unstable.ghc9141.{native,ghcjs}` jobsets. The
test will now catch any future divergence between dummy-ghc and
real GHC's `--info` output.
* v2 builder: route exe-depends closure walk through pkgsBuildBuild's plan
Build-tool exes (hsc2hs / alex / happy / ...) run on the build
platform; their unit-ids and lib-dep closures belong to the
build-build project's plan, not the cross plan. Previously
\`mkClosureFrom\` resolved every \`exe-depends\` id against the cross
plan-json — pulling in cross-target unit-ids and (transitively) the
wrong versions of process / directory / etc. for the slice's
\`libConstraintPins\` and \`sourceRepoEntries\`.
Tag every closure node with its plan ("cross" or "bb"), and have
\`exe-depends\` ids cross over to the bb plan via direct id lookup
(rare hit) or pkg-name fallback through \`package-ids-by-name\`.
Lib-deps of bb-tagged nodes stay in bb-plan; lib-deps of cross-tagged
nodes stay in cross. \`sourceRepoEntries\` now dispatches on
\`e.plan\` for the \`hsPkgs\` lookup.
\`libConstraintPins\` reverts to \`allDepClosure\` so cabal in the
slice pins the bb plan's versions for an exe's lib closure (matching
what the bb slice was built against).
Plumbed via \`hsPkgs.{plan-json-by-id, package-ids-by-name}\` exposed
in component-driver — \`hsPkgs.pkgsBuildBuild.<idx>\` reaches the
bb project's indexes naturally.
* v2 builder: skip exe entries when forming libConstraintPins
The bb-plan walk added by the previous commit pulled exe entries
(hsc2hs / alex / happy / ...) into `allDepClosure`. Pinning them
in `libConstraintPins` lands them in `extra-packages:`, which
makes cabal's solver in the slice plan the build-tool from source
instead of using the pre-installed exe slice. Skip closure
entries whose `component-name` starts with `exe:` — their lib
closures (process, directory, ...) still get pinned via the
`libDepsOf` walk in bb-plan.
* v2 builder: drop build-tool source tarballs from the slicing repo
Build-tool exes (hsc2hs / alex / happy / ...) reach the slice's
build environment via `extraNativeBuildInputs` (PATH). Their
source tarballs were also being added to the slicing repo's index
via `++ lib.concatMap (s: s.passthru.transitiveTarballs) buildToolSlices`,
which let cabal's solver see hsc2hs in the index and plan a
from-source rebuild for `build-tool-depends: hsc2hs:hsc2hs` —
forking the tool's unit-id (cross GHC info ≠ build-platform GHC
info) and failing the expected-package check.
Drop the line and rely on cabal's legacy PATH fallback for build-tool
resolution. The tool's lib closure (process, directory, ...) still
reaches the slicing repo when those libs are also lib-deps of the
target package; otherwise they're not needed (the slice doesn't
re-solve the tool).
* v2 builder: split sibling exe-deps from lib-deps
The v2 slice handles sibling `depends` and `exe-depends` from
plan-json differently:
* lib-deps land in `externalDepIds`, drive the slicing repo
(via `depTransitiveTarballsOf`), and get pinned in
`libConstraintPins`.
* exe-deps (build-tools) need their exe on PATH but their
source MUST stay out of the slicing repo's index — otherwise
cabal's solver in the slice plans the tool from source for
`build-tool-depends: foo:foo`-style deps and forks the
tool's unit-id (cross GHC info ≠ build-platform GHC info).
Split the plan-json walk in hspkg-builder into `homeDependIds`
(lib) and `homeBuildToolIds` (exe). The v2 builder's
`homeDepExeSlices` now feeds from the latter; `externalDepIds`
naturally drops exe-only entries.
* hspkg-builder: hoist homeIds out of comp-v2-builder attr-set
Pure restructure: `inherit (homeIds) ...` only works when `homeIds`
is in scope, not as a sibling field of the same attr-set. Move
the let-binding above the `comp-v2-builder { ... }` call so the
inherit references resolve.
* v2 builder: cross builds steer cabal off build-tool goals via --with-PROG
On native, build-tool source tarballs go in the slicing repo (as
before) so cabal recognises the pre-installed bb slice's unit-id
and skips re-building. Restored to old behaviour, including
merging `homeBuildToolIds` into `externalDepIds`.
On cross the unit-ids legitimately diverge (cross GHC info ≠
build-platform GHC info), so the bb hsc2hs slice would never
match what cabal-in-slice computes; cabal would plan it from
source and fork. Instead:
* keep the build-tool's source OUT of the slicing repo
(`externalDepIds` skips `homeBuildToolIds`; `depTransitives`
skips the `buildToolSlices` tarballs);
* emit `--with-<exe>=<bb-slice>/bin/<exe>` for every transitive
build-tool reached in `allDepClosure` — cabal skips planning
the tool from source and uses the explicit path;
* skip the unit-id MATCH check (`expectedUnitId = null`), but
`build-cabal-slice` now verifies exactly ONE unit-id is
captured so the slice still produces a single, well-defined
`$out/store` content.
* v2 builder: collapse duplicate isCross definition
The hoisted-up isCross collides with the existing one further
down. Drop the lower-down one.
* v2 builder: keep build-tool tarballs in the slicing repo on cross too
The cabal solver in the slice always plans every transitive
`build-tool-depends:` package, even when `--with-PROG=PATH` is
set — `--with-PROG` only short-circuits at build time, after the
solver has succeeded. Leaving the build-tool's source out of the
index made the solver fail with
`unknown package: <pkg>:<exe>:exe.<exe> (dependency of ...)`.
Restore the build-tool's transitive tarballs (the tool itself
plus its lib closure) for every build. On native cabal recognises
the pre-installed bb slice's unit-id and skips re-building; on
cross `withProgFlags` provides `--with-<exe>=<bb-slice>/bin/<exe>`
so cabal short-circuits the build despite the divergent unit-id.
The dry-run `expectedPackage` check is skipped on cross (cabal
*plans* every build-tool there, by design), leaving the
post-install captured-unit-ids count==1 check as the guarantee
that cabal did short-circuit the tool builds.
* v2 builder: compose cross build-tool slice (matching uid) on cross
Build-tool slices are the unit cabal needs to find in the
cabal-store to skip re-building. Previously we composed the
build-build slice (e.g. native hsc2hs), whose plan-nix-computed
uid Y doesn't match what the cross slice's cabal computes for the
tool (uses cross dummy-ghc info, matching real cross-ghc info per
tests.dummy-ghc-info). cabal didn't recognise the composed slice
and rebuilt the tool from source.
Compose the CROSS hsPkgs's tool slice instead (`targetSlice` in
the new `transitiveBuildToolEntries`). Its uid matches what the
slice's cabal computes, so cabal recognises the tool as already
installed and skips re-building. The cross binary isn't runnable
on the build host, but cabal only needs the unit-id-keyed dir
present in the cabal-store; actual invocation goes through
`--with-PROG=<buildSlice>/bin/<exe>` which points at the
build-build binary.
Skip the expected-uid check on cross (`expectedUnitId = null`):
the slice's network unit-id picks up `--with-PROG=PATH` into
pkgHashProgramArgs, which plan-nix doesn't have, so the two uids
legitimately diverge. The post-install captured-set check now
verifies the slice produced exactly one unit for the target
package plus zero-or-more units for the allowed transitive
build-tools (a safety net for cases where cabal didn't recognise
a composed targetSlice's uid). The dry-run plan check similarly
tolerates build-tool packages — anything else is still a fail.
* v2 builder: tighten unit-id pkg-name parser to a strict version pattern
`iserv-proxy-9.3-011cc258...`'s hash starts with `0`, which the
old `^[0-9]` regex matched, leaving the parser thinking the hash
was the version and producing `iserv-proxy-9.3` as pkg-name.
Use `^[0-9]+(\.[0-9]+)*$` so only true version tokens match
(the hash, being all-hex with mixed letters, never matches).
* flake.lock: bump iserv-proxy to a31c4c4 (armv7a NDK stubs)
Picks up `stable-haskell/iserv-proxy@a31c4c4`:
armv7a-android: stub symbols missing from current NDK
so the v2 cross builder's `iserv-proxy-interpreter` exe slice
gets past lld's undefined-symbol errors on armv7a-android.
* flake.lock: bump iserv-proxy to 8cdc446 (posix_spawnp stub)
* v2 builder: inject component.libs paths into post-register .conf
GHC's runtime linker (the one TH eval uses, including under
`-fexternal-interpreter` / `ghc-iserv`) dlopens each loaded
package's `extra-libraries:` entries by bare name (e.g.
HsOpenSSL's `extra-libraries: ssl crypto` → `libssl.so`).
Cabal records empty `library-dirs:` etc. in the per-unit
`.conf` because we deliberately don't push these paths into
the slice's configure args (that would land in
`pkgHashExtraLibDirs` and fork the slice's unit-id from
plan-nix).
v1 baked these into the .conf via `make-config-files.nix`'s
`extra-lib-dirs` flag fed to `Setup configure` (v1 used its
own unit-id scheme so the hash didn't matter). In v2 we
post-process: after `cabal v2-build` registers the unit, append
the lib paths to the `library-dirs:` / `library-dirs-static:` /
`dynamic-library-dirs:` fields, then `ghc-pkg recache`.
Downstream consumers' unit-ids are unaffected — their config hash
records each dep's unit-id, not the dep's .conf content — so the
chain stays plan-nix-consistent end to end.
* v2 builder: use .conf 'name:' field over uid prefix for pkg matching
cabal's OS-prefix patch shortens unit-id prefixes (e.g.
`bytrdr-1.0.4-...` for the `byteorder` package), so parsing the
pkg-name from the uid alone misclassified lib units and failed the
post-install captured-unit check with
`slice captured 0 units for the target package 'byteorder'` even
when the captured uid WAS the right one.
Read the authoritative pkg-name from each unit's `.conf` (which
records the real package name) and fall back to uid parsing only
for bin-only units that don't have a .conf.
* v2 builder: handle sublib pkg-name + drop backpack nix-tools override
Three related cleanups:
* `build-cabal-slice.nix`: prefer `package-name:` over `name:` in
the captured-unit `.conf` parser. For sublibs cabal records
`name: z-<pkg>-z-<sublib>` (z-encoded) but also
`package-name: <pkg>` — the latter is what the slice's expected
package check should match against.
* `test/backpack/default.nix`: drop
`inherit (evalPackages.haskell-nix) nix-tools;`. The line was
needed when backpack PR (#2467, 2026-03-17) added a new
`make-install-plan` flag that wasn't yet in the prebuilt
`nix-tools-static` tarball. The tarball has been updated since
(febad32e4 on 2026-03-24, and subsequently), so the default
`nix-tools-unchecked` picks up backpack support; the override
forces an unnecessary from-source build that on aarch64-darwin
cascades into a v2 slice mismatch on `cabal-install`'s
`pkg-src.repo.type` (`secure-repo` vs `remote-repo`).
* `test/cabal.project.local`: bump the pinned
`head.hackage.ghc.haskell.org` `--sha256` to match the current
index tarball — the previous hash was stale and would fail
the fixed-output hash check during plan-to-nix.
* v2 builder: accept backpack instantiations in the captured-unit set
The exe slice that consumes an indefinite backpack library ends up
materialising the instantiated form (a `+`-suffixed unit-id, e.g.
`bckpck-0.1.0.0-55b00c8f+Dwq5ijz...`) alongside the exe itself,
because the indefinite consumer's own slice produced no compiled
artifacts to compose in (cabal v2-build for an indefinite library
is "Up to date" and writes no `.conf`). v1 handles this with a
per-instantiation derivation (`lib/default.nix:369`'s
`components.library.override { inherit instantiations; }`); v2
doesn't yet have a slice-per-instantiation, so the instantiated
unit rides along inside the consuming slice's $out.
Three captured-unit changes:
* Read pkg-name from cabal's `dist-newstyle/cache/plan.json`
for bin-only units (no `.conf`). Falling back to uid parsing
misclassified OS-prefix-shortened names like `bckpck-...` as
a package called `bckpck` instead of `backpack`.
* Allow 0 target-package units (indefinite libraries register
nothing).
* Skip `+`-suffixed unit-ids when counting target-package units
— they're cabal-emitted instantiation byproducts, not the
slice's own target. The "no foreign package" invariant
(everything outside `expectedPackage` ∪ `allowedBuildToolPackages`
is rejected) still applies and is what catches an accidentally
rebuilt lib dep.
* 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\`.
* 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`.
* 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.
* flake.lock: bump iserv-proxy to 0b8d6f6 (aarch64-android stubs)
* flake.lock: bump iserv-proxy to 3d649af (more aarch64-android stubs)
* 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.
* 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: 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: 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: 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: 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: 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).
* 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: 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 …