fix(gnu.org/gcc): add libc-wrapper for end-user pkgx gcc (#8423)#13094
Open
tannevaled wants to merge 5 commits into
Open
fix(gnu.org/gcc): add libc-wrapper for end-user pkgx gcc (#8423)#13094tannevaled wants to merge 5 commits into
tannevaled wants to merge 5 commits into
Conversation
End-user `pkgx gcc test.c` on a host without distro glibc-devel / libc6-dev couldn't find stdlib.h + crt*.o. Earlier attempts via runtime.env (pkgxdev#13084) and --with-sysroot (pkgxdev#13092) failed because both poisoned gcc's own bootstrap build. This take installs a thin POSIX-sh wrapper at {{prefix}}/bin/<tool> (modeled on the bklibcvenv pattern, brewkit#348) that: 1. resolves the sibling gnu.org/glibc bottle relative to its own install path 2. exec's the real binary (moved to libexec/gcc-wrap/) with -isystem $glibc/include + -L$glibc/lib appended 3. NO-OPs when CPATH is already set (brewkit build-context — the bootstrap gcc loop uses brewkit-composed CPATH, so injecting pkgx-glibc paths twice is unnecessary and could trigger C23 symbol mismatches like __isoc23_strtoul) Pinning gnu.org/glibc <2.38 avoids C23 symbol redirects absent on older CI/host runners; the wrapper's runtime CPATH check guards against build-time poisoning regardless. Wrappers cover gcc, g++, cpp, c++, gfortran. The existing cc -> gcc and gc++ -> c++ symlinks still resolve (now via the wrapper). The wrapper dispatches by $0 basename. Pairs with pkgxdev#13083 (multi-arch triplet symlinks). Together they should fully close pkgxdev#8423. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The runtime dep on gnu.org/glibc poisoned gcc's own bootstrap build:
brewkit exposes runtime deps via CPATH/LIBRARY_PATH during build too,
so configure-time test programs end up compiling against pkgx libc
2.34 but running on the host's ld-linux — and ld-linux finds host
libc 2.35 in the default path even with LD_LIBRARY_PATH set,
producing `cannot run C++ compiled programs`.
The wrapper itself doesn't need the dep declared — it does a runtime
sibling lookup (`bindir/../../../glibc/v*`) that no-ops if no pkgx
glibc is present. Users who want the bottled libc explicitly add it:
pkgx +gnu.org/gcc +gnu.org/glibc gcc test.c
This trades automatic resolution for a clean bootstrap. Closing
this trade-off the "right" way needs a pkgx feature to separate
runtime-only deps from build-time-injected deps.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When the wrapper detects a sibling pkgx glibc bottle, it now also passes: -Wl,--dynamic-linker=$glibc/lib/ld-linux-*.so.* -Wl,-rpath,$glibc/lib so the produced binary's ELF interpreter (PT_INTERP) points at pkgx ld-linux. End-to-end consistency: the same libc is used at compile, link, and exec. Without this, the binary's PT_INTERP would be the host's /lib64/ld-linux-x86-64.so.2 and the kernel would load host ld-linux at exec time — even with -L pointing at pkgx libc and rpath set — mixing libc internal layouts across host/pkgx. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When a pkgx glibc sibling is found, wrapper now also passes -nostdinc (and -nostdinc++ for g++/c++) to drop /usr/include from gcc's search path, then re-adds: - gcc's own builtin headers (lib/gcc/<triplet>/<ver>/include[+-fixed]) - libstdc++ headers for C++ tools (include/c++/<ver>[/<triplet>]) - pkgx glibc headers via -isystem Without -nostdinc, gcc still found /usr/include/stdlib.h first because -isystem only appends to the search chain — so pkgx-glibc headers were shadowed by whatever the host had. Modeled on Nix's cc-wrapper.sh (pkgs/build-support/cc-wrapper/). See pkgxdev#8423. The wrapper stays opportunistic (CPATH unset + sibling glibc), so the gcc bootstrap loop is unaffected. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous shape moved the real gcc binary to libexec/gcc-wrap/,
which broke gcc's relative lookup for cc1 / cc1plus / collect2 (gcc
expects them at lib/gcc/<triplet>/<version>/ relative to its OWN
location). Result: `cannot execute 'cc1': No such file or directory`
during fixincludes at make-install time.
Keep the real binary at bin/.${tool}-real (hidden by leading dot
to avoid cluttering bin/) and have bin/<tool> point at the wrapper.
cc1 lookup then resolves the same way it always did.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a thin POSIX-sh wrapper at
{{prefix}}/bin/<tool>(gcc, g++, cpp, c++, gfortran) that injects-isystem $glibc/include -L$glibc/libfor end-user invocations, without poisoning gcc's own bootstrap build. The real binaries are moved to{{prefix}}/libexec/gcc-wrap/. Addsgnu.org/glibc: '<2.38'+kernel.org/linux-headers: '*'as Linux deps so pkgx provisions a sibling glibc bottle the wrapper can find.Why this approach
Previous attempts at #8423:
runtime.env CPATH): clobbered brewkit's composed CPATH during gcc's own build → couldn't findgmp.h. Closed.--with-sysroot): configure-time test programs link against the bottled glibc's interp path which doesn't exist on the host →cannot run C++ compiled programs. Closed.This take avoids both pitfalls because the wrapper:
$0-relative lookup, not via baked-in configure flags<2.38to avoid C23 symbol redirects (__isoc23_*) absent on older runnersPattern is modeled on the bklibcvenv shim (brewkit#348).
Pairs with
Test plan
pkgx gcc -E -x c /dev/nullsucceeds without distro glibc-develglibc-devel,pkgx gcc test.c -o test && ./testsucceedspkgx +gnu.org/gcc cc -v 2>&1 | grep gnu.org/glibcconfirms the wrapper found the bottleif: linux)🤖 Generated with Claude Code