Skip to content

validation: post-split cabal re-pin + stage-qualified host-only (DO NOT MERGE — pins WIP cabal#378) - #189

Draft
angerman wants to merge 142 commits into
stable-ghc-9.14from
feat/cabal-pin-postsplit
Draft

angerman wants to merge 142 commits into
stable-ghc-9.14from
feat/cabal-pin-postsplit

Conversation

@angerman

Copy link
Copy Markdown

Validation only — DO NOT MERGE. This pins the WIP cabal branch
feat/wasm-cross-ghcup-stack-next (stable-haskell/cabal #378 host-only +
#361 + #368 + #385 $ORIGIN), to validate the eventual post-split re-pin
across the full release matrix. It cannot merge until cabal #378 lands.

Replaces the pre-split aa57a49 pin and drops both pre-split hacks:

  • compiler/Setup.hs + ghc-boot/Setup.hs restored to the upstream
    #if MIN_VERSION_Cabal(3,17,0) VerbosityHandles form.
  • cabal.project.stage0 hooks-exe sub-dir restored.

Plus the one adaptation the post-split host-only model needs: cabal.project.stage2.dynamic
stage-qualifies shared/executable-dynamic to host:* (with build:* forced
static), because an unqualified package * no longer scopes host-only on #378.

Validated locally on aarch64-darwin: stage0 + stage1 + stage2 (DYNAMIC=1)
green
, stage2 ghc dynamically linked. This run exercises the breadth
(DYNAMIC=0, Linux/Windows/FreeBSD/musl, cross). See stable-haskell/cabal#384.

angerman and others added 30 commits March 5, 2026 12:35
This change reverts part of !14544, which forces the bootstrap
compiler to have ghc-internal.  As such it breaks booting with
ghc 9.8.4. A better solution would be to make this conditional
on the ghc version in the cabal file!
…ernal

If the boot compiler doesn't have ghc-internal use "<unavailble>" as the
`cGhcInternalUnitId`.  This allows booting with older compilers. The
subsequent stage2 compilers will have the proper ghc-internal id from
their stage1 compiler, that boots them.
Make the first simple optimization pass after desugaring a real CoreToDo
pass. This allows CorePlugins to decide whether they want to be executed
before or after this pass.
It's more user-friendly to directly print the right thing instead of
requiring the user to retry with the additional `-dppr-debug` flag.
mermaid is a common diagram format that can be inlined in markdown
files, and e.g. github will even render it.  This change adds
support for mermaid diagram output to ghc-pkg.
This adds support to ghc-pkg to infer a package-db from a target name.
Add a new optional unitDataDir field to GhcPkg.InstalledPackageInfo
and populate it in ghc-pkg's convertPackageInfoToCacheFormat.

This is needed by the WASM linker to locate per-package data files
(specifically WasmGlobalRegs.S) via GHC.Unit.Database.unitDataDir
at link time, without requiring a file-system search.
By mistake we tried to use deriveConstant without passing
`--gcc-flag -fcommon` (which Hadrian does) and it failed.

This patch adds deriveConstant support for constants stored in the .bss
section so that deriveConstant works without passing `-fcommon` to the C
compiler.
Apple's LLVM toolchain uses `arm64` as the canonical architecture name
for AArch64 on Apple platforms, while GNU config.sub normalises to
`aarch64`. This mismatch causes `--target=aarch64-apple-darwin` to be
passed to clang, which conflicts with toolchain wrappers (e.g. nix
cc-wrapper) that expect `arm64-apple-darwin`.

The result is thousands of test failures on aarch64-darwin because the
cc-wrapper warning pollutes compiler output and the target flag
interaction breaks compilation.

Fix by adding normaliseLlvmTarget that rewrites `aarch64-apple-*` to
`arm64-apple-*` for the LLVM target triple, matching Apple conventions
and the existing llvm-targets file which already uses arm64-apple-darwin.
Add AC_ARG_WITH([compiler]) to allow specifying the Haskell compiler
via the --with-compiler flag, consistent with standard autoconf practices
for tool configuration.

This provides an alternative to setting the GHC environment variable,
making the build system more flexible and consistent with other
configure scripts that accept --with-* options for tools.
Add entries to prevent AI agent config files from being accidentally
committed. These files contain project-specific instructions for various
AI coding assistants and should remain local.

Covers: Claude Code, GitHub Copilot, Cursor, Gemini CLI/Jules,
OpenAI Codex, and JetBrains Junie.

See: https://agents.md/ for the AGENTS.md standard
Fixes #26434

In detail, this does a number of things:
* Makes GHC aware of 'extra-libraries-static' (this changes the package
  database format).
* Adds a switch '-static-external' that will honour 'extra-libraries-static'
  to link external system dependencies statically.
* Adds a new field to settings/targets: "ld supports verbatim namespace".
  This field is used by '-static-external' to conditionally use '-l:foo.a'
  syntax during linking, which is more robust than trying to find the
  absolute path to an archive on our own.
* Adds a switch '-fully-static' that is meant as a high-level interface
  for e.g. cabal. This also honours 'extra-libraries-static'.

This also attempts to clean up the confusion around library search directories.
At the moment, we have 3 types of directories in the package database
format:
* library-dirs
* library-dirs-static
* dynamic-library-dirs

However, we only have two types of linking: dynamic or static. Given the
existing logic in 'mungeDynLibFields', this patch assumes that
'library-dirs' is really just nothing but a fallback and always
prefers the more specific variants if they exist and are non-empty.

Conceptually, we should be ok with even just one search dirs variant.
Haskell libraries are named differently depending on whether they're
static or dynamic, so GHC can conveniently pick the right one depending
on the linking needs. That means we don't really need to play tricks
with search paths to convince the compiler to do linking as we want it.
For system C libraries, the convention has been anyway to place static and
dynamic libs next to each other, so we need to deal with that issue
anyway and it is outside of our control. But this is out of the scope
of this patch.

This patch is backwards compatible with cabal. Cabal should however
be patched to use the new '-fully-static' switch.
"Executable" seems more appropriate.
This patch teaches GHC how to build the external interpreter program
when it is missing. As long as we have the `ghci` library, doing this is
trivial so most of this patch is refactoring for doing it sanely.

(cherry picked from commit 55eab80)
The comment still referenced the old `linkBinary` name after
the rename to `linkExecutable` in 55ff022.
GHC and ghc-iserv load Haskell shared libraries dynamically for Template
Haskell and GHCi. These libraries reference RTS symbols (e.g.,
stg_INTLIKE_closure) that are linked into the executable. Without special
linker flags, those symbols aren't visible to dlopen'd libraries.

This commit adds platform-specific linker flags to export these symbols:

- Linux/FreeBSD: -rdynamic (passes --export-dynamic to ld)
- macOS: -flat_namespace (makes all symbols visible across namespaces)
- Windows: Cannot use --export-all-symbols due to 65535 symbol limit

See Note [ghc-iserv and dynamic symbol export] in ghc-iserv.cabal.in
for detailed explanation of the approach and alternatives considered.
Replace legacy __sync_fetch_and_* builtins with their modern __atomic_fetch_*
equivalents. This simplifies the code significantly, particularly for the nand
operation which previously required extensive workarounds for compiler
compatibility issues.

Changes:
- Replace __sync_fetch_and_{add,sub,and,or,xor} with __atomic_fetch_*
- Replace __sync_fetch_and_nand with __atomic_fetch_nand
- Remove CAS-based fallback for nand operations
- Remove compiler-specific warning suppressions for -Wsync-nand
- Remove volatile qualifiers (not needed with __atomic builtins)
- Update comments to reflect modern atomics usage

All operations maintain __ATOMIC_SEQ_CST memory ordering for sequential
consistency, matching the original behavior.

Co-authored-by: Andrea Bedini <andrea@andreabedini.com>
angerman and others added 26 commits March 10, 2026 14:17
The T21651 concurrency stress test times out on aarch64-darwin CI
runners. Mark it fragile since it's a CI environment issue, not a
code regression.
ss_conv was emitting raw SBFM for all MO_SS_Conv cases. For widening conversions (e.g. W32->W64), emit the canonical SXTB/SXTH/SXTW instructions instead, with the correct source register width (Wn not Xn).

Also fix signExtendReg to use source register width for the source operand of SXTW/SXTH/SXTB instructions (latent bug: source always used destination width).
FP_VISIBILITY_HIDDEN was called in rts/configure.ac but the macro
definition was removed in an earlier commit. Remove the orphaned
call to fix autoconf warnings.
The macOS-13 GitHub Actions runner now ships with Homebrew llvm@18,
whose libunwind triggers a linker warning on every invocation:

  ld: warning: reexported library with install name
  '/usr/local/opt/llvm@18/lib/libunwind.1.dylib' ... couldn't be
  matched with any parent library and will be linked directly

This causes ~190 spurious test failures (bad stderr / stderr mismatch)
on the Mac x86_64 CI. Filter the warning in both normalise_errmsg and
normalise_output, alongside the existing macOS ld warning patterns.
Recent macOS and Windows CI runner images set CC to include flags
(e.g. "/usr/bin/cc -std=gnu23"). The --gcc-program argument was
passed directly to rawSystem which treats the entire string as an
executable path, causing:

  deriveConstants: /usr/bin/cc -std=gnu23: rawSystem: posix_spawnp:
  does not exist (No such file or directory)

Split the --gcc-program value on whitespace: the first word becomes
the program path, remaining words are prepended to the gcc flags.
On Windows (MSYS2/CLANG64), the _utime function expects a
struct _utimbuf pointer. The CUtimbuf CTYPE was declared as
"struct utimbuf" which worked when clang treated them as compatible,
but with -std=gnu23 (now the default on updated CI runner images)
clang errors on the type mismatch:

  incompatible pointer types passing 'struct utimbuf *' to
  parameter of type 'struct _utimbuf *'

Use the correct Windows type name in the CTYPE pragma.
Point all stage cabal.project files at stable-haskell/cabal
wip/angerman/compile-less (44817477ff6d22de4bfa4307e061df58f319d3b6),
which is based on Andrea Bedini's wip/andrea/compile-less and includes:

- Cross-compilation support (Stage/Toolchain architecture)
- Local store (replaces in-place builds)
- Recompilation avoidance (file monitor tracking for installed packages)
- hasufell's "Stop stealing the vowels" and "Fix caching of remote source tarballs"
- TOCTOU race fix for BuildInplaceOnly tarball extraction
wip/angerman/compile-less has been renamed to stable-haskell/master
…split

Cabal 3.17 (commit edb808a0b8b, "allow setting the logging handle")
split the old Verbosity type into VerbosityFlags (the CLI-passable
part) plus VerbosityHandles. configVerbosity now yields a Flag
VerbosityFlags, which must be wrapped back into a Verbosity via
mkVerbosity before being passed to Cabal library functions such as
requireProgram, getProgramOutput and info.

Add a CPP-guarded configVerbosity' helper to both Setup.hs files, and
in compiler/Setup.hs replace the bare 'normal' literal (now a
VerbosityFlags) with the in-scope 'verbosity' parameter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
It's required since cabal commit 6867dd5da57194337bab0079bbe2f1c21e11662f
It's required since cabal commit 6867dd5da57194337bab0079bbe2f1c21e11662f
Statically-linked executables link only system libraries (libc/libm) and
load nothing from ../lib, so they need no rpath. patchelf also cannot
rewrite the large statically-linked ghc/haddock/ghc-iserv binaries (it
fails with "virtual address space underrun"). Gate the dist binary rpath
loop under DYNAMIC=1, matching the existing gating of the shared-library
rpath step.
The hackage-security package is only ever used in stage0 to build cabal-install.
…igure

Replace the configure-driven static/dynamic selection for stage2 with
explicit cabal project files.

Previously a `--enable-dynamic` autoconf toggle, together with the
`m4/accumulate.m4` helper macros, generated cabal.project.stage2.settings
from a .in template, while the Makefile separately appended
--enable-dynamic to GHC_CONFIGURE_ARGS when DYNAMIC=1. Keeping these two
mechanisms in sync was fragile.

Now the stage2 configuration is split into a shared
cabal.project.stage2.common plus two thin variants that import it:

  - cabal.project.stage2.static  (default; shared: False)
  - cabal.project.stage2.dynamic (shared: True, executable-dynamic: True,
                                  rts +dynamic)

The Makefile selects the project file directly through DYNAMIC_SUFFIX and
the new CABAL_PROJECT_FILE variable, so DYNAMIC=1 picks the dynamic file
without any configure round-trip.

Removed as no longer needed:
  - the --enable-dynamic configure option and its substitution logic
  - cabal.project.stage2.settings(.in) template
  - m4/accumulate.m4
The hosted Windows runner's make changed from MSYS2 (MAKE_HOST=x86_64-pc-msys)
to Cygwin (x86_64-pc-cygwin). Both `ifeq ($(MAKE_HOST),x86_64-pc-msys)` guards
then fell through, dropping the Windows CC/CXX/LD overrides so CC/CXX defaulted
to cc/g++ and ghc-toolchain failed stage1 settings generation with
"g++ not found". Match all Windows make-host triples (msys, cygwin, mingw32)
via $(filter ...).
release.yml was broken at the root by the Cabal source-repo pin
`tag: stable-haskell/master`, which cabal could not resolve at stage0 (every
platform died building cabal-install). Pin an explicit, resolvable SHA on the
feature/wasm-cross-ghcup-stack branch (aa57a49) which carries the fixes the
build needs:

  * host-only `package *` handling, so cabal.project.stage2.dynamic's
    `shared: True` no longer builds the build-stage packages shared (those
    failed to link against the bootstrap GHC on ~every platform:
    "ld: cannot find -lHSbytestring-...-ghc9.8.4");
  * #361 target-prefix-aware companion-tool guess (cross ghc-pkg);
  * a self ($ORIGIN/@loader_path) rpath entry so an instantiated Backpack
    unit finds its signature implementation under musl (testsuite T14304 on
    Alpine; glibc masked it via the runtime LD_LIBRARY_PATH GHC sets before
    dlopen, which musl ignores).

Adapt the tree to this Cabal:
  * cabal.project.stage0: drop the `hooks-exe` subdir (absent on this branch);
  * compiler/Setup.hs, libraries/ghc-boot/Setup.hs: revert the Cabal-3.17
    Verbosity/VerbosityHandles-split adaptation (this branch predates it);
  * cabal.project.stage{1,2.common}: compile out libffi's deprecated (Java)
    raw API with -optc-DFFI_NO_RAW_API=1, which RockyLinux 8 gcc treats as a
    hard error (GHC does not use that API).
The FreeBSD self-hosted runner has no JS toolchain (llc/opt/emscripten), so it
cannot build the javascript-unknown-ghcjs cross target. Drop both the JS
bindist and haskell-toolchain.tar.gz (which depends on
stage3-javascript-unknown-ghcjs) from the FreeBSD build; ship only the native
ghc/cabal/tests bindists.
Replace the pre-split aa57a49 pin (feature/wasm-cross-ghcup-stack) with
feat/wasm-cross-ghcup-stack-next (ee3b55e6): stable-haskell/cabal's
wip/andrea/stage-qualified-options (#378, Host-only `package *` handling)
+ target-prefixed ghc-pkg guess (#361) + absolute-rpath relativization
(#368) + the $ORIGIN/@loader_path self-rpath (#385, musl T14304).

Being post-split, the next branch carries the Cabal-3.17 VerbosityHandles
API and the hooks-exe sub-dir, so two adaptations the aa57a49 pin forced
are no longer needed and are reverted here:

  * compiler/Setup.hs, libraries/ghc-boot/Setup.hs: restore the upstream
    `#if MIN_VERSION_Cabal(3,17,0)` VerbosityHandles form (un-revert).
  * cabal.project.stage0: restore the hooks-exe sub-dir.

The libffi-clib FFI_NO_RAW_API workaround (Rocky gcc-8) is unrelated to
the pin and is kept. Tracked by stable-haskell/cabal#384; re-pin to
`master` once #378 lands there.
The post-split Cabal (#378, `package <stage>:*`) does not treat an unqualified
`package *` as host-only the way the pre-split aa57a49 pin did, so a bare
`package * { shared: True }` here also built the BUILD-stage tools shared and
they failed to link the bootstrap GHC's static-only libs
("ld: library not found for -lHSbytestring-...-ghc9.8.4", on build:os-string).

Split it per #378's own fixture: `package host:*` carries shared/dynamic,
`package build:*` forces the build tools static. Validated locally:
stage0+stage1+stage2 (DYNAMIC=1) build green on aarch64-darwin and stage2 ghc
is dynamically linked (@rpath/libHSghc-9.14-ghc9.14.dylib).
Consolidates the cabal.project changes for the post-split Cabal pin:

- stage1 hermetic build: `active-repositories: :none` + pin happy/alex/
  happy-lib/hpc so stage1 build-tools don't float to Hackage's newest (a
  floated happy produces parser code mismatching the pinned template ->
  genprimopcode/GHC-44432). stage2/stage3 already did this. (stable-haskell/
  cabal#384)

- stage1 `time-1.14` as source: the post-split host Cabal-3.17.0.1 pulls in
  `time`; the bootstrap's installed time-1.12.2 is bound to installed
  Win32-2.13.4.0 and conflicts with the pinned source Win32-2.14.2.1 on
  Windows. time-1.14 is the newest release satisfying hpc-0.7.0.2's
  `time >=1.2 && <1.15` (1.15 backjumps on host:hpc/host:time).

- re-pin Cabal ee3b55e6 -> f2e0a89 (stage0/1/2.common/3): f2e0a89 fixes
  cross build-stage `ar` archiving — it derives -L/@-file support from the
  actual ar program (its --version) instead of the host/target compiler's
  claim, with a non-throwing probe so Apple cctools `ar` (no --version) falls
  back to the conservative path. Without it, build-stage happy-lib failed to
  archive on RockyLinux 8 (GNU ar, -qL) and macOS x86_64 (cctools ar, @-file).
The post-split Cabal-syntax now knows ExplicitLevelImports and
ImplicitStagePersistence, so T4437 no longer reports them as "GHC-only"
extensions; the two stale lines are removed from the golden.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.