From 22bf487b1ad30edbfb931dd27e6675c8e378b2a0 Mon Sep 17 00:00:00 2001 From: Sergio Date: Sun, 6 Sep 2026 20:08:53 +0000 Subject: [PATCH] =?UTF-8?q?gcc-libs:=20las=20librer=C3=ADas=20de=20ejecuci?= =?UTF-8?q?=C3=B3n=20que=20faltaban=20(b3:aa605af4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit libstdc++.so.6 (20.850.968 bytes) y libgcc_s.so.1 (824.776), construidas desde el tarball de GCC 15.2.0 — la MISMA versión del lab, porque firefox se enlaza contra la libstdc++ compartida de ese gcc y otra versión traería de vuelta el mismo fallo disfrazado. sha512 del tarball verificado byte a byte contra el APKBUILD de Alpine. Tres decisiones que no son de estilo: --disable-symvers Alpine lo pasa. El versionado cambia la tabla de símbolos; nuestros binarios se enlazaron contra la libstdc++ SIN versionar del lab. link = "dynamic" hammer inyecta LDFLAGS=-static por defecto y acá el producto ES una librería compartida: con el default no saldría ni un .so. Misma perilla que apagaba los threads de openssl, vista desde el otro lado. --disable-bootstrap Sólo `all-target-libgcc all-target-libstdc++-v3`. GCC entero multiplica el tiempo por cinco para tirar el compilador a la basura. Los guardianes se ganaron el sueldo en las dos primeras corridas: 1ª «!! falta libstdc++.so.6» — y las librerías estaban perfectas: GCC instala en /usr/lib64 porque su t-linux64 fija MULTILIB_OSDIRNAMES=../lib64, y --disable-multilib NO lo apaga. Un .so impecable en el directorio que el loader no mira es EXACTAMENTE el fallo que esta receta viene a arreglar, un directorio más allá. Se normaliza a lib en el install. 2ª «!! no definen los símbolos» — y sí los definían. --disable-symvers apaga el versionado de libstdc++, pero libgcc tiene su PROPIO libgcc.map y versiona igual: nm los imprime como _Unwind_Backtrace@@GCC_3.3 y el grep anclado al fin de línea no los veía. El fallo era del guardián. Verificado contra el libgcc_s.so.1 DEL LAB —el que satisface a firefox hoy— y coinciden hasta en la etiqueta de versión. gmp/mpfr/mpc ya existían pero sólo en recipes/incoming-*, con DOS variantes cada una. Promovidas las de incoming-kde y no las de cosmic: la terna tiene que ser internamente coherente porque mpc enlaza su .so contra las otras dos, y con las de cosmic (estáticas sin PIC) muere en «relocation R_X86_64_32 ... recompile with -fPIC». La de kde va con link=dynamic las tres y además ya estaba SELLADA entera, así que la promoción no costó ni un build. --- recipes/gcc-libs.toml | 169 ++++++++++++++++++++++++++++++++++++++++++ recipes/gmp.toml | 52 +++++++++++++ recipes/mpc.toml | 28 +++++++ recipes/mpfr.toml | 31 ++++++++ 4 files changed, 280 insertions(+) create mode 100644 recipes/gcc-libs.toml create mode 100644 recipes/gmp.toml create mode 100644 recipes/mpc.toml create mode 100644 recipes/mpfr.toml diff --git a/recipes/gcc-libs.toml b/recipes/gcc-libs.toml new file mode 100644 index 00000000..6a07f181 --- /dev/null +++ b/recipes/gcc-libs.toml @@ -0,0 +1,169 @@ +# gcc-libs — `libstdc++.so.6` y `libgcc_s.so.1`. LAS LIBRERÍAS DE EJECUCIÓN QUE FALTABAN. +# +# ══ POR QUÉ EXISTE, Y CÓMO SE DESCUBRIÓ ════════════════════════════════════════════════════════ +# No salió de leer el grafo sino de CORRER el navegador. El 2026-09-06, `atuq` bajo un sway headless +# murió con decenas de `Error relocating: _ZNKSt5ctypeIcE13_M_widen_initEv: symbol not found`. El +# binario SELLADO de firefox declara: +# +# NEEDED libstdc++.so.6 NEEDED libgcc_s.so.1 NEEDED libc.so +# +# y las dos primeras no existían en el store ni en ningún cierre: sólo en `.dev-fs/alpine`, o sea en +# el LAB. `scripts/audit-needed.sh` midió el alcance: 6 recetas colgantes —`firefox`, `atuq`, +# `waterfox`, `librsvg`, `spidermonkey`, `mesa-llvmpipe`— y SÓLO ESTOS DOS sonames faltando en todo +# el corpus. Como `firefox` y `atuq` son raíces de los CUATRO perfiles de escritorio, las cuatro +# imágenes llevaban un navegador que no podía arrancar. +# +# Lo que lo hizo caro es que ninguna métrica lo veía: `build-state.json` decía `sealed`, +# `verificar-repro.sh` decía que REPRODUCE bit a bit y los tres guardianes de la receta pasaban. +# **El verde responde «¿construye?», nunca «¿corre?».** +# +# ══ POR QUÉ SE CONSTRUYE GCC ENTERO PARA DOS `.so` ═════════════════════════════════════════════ +# Porque no hay otra fuente: `libstdc++` no tiene tarball propio, es parte del árbol de GCC (Alpine +# la publica como subpaquete de su aport `gcc`). Se construye SÓLO lo necesario —los target libs— +# con `--disable-bootstrap`, que evita las tres etapas y es la diferencia entre una hora y cinco. +# +# ⚠ LA VERSIÓN NO ES LIBRE: 15.2.0 PORQUE ES LA DEL LAB. `firefox` se enlaza con el `clang++` del +# lab, que usa la `libstdc++` COMPARTIDA del gcc del lab — 15.2.0, `libstdc++.so.6.0.34`. Si acá se +# construyera otra versión, el `.so` existiría y los símbolos podrían no cuadrar: el modo de fallo +# volvería, disfrazado de otra cosa. Un bump del lab obliga a bumpear esto. +# +# ⚠ `--disable-symvers` NO ES OPCIONAL Y NO ES COPIA CIEGA. Alpine lo pasa, y el versionado de +# símbolos cambia la tabla de símbolos de la librería. Nuestros binarios se enlazaron contra la +# libstdc++ SIN versionar del lab; una con versionado no los satisface. Verificado en el APKBUILD de +# `main/gcc` de Alpine el 2026-09-06, junto con el resto de los flags de ABI de abajo. +# +# Verificado: el sha512 del tarball coincide byte a byte con el del APKBUILD de Alpine. +name = "gcc-libs" +version = "15.2.0" +license = "GPL-3.0-or-later WITH GCC-exception-3.1" + +[source] +tarball = "https://ftp.gnu.org/gnu/gcc/gcc-15.2.0/gcc-15.2.0.tar.xz" +sha256 = "438fd996826b0c82485a29da03a72d71d6e3541a83ec702df4271f6fe025d24e" + +[build] +# Se construye GCC con el gcc del lab: es el camino que upstream prueba, y con zig-cc el configure +# de GCC pelea por las mismas tres razones que ya documenta `firefox.toml`. +compiler = "gcc" +# ⚠ `dynamic` ES EL PUNTO DE LA RECETA. hammer inyecta `LDFLAGS=-static` en modo estático, y acá el +# producto ES una librería compartida: con el default no saldría ni un `.so`. Es la misma perilla +# que apagaba los threads de openssl, vista desde el otro lado. +link = "dynamic" + +[deps] +# gmp/mpfr/mpc son las tres que el configure de GCC exige aunque sólo se quieran los target libs: +# el top-level configura también el compilador. Estaban ya en `recipes/incoming-*`; se promovieron +# al catálogo canónico para poder declararlas desde acá (la resolución es sibling-first y una receta +# de `recipes/` no ve las de una cola). +build = ["make", "m4", "gmp", "mpfr", "mpc"] + +[build.phases] +configure = ''' +set -e +# GCC EXIGE construir fuera del árbol de fuentes; si no, el configure aborta. +mkdir -p build && cd build + +# Los flags de ABI son los de Alpine (`main/gcc`, verificado el 2026-09-06). No son preferencias: +# esta librería tiene que ser intercambiable con la que el lab le dio a firefox al enlazar. +../configure \ + --prefix=/usr \ + --build=x86_64-alpine-linux-musl \ + --host=x86_64-alpine-linux-musl \ + --target=x86_64-alpine-linux-musl \ + --enable-languages=c,c++ \ + --disable-bootstrap \ + --disable-symvers \ + --disable-libstdcxx-pch \ + --disable-multilib \ + --disable-nls \ + --disable-werror \ + --disable-cet \ + --disable-fixed-point \ + --disable-libssp \ + --disable-libsanitizer \ + --disable-libgomp \ + --disable-libitm \ + --disable-libquadmath \ + --enable-__cxa_atexit \ + --enable-default-pie \ + --enable-default-ssp \ + --enable-shared \ + --enable-threads \ + --enable-tls \ + --enable-checking=release \ + --with-linker-hash-style=gnu +''' +compile = ''' +set -e +cd build +# SÓLO los target libs. `all` construiría el compilador entero, que no queremos y que multiplica el +# tiempo. Make resuelve solo que para llegar acá hace falta un xgcc de etapa 1. +make -j"$(nproc)" all-target-libgcc all-target-libstdc++-v3 +''' +install = ''' +set -e +cd build +make install-target-libgcc install-target-libstdc++-v3 DESTDIR=/out + +# ⚠ GCC INSTALA EN `lib64`, Y `--disable-multilib` NO LO APAGA. En x86_64 el `t-linux64` de GCC fija +# `MULTILIB_OSDIRNAMES = ../lib64`, así que el install aterriza en `/usr/lib/../lib64/` — o sea +# `/usr/lib64/`— por más que se haya desactivado el multilib. Esta distro es `lib`-only, como el +# Alpine del que sale el lab, así que se normaliza acá. +# +# No es cosmético: el enlazador dinámico busca en `/usr/lib`, y un `.so` perfecto en `/usr/lib64` +# es exactamente el fallo que esta receta viene a arreglar, sólo que un directorio más allá. Lo +# cazó el guardián 1 en la primera corrida (`!! falta libstdc++.so.6`), que es para lo que está. +if [ -d /out/usr/lib64 ]; then + mkdir -p /out/usr/lib + cp -a /out/usr/lib64/. /out/usr/lib/ # `-a` preserva los symlinks .so.6 -> .so.6.0.34 + rm -rf /out/usr/lib64 +fi + +# Se PODA todo lo que no sea runtime: headers, `.a`, `.la`, libsupc++, los `.py` del pretty-printer. +# Esta receta existe para que un binario ARRANQUE, no para compilar contra ella; dejar los headers +# invitaría a que otra receta se enlace contra esto en vez de contra el lab, que es una decisión +# distinta y no la que se está tomando acá. +find /out -name '*.la' -delete +rm -rf /out/usr/include /out/usr/share /out/usr/lib/gcc +find /out -name '*.a' -delete +find /out -name '*.py' -delete + +L=/out/usr/lib +test -d "$L" || { echo "!! no se instaló nada en $L" >&2; find /out -maxdepth 3 >&2; exit 1; } + +# ── GUARDIÁN 1: los dos sonames, y que sean los que el loader busca ────────────────────────── +# No alcanza con que exista un fichero llamado así: lo que el enlazador dinámico usa es el SONAME +# de dentro. Un `.so` bien nombrado con otro soname no lo encuentra nadie. +for so in libstdc++.so.6 libgcc_s.so.1; do + f=$(find "$L" -name "$so*" -o -name "$so" | head -1) + test -n "$f" || { echo "!! falta $so" >&2; ls -la "$L" >&2; exit 1; } + real=$(readelf -d "$f" 2>/dev/null | sed -n 's/.*SONAME.*\[\(.*\)\].*/\1/p') + test "$real" = "$so" || { echo "!! $f tiene SONAME '$real' y esperaba '$so'" >&2; exit 1; } + echo "guardián: $so ok (SONAME correcto, $(stat -Lc%s "$f") bytes)" +done + +# ── GUARDIÁN 2: LA PRUEBA DEL CONSUMIDOR ───────────────────────────────────────────────────── +# «Existe» no es «sirve». Se exige que estén DEFINIDOS los símbolos exactos que firefox no +# encontraba — copiados del fallo real de `atuq`, no inventados. Si esta receta sella sin ellos, +# el navegador vuelve a morir igual y el artefacto habría dicho que todo bien. +# ⚠ EL SÍMBOLO PUEDE VENIR VERSIONADO, Y LA PRIMERA VERSIÓN DE ESTE GUARDIÁN NO LO CONTEMPLABA. +# `--disable-symvers` desactiva el versionado de **libstdc++**, pero `libgcc` tiene su PROPIO +# `libgcc.map` y sigue versionando pase lo que pase. Así que `nm` los imprime como +# `_Unwind_Backtrace@@GCC_3.3`, y un grep anclado al fin de línea NO los encuentra: el guardián +# reportaba «no definen los símbolos» sobre una librería que los definía perfectamente. +# Comprobado contra el `libgcc_s.so.1` DEL LAB —el que hoy satisface a firefox— y coinciden hasta +# en la etiqueta de versión: `_Unwind_Backtrace@@GCC_3.3`, `__udivti3@@GCC_3.0`. +falta="" +for s in _ZNKSt5ctypeIcE13_M_widen_initEv _ZNSt13runtime_errorC1EPKc _ZNKSt9bad_alloc4whatEv; do + nm -D --defined-only "$L"/libstdc++.so.6* 2>/dev/null | grep -qE " $s(@|\$)" || falta="$falta $s" +done +for s in _Unwind_Backtrace _Unwind_GetIP __udivti3; do + nm -D --defined-only "$L"/libgcc_s.so.1* 2>/dev/null | grep -qE " $s(@|\$)" || falta="$falta $s" +done +test -z "$falta" || { + echo "!! los .so están pero NO definen los símbolos que firefox pide:$falta" >&2 + echo " (son los del fallo real de atuq; si cambiaron, revisá --disable-symvers)" >&2 + exit 1 +} +echo "guardián: los 6 símbolos que firefox no encontraba están DEFINIDOS" +''' diff --git a/recipes/gmp.toml b/recipes/gmp.toml new file mode 100644 index 00000000..bea06d46 --- /dev/null +++ b/recipes/gmp.toml @@ -0,0 +1,52 @@ +# ── ⚠ HAY DOS `gmp` EN EL CORPUS, Y ES A PROPÓSITO (verificado 2026-09-01) ───────────────────── +# `incoming-kde/gmp.toml` (ésta) y `incoming-cosmic/gmp.toml` emiten el MISMO nombre de artefacto y +# sellan en direcciones distintas. NO es un duplicado rancio que haya que unificar — son dos +# variantes deliberadas, y la diferencia está en las dos líneas que importan: +# +# KDE link=dynamic --enable-shared --enable-cxx ⇒ libgmp.so + libgmpxx.so +# COSMIC link=static --disable-shared ⇒ libgmp.a, sin C++ +# +# Y las dos citan a libqalculate como consumidor con conclusiones opuestas sobre `gmpxx.h`: acá se +# activa porque el libqalculate de la campaña KDE lo exige; allá se apaga a propósito para no +# arrastrar el runtime de C++. Las dos están selladas y las dos son correctas para su frente. +# +# ⚠ LO QUE SÍ CUESTA, Y CUÁNDO. Compartir nombre hace ambigua la clasificación de `store-gc.sh`: un +# artefacto rancio de UNA de las dos puede caer como SUPERADO porque la OTRA tiene sellado vigente, +# y ahí se perdería el único ejemplar. La condición es precisa: **sólo corre riesgo si el hash +# vigente de una de las dos NO está sellado**. Medido el 2026-09-01: las dos selladas ⇒ exposición +# CERO. Antes de podar con nombres compartidos, comprobar eso, no el nombre. +# +# `mpfr` tiene exactamente el mismo par (KDE dynamic / COSMIC static) por la misma razón. +# ⇒ Si algún día molesta de verdad, la salida NO es unificar sino renombrar la dinámica a +# `gmp-shared`, que es la convención que el corpus ya usa (zlib-shared, cairo-shared…). Cuesta +# re-hashear: `yupana radio` da 7 sellados de KDE que caen a deuda. No se hizo por eso. +# GNU GMP 6.3.0 — aritmética de enteros/racionales/floats de precisión arbitraria (libgmp.so + libgmpxx.so). +# Campaña KDE (ADR 0011): sustrato de libqalculate (motor matemático de KCalc/KRunner), que exige el +# interfaz C++ gmpxx.h además del C. También base de mpfr (#2 de esta tanda). +# +# compiler=zig-cc + --disable-assembly: GMP trae asm x86_64 a mano, pero el gueto-gcc del sandbox falla el +# test de configure ("cannot find -lssp_nonshared/-lgcc: file in wrong format" — libgcc/ssp del gcc de +# Alpine en formato incorrecto para el link musl). zig cc compila musl limpio; con --disable-assembly usa +# el mpn en C genérico (más lento, irrelevante para un build-dep de libqalculate). --enable-cxx = libgmpxx.so +# (gmpxx.h que libqalculate exige). La descarga es del mirror GNU (gmplib.org cuelga en TLS con hammer-fetch). +name = "gmp" +version = "6.3.0" + +[source] +tarball = "https://ftp.gnu.org/gnu/gmp/gmp-6.3.0.tar.xz" +sha256 = "a3c2b80201b89e68616f4ad30bc66aee4927c3ce50e33929ca819d5c43538898" + +[build] +compiler = "zig-cc" +target = "x86_64-linux-musl" +link = "dynamic" +zig_version = "0.13.0" +flags = [] + +[build.phases] +configure = './configure --build=$CBUILD --host=$CHOST --prefix=/usr --disable-static --enable-shared --enable-cxx --disable-assembly' +compile = 'make -j"$(nproc)"' +install = "make install DESTDIR=/out && find /out -name '*.la' -delete" + +[deps] +build = ["m4", "pkgconf"] diff --git a/recipes/mpc.toml b/recipes/mpc.toml new file mode 100644 index 00000000..44fd34e0 --- /dev/null +++ b/recipes/mpc.toml @@ -0,0 +1,28 @@ +# GNU MPC 1.3.1 — aritmética de números complejos de precisión arbitraria con redondeo correcto +# (libmpc.so), sobre GMP+MPFR. Campaña KDE (ADR 0011): lo exige knumber (el motor matemático de KCalc); +# knumber/knumber_complex.cpp incluye incondicionalmente ⇒ MPC es build-dep duro de kcalc. +# +# compiler=zig-cc como gmp/mpfr (el gueto-gcc del sandbox falla el link test libgcc/ssp "wrong format"). +# --with-gmp=/usr --with-mpfr=/usr apuntan a los sellados. link=dynamic (libtool descarta -static). +name = "mpc" +version = "1.3.1" +license = "LGPL-3.0-or-later" + +[source] +tarball = "https://ftp.gnu.org/gnu/mpc/mpc-1.3.1.tar.gz" +sha256 = "ab642492f5cf882b74aa0cb730cd410a81edcdbec895183ce930e706c1c759b8" + +[build] +compiler = "zig-cc" +zig_version = "0.13.0" +target = "x86_64-linux-musl" +link = "dynamic" +flags = [] + +[build.phases] +configure = './configure --build=$CBUILD --host=$CHOST --prefix=/usr --disable-static --enable-shared --with-gmp=/usr --with-mpfr=/usr' +compile = 'make -j"$(nproc)"' +install = "make install DESTDIR=/out && find /out -name '*.la' -delete" + +[deps] +build = ["gmp", "mpfr", "pkgconf"] diff --git a/recipes/mpfr.toml b/recipes/mpfr.toml new file mode 100644 index 00000000..945e6c71 --- /dev/null +++ b/recipes/mpfr.toml @@ -0,0 +1,31 @@ +# GNU MPFR 4.2.2 — floats de precisión arbitraria con redondeo correcto (libmpfr.so), sobre GMP. +# Campaña KDE (ADR 0011): sustrato de libqalculate (motor matemático). Depende de gmp (#1 de esta tanda). +# +# compiler=zig-cc: el gueto-gcc del sandbox falla el link test (libgcc/ssp "wrong format"); zig cc compila +# nativo lo construye idéntico a Alpine (mpfr-dev). link=dynamic (libtool descarta -static). +# +# --with-gmp=/usr: apunta al GMP sellado (headers en /usr/include, libgmp.so en /usr/lib). El flag exacto +# de MPFR es --with-gmp=DIR (NO --with-gmp-prefix); con GMP en el prefix estándar /usr lo hallaría solo, +# pero se explicita para determinismo. +name = "mpfr" +version = "4.2.2" +license = "LGPL-3.0-or-later" + +[source] +tarball = "https://ftp.gnu.org/gnu/mpfr/mpfr-4.2.2.tar.xz" +sha256 = "b67ba0383ef7e8a8563734e2e889ef5ec3c3b898a01d00fa0a6869ad81c6ce01" + +[build] +compiler = "zig-cc" +zig_version = "0.13.0" +target = "x86_64-linux-musl" +link = "dynamic" +flags = [] + +[build.phases] +configure = './configure --build=$CBUILD --host=$CHOST --prefix=/usr --disable-static --enable-shared --with-gmp=/usr' +compile = 'make -j"$(nproc)"' +install = "make install DESTDIR=/out && find /out -name '*.la' -delete" + +[deps] +build = ["gmp", "pkgconf"]