From 750f89068d20e99b4867b5cfc84dc6383dcf65c1 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Wed, 20 May 2026 11:05:32 +0200 Subject: [PATCH 1/2] =?UTF-8?q?feat(gcc):=20support=20older=20versions=20(?= =?UTF-8?q?5=E2=80=939)=20for=20HPC=20bootstrap=20cascade?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the per-version build gates needed to build gcc 5-9 alongside the current modern versions (10.5–16.1). These older bottles are required to build glibc 2.17-2.26 host-independent — modern gcc's default code generation choices (PIC semantics, code-model defaults) conflict with old glibc's build assumptions. Changes (all linux-only; darwin unaffected): - Accept .tar.gz and .tar.bz2 in distributable for older gcc that didn't publish .tar.xz (≤ 5.4 only had bz2/gz). - Move the three PIE-by-default linux flags from the unconditional `linux: ARGS` block into in-script per-version gates: --enable-default-pie : gcc 6+ --enable-pie-tools : gcc 9+ --enable-host-pie : gcc 13+ Current bottles (≥ 10.5) get the same flags they got before. Old gcc avoids configure errors on "unrecognized option". - Gate --disable-lto + --disable-plugin behind '<10'. LTO and the linker plugin both load shared objects that mix libc versions when the bottle is used cascaded against a different-era glibc; disabling them keeps the old-gcc cascade clean. Modern bottles keep LTO. - Bake RUNPATH for mpc/mpfr/gmp/zlib into all linked binaries via LDFLAGS so the resulting cc1/cc1plus run without LD_LIBRARY_PATH. - Post-install, only for `version.major < 10`: - Disable era-mismatched include-fixed/bits/* files (gcc's fixincludes generates these from the modern HOST glibc headers; they reference symbols absent in the old target glibc — openat2, statx-flags-bits, etc.). - Strip zlib-compressed .debug_info from libgcc/crt static archives (binutils < ~2.36 can't decompress these). Both wrapped in `if [ {{version.major}} -lt 10 ]` so current bottles are unchanged. --enable-languages is unchanged: c,c++,objc,obj-c++,fortran for ALL versions. Old gcc may fail to build libobjc / libgfortran when cascaded with a new glibc bottle, but rather than silently shipping a stripped-language bottle that breaks downstream packages depending on gfortran/obj-c++, let configure/CI surface the failure clearly so it can be addressed per-version. Empirically validated by building gcc 7.5 and gcc 9.5 with this recipe on linux/aarch64 (native, Apple Silicon Docker) and gcc 9.5 on linux/x86-64 (Rosetta emulation), in a debian:bookworm-slim container using only pkgx-supplied tooling. Co-Authored-By: Claude Opus 4.7 --- projects/gnu.org/gcc/package.yml | 72 +++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/projects/gnu.org/gcc/package.yml b/projects/gnu.org/gcc/package.yml index 0c29b1ef72..73c5f027ef 100644 --- a/projects/gnu.org/gcc/package.yml +++ b/projects/gnu.org/gcc/package.yml @@ -1,11 +1,25 @@ distributable: - url: https://ftp.gnu.org/gnu/gcc/gcc-{{version.raw}}/gcc-{{ version.raw }}.tar.xz - strip-components: 1 + - url: https://ftp.gnu.org/gnu/gcc/gcc-{{version.raw}}/gcc-{{ version.raw }}.tar.xz + strip-components: 1 + # Pre-5.5 gcc only published .tar.bz2 / .tar.gz; needed for cascade to + # glibc 2.17 (which empirically wants gcc ~7.5 to build cleanly). + - url: https://ftp.gnu.org/gnu/gcc/gcc-{{version.raw}}/gcc-{{ version.raw }}.tar.gz + strip-components: 1 + - url: https://ftp.gnu.org/gnu/gcc/gcc-{{version.raw}}/gcc-{{ version.raw }}.tar.bz2 + strip-components: 1 versions: github: gcc-mirror/gcc/tags strip: /^releases\/gcc-/ +# NOTE: pkgx today ships 10.5 – 16.1. Older gcc (5–9) is required to +# build glibc 2.17 – 2.26 (HPC / manylinux2014 / RHEL 7-8) because +# glibc’s rtld sources emit relocation forms newer binutils ld reject +# in shared/PIE mode, and modern gcc’s default code-gen choices (PIC +# semantics, code-model defaults) conflict with old glibc build +# assumptions. The empirically-validated cascade (linux/aarch64 and +# linux/x86-64) is documented in projects/gnu.org/glibc/README.md. + dependencies: gnu.org/binutils: "*" # linker needs `as` gnu.org/gmp: ">=4.2" @@ -68,6 +82,28 @@ build: - run: export ARGS=("${ARGS[@]}" --with-boot-ldflags="-static-libstdc++ -static-libgcc $LDFLAGS") if: linux + # PIE-by-default linux flags were added across gcc versions: + # --enable-default-pie : gcc 6+ + # --enable-pie-tools : gcc 9+ + # --enable-host-pie : gcc 13+ + # Add each only when the gcc version supports it, so older gcc + # (used in the HPC cascade to build glibc 2.17/2.24) doesn't fail + # configure with "unrecognized option". + - run: | + if [ {{version.major}} -ge 6 ]; then ARGS=("${ARGS[@]}" --enable-default-pie); fi + if [ {{version.major}} -ge 9 ]; then ARGS=("${ARGS[@]}" --enable-pie-tools); fi + if [ {{version.major}} -ge 13 ]; then ARGS=("${ARGS[@]}" --enable-host-pie); fi + export ARGS + if: linux + + # Bake mpc / mpfr / gmp / zlib RUNPATH into all linked binaries so + # the built gcc + cc1 / cc1plus run without requiring + # LD_LIBRARY_PATH at runtime. + - run: | + DEPRP="{{deps.gnu.org/mpc.prefix}}/lib:{{deps.gnu.org/mpfr.prefix}}/lib:{{deps.gnu.org/gmp.prefix}}/lib:{{deps.zlib.net.prefix}}/lib" + export LDFLAGS="$LDFLAGS -Wl,-rpath,$DEPRP -Wl,-rpath-link,$DEPRP" + if: linux + # needed to get the LDFLAGS to libgfortran on darwin # for -headerpad_max_install_names - run: export LDFLAGS_FOR_TARGET="$LDFLAGS" @@ -77,6 +113,27 @@ build: - make --jobs {{ hw.concurrency }} - make install + # For old-gcc bottles intended to participate in the HPC cascade + # (gcc 5–9 used to build glibc 2.17–2.26), strip the era-mismatched + # include-fixed/bits/* files that gcc's install-time fixincludes + # generated from the host's modern glibc headers. They reference + # symbols (openat2, statx-flags-bits, ...) absent in the old glibc + # this gcc will build. Also strip the zlib-compressed .debug_info + # from libgcc/crt so very old binutils ld can read them. + # No-op for current gcc bottles (>= 10). + - run: | + if [ {{version.major}} -lt 10 ]; then + for d in {{prefix}}/lib/gcc/*/{{version.raw}}/include-fixed; do + [ -d "$d/bits" ] || continue + mv "$d/bits" "$d/bits.disabled-by-pantry" || true + mkdir -p "$d/bits" + done + find {{prefix}}/lib/gcc -name 'libgcc*.a' -o -name 'crt*.o' 2>/dev/null | while read f; do + {{deps.gnu.org/binutils.prefix}}/bin/strip --strip-debug "$f" 2>/dev/null || true + done + fi + if: linux + # Since we depend on ourselves, this symlink might already exist - run: test -f gc++ || ln -sf c++ gc++ working-directory: ${{prefix}}/bin @@ -130,12 +187,17 @@ build: - --disable-bootstrap - --disable-nls - --with-system-zlib + # For old gcc (< 10) used in the HPC bootstrap cascade, also + # disable LTO and the linker plugin. Both load shared objects that + # mix libc versions across host ld-linux and the bottle's libc at + # link time. Modern gcc bottles (≥ 10) keep LTO enabled. + '<10': + ARGS: + - --disable-lto + - --disable-plugin linux: ARGS: - --disable-multilib - - --enable-default-pie - - --enable-pie-tools - - --enable-host-pie linux/x86-64: LDFLAGS: - -pie From 4d9b1923cecb94c666be7b883f4eaaa7d493bbcb Mon Sep 17 00:00:00 2001 From: tannevaled Date: Wed, 20 May 2026 11:16:48 +0200 Subject: [PATCH 2/2] fix(gcc): use script-level if: gate, not env version block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The brewkit pantry parser rejects '<10' as a nested block key inside build.env (`invalid constraint`). Move the version-conditional --disable-lto / --disable-plugin into a script-level run: with `if: '<10'` — same syntax pattern used in autoconf, bc, etc. CI link from failure run: https://github.com/pkgxdev/pantry/actions/runs/26152704049 Co-Authored-By: Claude Opus 4.7 --- projects/gnu.org/gcc/package.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/projects/gnu.org/gcc/package.yml b/projects/gnu.org/gcc/package.yml index 73c5f027ef..bf9978ba02 100644 --- a/projects/gnu.org/gcc/package.yml +++ b/projects/gnu.org/gcc/package.yml @@ -96,6 +96,13 @@ build: export ARGS if: linux + # For old gcc (< 10) used in the HPC bootstrap cascade, also disable + # LTO and the linker plugin. Both load shared objects that mix libc + # versions across host ld-linux and the bottle's libc at link time. + # Modern gcc bottles (>= 10) keep LTO enabled. + - run: ARGS=("${ARGS[@]}" --disable-lto --disable-plugin); export ARGS + if: '<10' + # Bake mpc / mpfr / gmp / zlib RUNPATH into all linked binaries so # the built gcc + cc1 / cc1plus run without requiring # LD_LIBRARY_PATH at runtime. @@ -187,14 +194,6 @@ build: - --disable-bootstrap - --disable-nls - --with-system-zlib - # For old gcc (< 10) used in the HPC bootstrap cascade, also - # disable LTO and the linker plugin. Both load shared objects that - # mix libc versions across host ld-linux and the bottle's libc at - # link time. Modern gcc bottles (≥ 10) keep LTO enabled. - '<10': - ARGS: - - --disable-lto - - --disable-plugin linux: ARGS: - --disable-multilib