Nothing could select the split GCC package set, so none of the fixes
below this commit were reachable from a normal build.
Add `useGccNG` alongside the existing `useLLVM`/`useZig`/`useArocc`
choices, and honour it where a compiler is picked: the cross stdenv takes
`gccNGPackages.gcc`, and `stdenvNoLibs`/`stdenvNoLibc` map to
`gccNoLibgcc` and `gccWithLibgcc`. That last pair is the point of the
split. Both currently fall back to `gccCrossLibcStdenv`, because the
monolithic compiler cannot distinguish them; `lib/systems/default.nix`
says as much next to `linker`, noting that we would like to choose the C
compiler and runtime library orthogonally but "due to the monolithic GCC
build we cannot actually make those choices independently". This is what
lifts that, the way the LLVM set already splits `clangNoCompilerRt` from
`clangNoLibc`.
`gccNGPackages` tracks `default-gcc-version` rather than naming a
release, so the split set and the monolithic `gcc` stay on the same one.
`useGccNG` defaults to `false` and no platform derives it, so no existing
build changes. Setting it on a platform spec is enough to exercise the
whole stack:
nix-build . -A stdenv.cc --arg crossSystem \
'{ config = "aarch64-unknown-linux-musl"; useGccNG = true; }'
The intent is to switch obscure low-tier platforms over to it soon --
NetBSD first -- so `ng` gets dogfooded somewhere the blast radius is
small. Those switches come separately.
Assisted-by: Claude Code (Claude Opus 5)
These shorthands hide the platform distinction and are unfit for
cross-compilation. Wrap them in `lib.warn` so each access prints a
deprecation notice, and gate them on `config.allowAliases` so they
can be removed entirely.
Assisted-by: claude-code with claude-opus-4-8
The final stage asserted
assert prevStage.libiconv == prevStage.darwin.libiconv;
On Darwin `libiconv` is `darwin.libiconv`, so this compares a value with
itself. Nix does not notice: `eqValues` short-circuits only on pointer
identity of the two value slots, and these are two slots that resolve to
one attribute set. It therefore falls through to the derivation case,
which compares `outPath`.
`lib.extendDerivation` guards `outPath` behind the derivation's validity,
which reads `config.allowUnfree`, so the assertion demanded a `config`
option while the package set was still being assembled. When `config` is a
function it is passed `pkgs`, and the loop closes:
(import <nixpkgs> {
system = "aarch64-darwin";
config = { pkgs, lib, ... }: { allowUnfree = lib.isAttrs pkgs; };
}).config.allowUnfree
failed with an infinite recursion on Darwin while evaluating on Linux,
whose stdenv never forces a derivation that early. It now evaluates on
both.
Keep checking the invariant, from `tests.stdenv` instead. By then the
package set is complete, so forcing `outPath` is just a read.
The other twelve assertions in the stage read `passthru` and
`stdenv.cc.cc`, which are ungated, and stay where they are.
Assisted-by: claude-code with claude-opus-5[1m]-high
The dispatcher now constructs local bootstrap stages directly, so their target is represented entirely by localSystem. Remove the redundant crossSystem arguments and equality assertions from each local stage implementation.
Assisted-by: codex with gpt-5.6-sol-high
Every in-tree union/intersection use has exactly two members, and the
binary form verifies without allocating a closure or calling the any/all
primop per check. check-meta.nix switches to either/both; union and
intersection are kept for potential future use.
Assisted-by: Claude Code (Claude Fable 5)