Siete recetas decían «lo vigila `scripts/audit-needed.sh`» y ese script ya no
existe: lo borré yo mismo en 02facebe, bien borrado, porque duplicaba a
`scripts/vigia-sonames.py` — que además ya estaba en el repo y ahora corre en el
latido. Pero las referencias quedaron, escritas por mí unas horas antes.
Es exactamente la etiqueta que se lee como el hecho, y en mi propia letra: un
comentario que afirma que existe un guardián manda a quien dude de una dep de
runtime a correr un script que no está. En el mejor caso pierde diez minutos; en
el peor concluye que no hay con qué comprobarlo.
Ahora apuntan a `vigia-sonames.py` y a `docs/state/sonames.txt`, que es el
fichero que el latido regenera y donde se ve si algo empeora entre cosechas.
Ningún ArtifactHash se mueve: los siete comentarios caen fuera de campos
hasheados. Verificado uno por uno antes y después, incluido
firefox-instrumentado, que tiene un build en vuelo y se habría invalidado.
Lo levantó hammer-99 desde el frente atuq. `recipes/atuq.toml` NO se toca: su
mención es una nota histórica ya corregida por ellos («…y NO audit-needed.sh»),
y mi primer grep casi la «arregla» por no leerla.
Y la advertencia que traían vale para cualquiera con pruebas de runtime: si el
runner monta `.dev-fs/alpine` debajo, `libstdc++.so.6` se resuelve contra el LAB
y la prueba es ciega. Comprobado que la mía NO lo estaba: el rootfs hidratado
trae el del corpus (20.850.968 bytes) y no el del lab (2.804.104), y el bwrap de
la prueba nunca montó .dev-fs.
170 lines
9.0 KiB
TOML
170 lines
9.0 KiB
TOML
# 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/vigia-sonames.py` —que ya existía y nadie corría— medía 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"
|
|
'''
|