mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-09-01 05:04:40 +00:00
The chain is the part of this package set that cannot be read off any one file: four compilers, each a step further along, and two `libgcc`s either side of the libc. Until now it was only recoverable by reading the `overrideCC` call sites in order and reconstructing the argument. Write it down once, as a table, next to why the cycle needs breaking at all -- a libc's sources call into libgcc, and a libgcc that can use the libc's threads needs the libc. Also record the two things that are easy to get wrong and hard to notice: that the pre-libc stage is written down in exactly one place (`binutilsNoLibc` carrying `preLibcHeaders` as its `libc`), and that a libgcc built with `inhibit_libc` still compiles, links and installs, just with pieces silently missing. The per-wrapper comments shrink to what is local to each -- which stage it is and what keeps the libc out -- since the chain-wide narrative now has somewhere better to live. Assisted-by: Claude Code (Claude Opus 5)
59 lines
3.8 KiB
Markdown
59 lines
3.8 KiB
Markdown
# GCC Next-Generation
|
|
|
|
Experimental split GCC package set, based on the LLVM package set design.
|
|
|
|
The monolithic `gcc` derivation builds the compiler and every runtime library in one go, so a change to the target libc rebuilds the compiler too.
|
|
This set separates them — `gcc`, `libgcc`, `libstdcxx` and the rest are individual packages — so the compiler stops depending on the libc, and each piece can be rebuilt on its own.
|
|
Because GCC is not a multi-target compiler — a single target is baked into the binary with CPP — we still need to rebuild it more than we do LLVM, but someday that should change.
|
|
|
|
A platform opts in with `useGccNG`, in the same way it would opt into `useLLVM`.
|
|
|
|
## The bootstrap chain
|
|
|
|
The libc and libgcc depend on each other: a libc's own sources call into libgcc for integer and floating-point helpers and for stack unwinding, and a libgcc that can use the libc's threads needs the libc.
|
|
|
|
The way out we currently use is the same one the LLVM set takes with `compiler-rt-no-libc` and `compiler-rt-libc` — build the runtime twice, either side of the libc.
|
|
It is unclear whether this works in general to resolve the circularity, but we shall see.
|
|
|
|
That gives four compilers, each one step further along:
|
|
|
|
| compiler | libc | libgcc | used to build |
|
|
|---|---|---|---|
|
|
| `gccNoLibgcc` | headers, or nothing | — | `libgcc-no-libc` |
|
|
| `gccWithLibgcc` | headers, or nothing | `libgcc-no-libc` | the libc |
|
|
| `gccWithLibcAndBasicLibgcc` | real | `libgcc-no-libc` | `libgcc-libc` |
|
|
| `gccWithLibc` / `gcc` | real | `libgcc-libc` | everything else |
|
|
|
|
`libgcc` resolves to `libgcc-libc` wherever a libc exists; only those first three stages ever see `libgcc-no-libc`.
|
|
The bootstrap one is single-threaded and compiled against the libc's headers at best, so it is not intended for use beyond building the libc.
|
|
|
|
Nothing is passed down to say which stage is which.
|
|
It follows from the compiler: each package reads `stdenv.cc.libc` and needs no flag of its own.
|
|
That is also how the two `libgcc`s differ — same expression, different `stdenv`.
|
|
|
|
## Where the pre-libc stage is written down
|
|
|
|
`binutilsNoLibc` carries `preLibcHeaders` as its `libc`: the header-only stand-in for platforms that have one, and nothing at all for platforms that do not.
|
|
`wrapCCWith` defaults `libc` to `bintools.libc`, so the bootstrap compilers inherit it, and everything built with them reads `stdenv.cc.libc`.
|
|
|
|
Setting a sysroot as well is unusual for nixpkgs, since headers normally reach a compiler through the wrapper, as they do here.
|
|
It is needed because `gcc/configure` takes `target_header_dir` from `--with-sysroot`, and `target_header_dir` is what decides `inhibit_libc`.
|
|
A libgcc built with `inhibit_libc` still compiles, links and installs, just with pieces silently missing.
|
|
|
|
Given that, the sysroot is derived from `stdenv.cc.libc` too, so it cannot disagree with the headers.
|
|
|
|
## Threading
|
|
|
|
Which threading model is available is a property of the libc, so the libc declares it as `passthru.threadModel`; `libgcc` reads it from there, and `libstdcxx` takes both the model and the generated `gthr-default.h` from `libgcc`.
|
|
|
|
Reading it from the compiler instead, with `$CC -v | sed -n 's/^Thread model: //p'`, reports the wrong component: in this set the compiler is configured separately from libgcc, so the two can disagree.
|
|
A platform whose libc declares nothing gets `single`.
|
|
|
|
## Relationship to the monolithic set
|
|
|
|
Both are packaged from the same sources and, for now, the same version: `gccNGPackages` tracks `default-gcc-version` with no fallback, so bumping the monolithic default past what is packaged here is an evaluation error rather than a silent version skew.
|
|
|
|
Nothing selects GGN NG yet by default.
|
|
The plan is for very exotic package sets to switch to this first.
|
|
The main tier-1 native Linux package sets cached on `cache.nixos.org` will come later.
|