From e49545e0a7eff5f10c1d90e8cb54036becedf255 Mon Sep 17 00:00:00 2001 From: Sergio Date: Thu, 17 Sep 2026 23:38:18 +0000 Subject: [PATCH] =?UTF-8?q?gcc-libs=20enviaba=20un=20ld=20script=20que=20p?= =?UTF-8?q?ed=C3=ADa=20una=20librer=C3=ADa=20que=20nadie=20ten=C3=ADa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `/usr/lib/libgcc_s.so` no es una librería: es un ld script —`GROUP ( libgcc_s.so.1 -lgcc )`— y ese `-lgcc` es libgcc.a, que ninguna receta del corpus proveía. Esta misma la borraba: el `find -name '*.a' -delete` de la poda, y de paso el `rm -rf /usr/lib/gcc` se llevaba el original. Medido en la caja con el rust recién sellado: los binarios estáticos compilan y corren, pero cualquier dylib —y eso incluye TODAS las proc-macros— muere con `unable to find library -lgcc`. O sea `cargo build` con `derive` imposible sobre takana, con el compilador perfecto. Y no alcanza con dar `-L /usr/lib`: con eso se resuelven `-lc` y `-lgcc_s`, y entonces aparece justo este `-lgcc`. Es la misma familia que el hueco que originó esta receta —todo presente, todo reproducible, y el camino que hace falta no existe—, sólo que del lado del ENLACE en vez del arranque. libgcc.a se copia a /usr/lib (donde el -L del enlazador ya mira; el gcc completo no está en esta distro) y se salva de la poda. Y entra un GUARDIÁN 3 que compara lo que el ld script PIDE contra lo que el artefacto TRAE: si vuelve a quedarse sin libgcc.a, corta. Radio medido con yupana antes de tocar: 7 dependientes directos, 9 transitivos, 7 imágenes. Co-Authored-By: Claude Opus 5 (1M context) --- recipes/gcc-libs.toml | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/recipes/gcc-libs.toml b/recipes/gcc-libs.toml index 29294c40..30e43e45 100644 --- a/recipes/gcc-libs.toml +++ b/recipes/gcc-libs.toml @@ -119,13 +119,37 @@ if [ -d /out/usr/lib64 ]; then 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 +# ── libgcc.a SE SALVA DE LA PODA, Y ES UNA CORRECCIÓN (2026-09-17) ─────────────────────────── +# `/usr/lib/libgcc_s.so` que esta receta instala **no es una librería: es un ld script** +# +# GROUP ( libgcc_s.so.1 -lgcc ) +# +# y ese `-lgcc` es `libgcc.a`, que NINGUNA receta del corpus proveía —ésta la borraba con el +# `find -name '*.a' -delete` de acá abajo, y de paso `rm -rf /usr/lib/gcc` se llevaba el original—. +# Consecuencia medida en la caja de producción con el `rust` recién sellado: los binarios ESTÁTICOS +# compilan y corren, pero **cualquier dylib —y eso incluye TODAS las proc-macros— muere**: +# +# ld.lld: error: unable to find library -lgcc +# +# O sea `cargo build` con `derive` (serde, clap…) imposible sobre takana, con el compilador perfecto. +# Es la misma familia que el hueco que originó esta receta: todo presente, todo reproducible, y el +# camino que hace falta no existe. Y no alcanza con dar `-L /usr/lib`: con eso se resuelven `-lc` y +# `-lgcc_s`, y entonces aparece justo este `-lgcc`. +# +# Va a `/usr/lib` —no al directorio privado de gcc— porque es donde el `-L` del enlazador ya mira, y +# porque el gcc completo no está en esta distro: acá la librería tiene que valerse sola. +A=$(find /out -name libgcc.a | head -1) +test -n "$A" || { echo "!! el install no dejó ninguna libgcc.a — sin ella el ld script de libgcc_s miente" >&2; exit 1; } +cp "$A" /out/usr/lib/libgcc.a + +# Se PODA todo lo que no sea runtime: headers, el resto de los `.a`, `.la`, libsupc++, los `.py` del +# pretty-printer. Esta receta existe para que un binario ARRANQUE —y ahora también para que el +# `libgcc_s.so` que envía sea ENLAZABLE—, no para compilar C++ 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 '*.a' ! -name 'libgcc.a' -delete find /out -name '*.py' -delete L=/out/usr/lib @@ -166,4 +190,15 @@ test -z "$falta" || { exit 1 } echo "guardián: los 6 símbolos que firefox no encontraba están DEFINIDOS" + +# ── GUARDIÁN 3: EL LD SCRIPT NO PUEDE MENTIR ───────────────────────────────────────────────── +# `libgcc_s.so` es un ld script que manda buscar `-lgcc`. Si esa librería no viaja con él, el +# artefacto sella, reproduce, y la primera dylib que alguien enlace en una caja takana muere. Se +# comprueba lo que el script PIDE contra lo que el artefacto TRAE, no la intención. +if grep -q "GROUP" "$L/libgcc_s.so" 2>/dev/null; then + grep -q -- "-lgcc" "$L/libgcc_s.so" && test -f "$L/libgcc.a" || { + echo "!! $L/libgcc_s.so es un ld script que pide -lgcc y no hay libgcc.a al lado" >&2 + cat "$L/libgcc_s.so" >&2; exit 1; } + echo "guardián: el ld script pide -lgcc y libgcc.a viaja con él ($(stat -Lc%s "$L/libgcc.a") bytes)" +fi '''