v2 shell: auto-write project's cabalProjectLocal at shell startup
Move the platform-specific cabal.project pragmas back into
`modules/cabal-project.nix`'s `cabalProjectLocal` mkIfs (so
plan-nix's elaboration records the matching configure-args) and
expose them to the v2 shell so users get them in their
`cabal.project.local` automatically — no more hand-maintained
`shared: True` / `library-for-ghci: True` / `executable-static: True`
blocks duplicated between the shell and the slice.
Mechanism:
* `lib/call-cabal-project-to-nix.nix`: drop `platformCabalProjectPragmas`
(which injected the defaults directly into the rawCabalProject
text); rewrite the `cabalProjectLocal != null` check to also
skip `""`, so internal projects can switch from
`cabalProjectLocal = null` to `cabalProjectLocal = ""` without
changing the rawCabalProject hash.
* `modules/cabal-project.nix`: replace `platformCabalProjectPragmas`
with four `mkIf` blocks targeting `cabalProjectLocal`:
- musl → `package * executable-static: True`
- x86_64-darwin → `package * library-for-ghci: True`
- android → `package * ghc-options: -optl-static
-optl-ldl
[-optl-no-pie]`
- wasm 9.12+ → `package * shared: True`
(The wasm case is new — previously handled only by
`comp-v2-builder.nix`'s `forceShared` rewrite in the slice;
surfacing it at the project level makes plan-nix's elaboration
match without the slice having to paper over a `--disable-shared`
mismatch.)
* `overlays/ghc-packages.nix`, `compiler/ghc/default.nix`: switch
`cabalProjectLocal = null` to `cabalProjectLocal = ""` so the
`nullOr lines` option's merge accepts the mkIf injections. The
rawCabalProject hash is preserved by the `!= ""` skip above.
* `modules/component-driver.nix`, `overlays/haskell.nix`,
`builder/default.nix`: thread `cabalProjectLocal` from the
project module through to `shellForV2`.
* `builder/shell-for-v2.nix`: add a `haskell-nix-cabal-project-local-sync`
script (modeled after `haskell-nix-cabal-store-sync`). If
`cabal.project.<targetPrefix>local` is missing it writes it
from a `/nix/store` `writeText` of the merged
`cabalProjectLocal`; if present and equal it does nothing; if
present and different it prints the diff plus a
`haskell-nix-cabal-project-local-sync --force` invocation to
replace it. Invoked from the shell's shellHook and exposed on
`env.passthru.cabalProjectLocalSync`. For native shells the
target file is `cabal.project.local` (auto-picked by cabal);
for cross shells the filename has the target prefix and tests
pull it in with `import: cabal.project.<targetPrefix>local`.
* `test/cabal-sublib-shell/default.nix`: drop the hand-rolled
platform-conditional blocks from the inline `cabal.project`;
instead call `haskell-nix-cabal-project-local-sync` from the
test's buildCommand and, on cross targets, `import:` the
prefixed file. Also stop reading `../cabal.project.local` —
this test doesn't actually need any of its content, and the
`head.hackage` repository definition there triggered a
bootstrap that the sandbox's unpatched cabal couldn't satisfy
(`user error (https not supported)`).
Verified:
x86_64-darwin.unstable.ghc9141.native.tests.cabal-sublib-shell.run
x86_64-linux.unstable.ghc9141.musl64.tests.cabal-sublib-shell.run
aarch64-darwin.unstable.ghc9141.wasi32.tests.cabal-sublib-shell.run
all reuse the shell's prebuilt provider unit-ids and pass.