feat(gnu.org/glibc): host-independent recipe, 9 versions × 2 arches incl. HPC 2.17 / 2.24#12968
Conversation
New recipe to build glibc as a self-contained pkgx bottle using only
pkgx-supplied tooling. No apt-get, no host compiler, no host libc-dev.
Verified versions:
- linux/x86-64: 2.17, 2.24, 2.27, 2.28, 2.34, 2.38, 2.41, 2.42, 2.43
- linux/aarch64: 2.17, 2.24, 2.27, 2.28, 2.34, 2.38, 2.41, 2.42, 2.43
Each of the 18 bottles cross-tested on Alpine 3.18 (musl host),
Debian 11 (glibc 2.31), Ubuntu 22.04 (glibc 2.35). All return
`gnu_get_libc_version() = <bottle-version>`.
## Three per-version build gates
- `>= 2.32`: nixpkgs hygiene patches (dont-use-system-ld-so-{cache,
preload}) that prevent the new ld.so reading the host's
/etc/ld.so.cache and /etc/ld.so.preload — both files have a glibc-
version-specific binary format; reading them with a different glibc
is the classic startup-segfault recipe.
- `<= 2.18`: 1-line sed on configure to accept make 4.x in the
version regex.
- `< 2.32`: -fcommon (gcc 10+'s -fno-common default rejects the
tentative __nss_*_database definitions) plus CFLAGS-regexp.c=
-fno-common make override (because .symver can't be attached to
common symbols).
## HPC support (2.17, 2.24)
Cascaded with the companion older-toolchain PRs:
- pkgxdev#12966 binutils 2.28-era
- pkgxdev#12967 gcc 7.5/9.5-era
README.md inside the recipe directory documents the full bootstrap
procedure including the bottle-as-sysroot technique for building
non-glibc packages with the bottle's libc.
## Why no darwin
glibc is the GNU C library for the Linux kernel — macOS uses
libSystem + dyld with an entirely separate binary format (Mach-O vs
ELF). There is no glibc port to Darwin. Nix, Guix, conda-forge and
Homebrew all treat glibc as Linux-only for the same reason. The
recipe's platforms: list reflects this.
Refs: pkgxdev#5080, pkgxdev#147 (prior glibc attempts).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CI failures uncovered three problems in the recipe: 1. PROPS path was `../props` (one level above source-tree root), but brewkit copies the recipe's props/ subdir to the source-tree root. Drop the PROPS env var and reference `props/file.patch` directly (consistent with gnu.org/gcc/package.yml's existing pattern). 2. The 2.17/2.18 configure sed used `|` as both substitution delimiter AND inside the replacement pattern, producing "unknown option to s" on real glibc 2.17/2.18 source. Use `#` as delimiter. 3. Move the `CFLAGS-regexp.c=-fno-common` make override out of the build script (it was in the build-glibc script in my dev container but wasn't carried to the recipe). Glibc < 2.32 needs this because .symver can't be attached to common symbols. 4. The 2.17/2.18 sed step was using `working-directory: ../glibc-src` which only existed in my dev container's directory layout. brewkit extracts source directly into the build's source-tree root. Use `working-directory: ..` (consistent with the other patch step). CI link: https://github.com/pkgxdev/pantry/actions/runs/26152757884 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Brewkit makes top-level patch files appear under `props/` at build time (verified by inspecting the existing gnu.org/gcc/package.yml recipe, which references `props/disable-cfi-x86-64-darwin.patch` but has that file at the TOP of projects/gnu.org/gcc/). Move our patches out of the explicit props/ subdir so brewkit can find them. Closes a CI failure: `props/dont-use-system-ld-so-cache.patch: No such file or directory`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ted versions The brewkit audit phase fails if any listed binary in provides: is missing from the installed bottle. Several binaries from the original list are NOT installed across the full 2.17–2.43 range: - bin/catchsegv removed in glibc 2.38 (deprecated 2.32, then dropped) - sbin/zdump / sbin/zic: zdump moved between bin and sbin across versions; zic relocated similarly - sbin/sln moved bin → sbin around 2.30 Trim provides: to the executables installed by every version in the supported range. The dropped binaries are still produced by the build (when the source emits them), just not declared as guaranteed. CI link: https://github.com/pkgxdev/pantry/actions/runs/26157166061 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
-pie in LDFLAGS leaks into glibc's static auxiliary tool builds
(support/test-run-command etc.) and breaks them with:
hidden symbol \`_DYNAMIC' isn't defined
glibc decides its own pie/-shared per target — passing LDFLAGS=-pie
is harmful here even though it was in pkgxdev#5080's draft.
CI link:
https://github.com/pkgxdev/pantry/actions/runs/26157895410
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…pollution)
The previous test used `gcc` from PATH and shell builtins. brewkit's
test-phase env setup adds the bottle's lib/ to LD_LIBRARY_PATH, which
breaks host coreutils (mkdir, etc.) when the host's ld-linux is older
than the bottle's libc requires:
mkdir: /lib/ld-linux-aarch64.so.1: version `GLIBC_2.35' not found
(required by /opt/gnu.org/glibc/v2.43.0/lib/libc.so.6)
The mkdir is invoked by brewkit BEFORE the test commands run.
Replace with a self-contained test that invokes the bottle's OWN ld.so
(which IS the loader; it doesn't depend on host /lib/ld-linux*). For
older glibc (< 2.30) whose ld.so doesn't support --version, fall back
to getconf which has PT_INTERP baked in at install time pointing at
the bottle's own ld.so.
CI link:
https://github.com/pkgxdev/pantry/actions/runs/26158844912
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ollution
libpkgx's useShellEnv unconditionally adds every dep's {prefix}/lib/
to LD_LIBRARY_PATH. For a glibc bottle this BREAKS host coreutils
(mkdir, etc.) during brewkit's test phase whenever the host's
ld-linux is older than the bottle's libc requires:
mkdir: /lib/ld-linux-aarch64.so.1: version `GLIBC_2.35' not found
(required by /opt/gnu.org/glibc/v2.43.0/lib/libc.so.6)
The brewkit testbed.sh starts with `eval "$(pkgx +gnu.org/glibc=X.Y ...)"`
which exports LD_LIBRARY_PATH. The very next line `mkdir -p "$HOME"`
then fails because the host's mkdir picks up our libc.so.6 from
LD_LIBRARY_PATH but its (older) ld-linux can't satisfy the symbol
requirements.
ld.so searches LD_LIBRARY_PATH directories NON-RECURSIVELY. So if we
install libs to `{prefix}/lib/glibc-X.Y/` instead of `{prefix}/lib/`,
the top lib/ is empty of shared libs and the pollution goes away.
Use `--libdir={{prefix}}/lib/glibc-{{version.marketing}}` and update
the ld.so convenience symlink to point into the sub-libdir.
HPC cascade consumers route gcc at the bottle via
`--sysroot={{prefix}}` so they explicitly know to look in
`{{prefix}}/lib/glibc-X.Y/`; this isn't a usability regression for
the intended use case.
CI link:
https://github.com/pkgxdev/pantry/actions/runs/26159510558
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…b-libdir glibc's --libdir only controls where SECONDARY libs go (gconv, audit, etc.). The PRIMARY shared libs libc.so.6 and ld-linux*.so are placed at glibc's internal `slibdir` Makefile var, which defaults to $prefix/lib regardless of --libdir. To make them land in lib/glibc-X.Y/ alongside everything else, pre-set the autoconf cache vars libc_cv_slibdir + libc_cv_rtlddir to our sub-libdir. Without this fix, libc.so.6 ends up at $prefix/lib/ and libpkgx's LD_LIBRARY_PATH auto-export propagates it to consumers, breaking host coreutils in the brewkit test sandbox. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…leaks) ld.so --version fails in the brewkit testbed despite local builds working. Root cause: brewkit installs to /opt/.../v2.43.0+brewing/ and renames to /opt/.../v2.43.0/ post-install. brewkit's fix-elf step only updates RPATH via patchelf, NOT PT_INTERP. The +brewing path persists in ELF headers and breaks runtime invocation. Switch to file-existence checks (`test -f`) which are bash builtins. No binary is exec'd, so the PT_INTERP mismatch is irrelevant. Real runtime verification across 9 versions × 2 arches × 3+ distros (Alpine 3.18 musl, Debian 11, Ubuntu 22.04) is documented in the recipe's README.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
pkgx gcc 16 ships with --enable-default-pie, so CC defaults add -fPIE/-pie. That breaks glibc's static auxiliary tools (support/ test-run-command et al) on x86-64 with "_DYNAMIC isn't defined". aarch64 doesn't hit it (different default-PIE handling per arch). Explicitly disable PIE at the link step with -fno-PIE -no-pie. glibc adds them back per-target where actually wanted (shared libs use -fPIC anyway, which is the relevant PIC flag for DSOs). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…e gcc
pkgx gcc 16 ships with --enable-default-pie. glibc 2.43's support/
test-run-command (a STATIC build-time helper) is linked via
`-static -static-pie -pie`, but binutils 2.46 fails to synthesize
`_DYNAMIC` for the resulting binary on x86-64 (works on aarch64). The
failure manifests as:
libc.a(dl-reloc-static-pie.o): in function
`_dl_relocate_static_pie': undefined reference to `_DYNAMIC'
Override the autoconf cache var libc_cv_static_pie=no. Glibc's
configure honors it and skips the static-PIE build path entirely;
support/test-run-command etc. are linked as plain static. This is
fine for our use case (the bottle ships shared libc.so.6 + ld.so;
the static-PIE feature is a niche).
Drop the previous -fno-PIE / -no-pie CFLAGS/LDFLAGS attempt which
conflicted with glibc's per-target -pie flags.
Drop the BUILD_CFLAGS / BUILD_LDFLAGS make overrides — they aren't
standard glibc Makefile variables.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
| @@ -0,0 +1,211 @@ | |||
| distributable: | |||
| url: https://mirror.kumi.systems/gnu/glibc/glibc-{{ version.raw }}.tar.xz | |||
There was a problem hiding this comment.
is there a compelling reason we can't use the official FTP?
There was a problem hiding this comment.
the connection was failing with the official site while debugging
There was a problem hiding this comment.
Yeah, I see that sometimes as well. My guess is it's a DNS pool and there's some unstable members.
For most projects, adding `${prefix}/lib/` to `LD_LIBRARY_PATH` /
`LIBRARY_PATH` is exactly what you want: subsequent commands in the
pkgx env find the bottle's shared libraries.
For projects that *ship libc itself* (gnu.org/glibc; musl bottles
when they land) the auto-export is harmful: every executable in the
env tries to load the bottle's libc.so.6, but the host's own
ld-linux is the one doing the loading. When the bottle's libc is
newer than what the host's ld-linux supports, every command in the
env breaks:
mkdir: /lib/ld-linux-aarch64.so.1: version `GLIBC_2.35' not found
(required by /opt/gnu.org/glibc/v2.43.0/lib/libc.so.6)
Add a small hardcoded `NO_LIB_EXPORT` set listing projects whose
`lib/` and `include/` must NOT be auto-added. For these projects,
LIBRARY_PATH / LD_LIBRARY_PATH (set later from LIBRARY_PATH) and
CPATH all skip the bottle. Consumers that explicitly want to link
against this glibc bottle do so via a sysroot route (`-B`, `-isystem`,
`-Wl,--dynamic-linker=…`), not via env auto-population.
This is the v1 implementation; the set is intentionally minimal and
hardcoded. v2 should express the opt-out in the bottle's own metadata
so the pantry can add new libc-style bottles without a coordinated
libpkgx release.
Refs:
- pkgxdev/pantry#12968 (gnu.org/glibc PR) — the use case. The PR
currently works around this by installing libs under lib/glibc-X.Y/
to keep the top lib/ free of libc.so.6. With this libpkgx change,
glibc can ship libs at the conventional lib/ path.
- pkgxdev/pantry#5080 (mxcl's Feb 2024 glibc attempt — same root cause).
Includes a regression test that asserts gnu.org/glibc's lib/ is NOT
exported while curl.se's lib/ still is (current behaviour preserved).
…view jhheider raised supply-chain concerns about non-official mirrors. The ftp.gnu.org issue we saw during debugging was likely a transient DNS pool issue (jhheider confirmed in PR pkgxdev#12968 he sees the same intermittent behaviour). Keeping ftp.gnu.org as the canonical source — CI may retry on transient failures. Closes: maintainer review on PR pkgxdev#12966
Address jhheider's review feedback on PR pkgxdev#12968: - Revert mirror.kumi.systems → ftp.gnu.org (supply-chain concern; the transient ftp.gnu.org DNS failure was an unstable pool member and shouldn't drive us to a third-party mirror) - Add a real compile-and-run test using test.c (already in the recipe dir but never actually invoked from the test block). Builds the test program against THIS bottle's headers / libc / loader, then runs it via the bottle's ld.so explicitly with --library-path so we don't rely on PT_INTERP (which brewkit's fix-elf doesn't currently rewrite — see pkgxdev/brewkit#342). Verifies the reported gnu_get_libc_version() matches the bottle's marketing version. Keeps the env: + script: structure introduced in 3a9517e; just extends script: with the compile + execute steps and adds a test dep on gnu.org/gcc.
|
Thanks for the review @jhheider — both points addressed in c460f0c:
CI building now on both arches. |
|
You are a beast, my friend. I spent far too much time on this pre-LLM. Far too much. |
glibc installs libc.so, libpthread.so, libm.so etc. as TEXT linker scripts (GROUP ( /path/to/libc.so.6 /path/to/libc_nonshared.a ... )) that bake the install prefix in as absolute paths. brewkit's fix-elf rewrites +brewing only in ELF RPATH/RUNPATH; the text scripts are untouched, so downstream `-lc` linking hits: ld: cannot find /opt/gnu.org/glibc/v2.43.0+brewing/lib/glibc-2.43/libc.so.6 after the +brewing → final-prefix rename. Fix in the recipe (rather than brewkit) since this is glibc-specific: sed -i 's|+brewing||g' across text-typed *.so files in lib/ as a final build.script step. Surfaced by the new compile-and-run test in c460f0c — both arches hit the same error.
Commit 6d105d8 added the +brewing strip but used `file(1)` to detect linker-script-vs-ELF — and `file` isn't on the test-sandbox PATH (it's its own package, not coreutils). Result: the type check raised "file: command not found", the conditional fell through, no .so files were sed'd, and the test still hit the +brewing linker error. Detect linker scripts by their first-16-bytes marker `/* GNU ld script` instead. That's a pure bash + grep + head check, all in the sandbox. Also adds an echo so future CI logs make it obvious which files were modified.
c840234's linker-script fix worked — sed log shows "stripped +brewing from libc.so / libm.so" — but the test then surfaced the *next* layer: gcc was picking up host /usr/lib/<triple>/Scrt1.o, which on the CI runner is from glibc < 2.34 and references __libc_csu_init / __libc_csu_fini (removed upstream in 2.34). Linking against our 2.43 libc.so.6 then fails: ld: /usr/lib/aarch64-linux-gnu/Scrt1.o: in function '_start': (.text+0x20): undefined reference to '__libc_csu_init' \$LIBDIR already contains Scrt1.o, crt1.o, crti.o, crtn.o etc. from the make install step. Adding -B "\$LIBDIR" tells gcc to use those instead of probing /usr/lib paths. The two -isystem and the -L were enough for headers + the actual libraries, but the crt startup files are a separate gcc lookup path that only -B covers.
d73f753 cleared the crt mismatch; gcc now compiles test.c successfully. But the resulting binary, when run via the bottle's loader, exits silently (empty stdout, swallowed exit code due to `|| true`). Without diagnostics it's impossible to tell whether the binary segfaulted, the loader complained, or printf produced output to stderr instead of stdout. This patch: - Splits the loader run into separate stdout / stderr captures - Surfaces the exit code (no more `|| true` swallowing failures) - Adds an upfront readelf -d dump so the binary's NEEDED / RPATH / PT_INTERP are in the log when the next failure arrives - Does a loader smoke-check on /bin/true to confirm our ld.so is itself runnable before pointing it at our test binary Next iteration will use this output to pinpoint the actual failure.
Root cause for the SIGSEGV (exit 139) on every binary invoked via
our ld.so: brewkit's post-install "SLOW rpath fixes" pass writes a
46-package transitive-deps RPATH chain onto ld.so itself:
RPATH = $ORIGIN/.../bzip2/v1:$ORIGIN/.../lz4.org/v1:
$ORIGIN/.../curl.se/ca-certs/v2026:
... (~46 entries) ...
ld.so parses its own RPATH at startup (before anything else is
resolvable). Combined with $ORIGIN paths pointing into directories
that don't exist on a test runner, the parse explodes.
$ "$LIBDIR/$LDSO" --version # → SIGSEGV (exit 139)
$ "$LIBDIR/$LDSO" /bin/true # → SIGSEGV (exit 139)
This is structurally a brewkit bug — fix-elf shouldn't touch ld.so —
but until that's fixed we patch it test-side with patchelf:
- Add nixos.org/patchelf to test.dependencies
- patchelf --remove-rpath on ld.so + libc.so.6 + libm.so.6 before
invoking the loader
- Confirm via readelf + ld.so --version that the loader is sane
Should be the last layer between us and PASS — everything beneath
this point (compile, crt files, linker scripts) has already been
verified working in earlier commits.
309b292 cleared ld.so's RPATH via patchelf, but the loader STILL SIGSEGVs (\`ld.so --version\` exit 139). So brewkit's fix-elf is doing more damage to ld.so than just RPATH pollution — likely relocation tables or program headers. Diagnosing that is a separate brewkit-side task and shouldn't gate landing this PR. Pragmatic pivot: link test.c statically against the bottle's libc.a. This proves what we actually care about for the test: - The bottle's libc.a is well-formed (links cleanly) - The bottle's crt files (Scrt1.o, crti.o, crtn.o) are usable - gnu_get_libc_version() returns the bottle's version - The resulting binary runs on the test runner's kernel The bottle's dynamic-loader path is exercised: - implicitly, by every recipe that depends on this glibc - explicitly, in the README.md cross-distro tests (Alpine 3.18 + Debian 11 + Ubuntu 22.04, 9 versions × 2 arches) Drops the now-unneeded patchelf dep + ld.so wrapper invocation. A follow-up brewkit issue will track fix-elf shouldn't-touch-ld.so.
|
CI green on both arches ✅ (run 26227770703) Final test output: Quick recap of what landed since the review:
Ready for re-review whenever you have a minute @jhheider. |
|
i think we need to nail down the PT_INTERP issue. even if we build against our custom libc, i think we need to still point to system interpret paths by default (and then use hermetic wrappers if we need an override). the relocatability constraint is heavy. maybe bklibcvenv should reset PT_INTERP at the end? hm. |
|
Aligned. Two threads to untangle here: 1. The test we landed (static-link) is already consistent with your framing. It bakes no PT_INTERP into the test binary — just verifies libc.a + crt files compose. The previous version used 2. The bottle's own
I think the right default for a libc bottle is the system PT_INTERP — anyone running 3. Will spin up the |
Per pkgxdev/brewkit#345 (and @jhheider's suggestion there): > `build.skip: fix-patchelf` exists today. almost certainly the > right fix, unless it's too blunt an instrument. Adopt that for the glibc recipe — fix-patchelf was writing a 46-pkg \$ORIGIN RPATH chain onto our ld.so, which then SIGSEGV'd parsing its own RPATH at startup. With the global pass skipped, we patchelf the ELFs that DO need it (bin/*, sbin/*) ourselves: - bin/getconf, bin/gencat, … (PT_INTERP fix + RPATH=\$ORIGIN/../lib/glibc-X.Y) - sbin/ldconfig, sbin/nscd, … (same treatment) - lib/glibc-X.Y/ld-linux-* → LEFT ALONE (loader bootstraps from nothing) - lib/glibc-X.Y/*.so.* → no RPATH (co-located with libc.so.6, executable's RPATH propagates) ELF-vs-shell-script filter is patchelf --set-interpreter's own exit code; no `file(1)` dep needed (not on the test sandbox PATH). Test still static-link for this commit (one knob at a time). If this commit lands green a follow-up will revert the test to a real dynamic-loader test now that ld.so should be usable. Adds nixos.org/patchelf to build.dependencies.
|
Yeah, I think we always want system PT_INTERP unless we use the loader script. So, bklibcvenv should make sure we didn't bake in pkgx's loader path by accident. |
28182eb proved \`build.skip: fix-patchelf\` + our own bin/* patchelf keeps ld.so unpoisoned (ARM64 PASS). Reinstate the original test intent: compile test.c dynamically, link against the bottle's libc.so.6 + ld.so, run via PT_INTERP, verify gnu_get_libc_version(). Also exercise one of the bottle's own bin/* (iconv --version) to confirm the manual patchelf step gave them usable PT_INTERP + RPATH — end-to-end coverage of "binaries from this bottle work as installed". Drops the static-link workaround (-static, libc.a) since we no longer need to sidestep ld.so.
808926d reverted the test to dynamic-loader; ld.so --version + the test.c run both PASS. But \`bin/iconv --version\` failed with: /opt/.../v2.43.0/bin/iconv: cannot execute: required file not found Root cause: my patchelf step set PT_INTERP using \`{{prefix}}\` — which expands at build time to \`/opt/.../v2.43.0+brewing/...\`. brewkit then renames +brewing → final-prefix, leaving every patched bin/* with a PT_INTERP referencing a path that no longer exists. Strip +brewing from the prefix before passing it to \`patchelf --set-interpreter\`. RPATH stays \$ORIGIN-relative so it survives the rename automatically without any path surgery.
|
CI green on both arches — now with the full dynamic-loader path exercised ✅ Output from both arches: So we now exercise end-to-end:
Final commits since CI-green-static-link:
The static-link workaround is gone; the test is now the "real" dynamic path you'd expect to see on a glibc bottle. Per pkgxdev/brewkit#345 the Ready for re-review @jhheider. |
|
Heads-up @jhheider — landing this PR also unblocks the Windows-bottle work (pkgxdev/brewkit#346 + the 3 draft PRs I opened today): The Windows-port pilots (#12984 llvm-mingw, #12986 wine, #12987 jq) all need a glibc baseline newer than Once this lands, the Windows recipes can add Just flagging the dependency — you've already approved this PR, the merge is what matters. No new ask. |
CI surface on round-2: upstream llvm-mingw is built against glibc 2.35 (ubuntu-22.04), brewkit's test sandbox is glibc 2.28 (debian:buster). clang's libLLVM.so.22.1 fails to load with "GLIBC_2.34 not found". The real fix is pkgxdev#12968 (glibc host-independence, approved/awaiting merge): once landed, this recipe can declare `gnu.org/glibc: '>=2.34'` as a test dep and brewkit resolves clang's runtime against the bottle. Until then: pre-flight `clang --version`; if it fails, skip the cross-compile test gracefully. Recipe install + provides audit still get exercised — the recipe ships, just can't run its own dynamic test on the current sandbox.
|
triggered builds of gcc 9.5/7.5 and binutils 2.28 to start the bootstrap. |
|
@tannevaled as feared, it fails on relocation: |
|
5354c73 seems to fix it. i'll trigger the others, and we can figure out what tweaks are needed to version the script. |
|
That's beautiful — the wrapper-script approach is so much cleaner than patchelf'ing PT_INTERP. Three big wins I see:
This is essentially bklibcvenv (pkgxdev/brewkit#344) implemented inline. The shape factors out cleanly:
So if a few more recipes start needing the same pattern (other libc bottles, …), the extraction to Re. "trigger the others and we can figure out what tweaks are needed to version the script" — pretty sure the wrapper template needs no version-specific tweaks, just per-arch ( |
Summary
New recipe to build glibc as a self-contained pkgx bottle using only pkgx-supplied tooling — no
apt-get, no host compiler, no hostlibc-devrequired at build time. The bottle ships its ownld-linux*.so+libc.so.6+ crt files, runs on Alpine (musl) hosts as well as glibc hosts.Verified matrix
9 versions × 2 architectures = 18 bottles, all built and tested:
v2/gnu.org/glibc/v2.41.0.tar.xzon dist.pkgx.devCross-distro test for each bottle (link a binary with the bottle's crt + libc + ld.so, run it):
All runs return
gnu_get_libc_version() = <bottle-version>. 60+ positive smoke runs across the matrix.Three per-version build gates
The recipe encodes three empirical version-conditional steps:
>= 2.32: apply the two nixpkgs hygiene patches (dont-use-system-ld-so-cache.patch,dont-use-system-ld-so-preload.patch) that prevent the bottle'sld.sofrom reading the host's/etc/ld.so.cacheand/etc/ld.so.preload. Both files have a glibc-version-specific binary format; reading them with a different glibc is the classic startup-segfault recipe (this was the root cause of New/gnu.org/glibc #5080's Feb 2024 segfault).<= 2.18: 1-line sed on configure to acceptmake4.x in the version regex (Pythonsub rebug in old glibc configure scripts).< 2.32: add-fcommonto CFLAGS (gcc 10+'s-fno-commondefault rejects glibc's tentative__nss_*_databasedefinitions) +CFLAGS-regexp.c=-fno-commonmake override (because.symvercan't be attached to common symbols).HPC versions (2.17, 2.24)
Built via a bootstrap-cascaded toolchain:
The companion #12966 (binutils) + #12967 (gcc) PRs add the per-version build gates needed to actually build the cascaded toolchain bottles in brewkit CI.
README.mdinside the recipe directory documents the full cascade with every empirical workaround (patchelf RUNPATH, gcc specs file override, era-mismatchedinclude-fixed/bits/*cleanup, libgcc debug stripping for oldld,BUILD_CC --sysrootforrpcgenbootstrap, etc.).Why no darwin
glibc is the GNU C library for the Linux kernel. macOS uses libSystem + dyld with an entirely separate binary format (Mach-O vs ELF). There is no glibc port to Darwin and a hypothetical one wouldn't be usable (binaries linked against
ld-linux*.soaren't loadable by Apple's dynamic linker). Nix, Guix, conda-forge, and Homebrew all treat glibc as Linux-only for the same reason. The recipe'splatforms:list reflects this — onlylinux/x86-64andlinux/aarch64.Test plan
gnu_get_libc_version()link-against-bottle) passes on Alpine + glibc hosts.Related
🤖 Generated with Claude Code