Barrido de TEXTO puro: 1427 líneas de comentario TOML. Cero ArtifactHash movidos, y eso está MEDIDO, no deducido: hasheé las 741 antes y después y los ficheros de hashes son idénticos byte a byte (723 con hash real + 18 que ya no hasheaban de antes). El guardián valió la pena: el primer barrido, filtrando por 'la línea empieza con #', movió el hash de helix, lsof y steam-runtime-sniper. La causa es que una fase se escribe como compile = <triple> ... <triple> y sus comentarios de SHELL también empiezan con #, pero viven dentro del VALOR — y las fases sí entran en hash_inputs. El barrido ahora calcula los rangos de las cadenas multilínea de TOML y no entra ahí. Quedan intactos a propósito: .hammer-zig-cc y .hammer-cargo-vendor (literales dentro de fases), hammerd, hammer-recover y toda ruta que empiece por /
86 lines
5.2 KiB
TOML
86 lines
5.2 KiB
TOML
# readline-shared 8.2 — la MISMA readline de `recipes/readline.toml` pero `.so`. Hermana de
|
|
# `ncurses-shared`, y existe por la misma clase de fuga.
|
|
#
|
|
# ══ POR QUÉ HACE FALTA ═════════════════════════════════════════════════════════════════════════
|
|
# `python3` y `sqlite-shared` salen con `NEEDED libreadline.so.8` y NINGÚN artefacto del cierre
|
|
# publica ese soname: la readline del catálogo es `--disable-shared`, así que sólo produce
|
|
# `libreadline.a`. En el rootfs hidratado eso se resuelve contra el sysroot Alpine DEL LAB, que en
|
|
# la máquina de desarrollo está y en la distro NO. Lo venía reportando `scripts/vigia-sonames.py`
|
|
# en los CUATRO perfiles, junto a `libstdc++.so.6` — que se pagó el 2026-09-06 con `gcc-libs`.
|
|
#
|
|
# No sustituye a `recipes/readline.toml`: quien quiera enlazar estático sigue usando aquélla. Es el
|
|
# mismo reparto que `ncurses` / `ncurses-shared`.
|
|
#
|
|
# ⚠ VERSIÓN 8.2 Y NO LA 8.3.3 DE ALPINE, A PROPÓSITO. El soname que piden los consumidores YA
|
|
# SELLADOS es `libreadline.so.8`, y las dos lo dan; pero la 8.2 es la que ya usa `readline.toml`, y
|
|
# tener las dos variantes en versiones distintas es pedir que diverjan sin que nadie lo note. Si se
|
|
# sube una, se suben las dos.
|
|
#
|
|
# ⚠ EL SUBRAYADO: READLINE SALE MAL ENLAZADA POR DISEÑO DE UPSTREAM. `libreadline.so` no enlaza
|
|
# contra ncurses salvo que se lo fuerces, y queda con `tgetent`, `tputs` y compañía SIN RESOLVER.
|
|
# Alpine lo arregla con un parche y —esto es lo que se copia— con un guardián que FALLA si el
|
|
# `NEEDED` de ncurses no aparece. Acá se consigue lo mismo sin parche, pasándole `SHLIB_LIBS` al
|
|
# make, que es la perilla que el propio Makefile de readline expone para esto.
|
|
name = "readline-shared"
|
|
version = "8.2"
|
|
license = "GPL-3.0-or-later"
|
|
|
|
[source]
|
|
tarball = "https://ftp.gnu.org/gnu/readline/readline-8.2.tar.gz"
|
|
sha256 = "3feb7171f16a84ee82ca18a36d7b9be109a52c04f492a053331d7d1095007c35"
|
|
|
|
[build]
|
|
compiler = "zig-cc"
|
|
target = "x86_64-linux-musl"
|
|
# El punto de la receta: takana inyecta `LDFLAGS=-static` en modo estático y acá el producto ES la
|
|
# librería compartida. Igual que en `gcc-libs` y `ncurses-shared`.
|
|
link = "dynamic"
|
|
|
|
[deps]
|
|
# `ncurses-shared` y no `ncurses`: si acá entrara la estática, `libreadline.so.8` se llevaría los
|
|
# objetos de `libncursesw.a` dentro en vez de declarar el `NEEDED`, y el guardián de abajo —que es
|
|
# el de Alpine— lo cazaría. Es la misma lección que el cairo estático de waterfox.
|
|
build = ["ncurses-shared", "make"]
|
|
|
|
[build.phases]
|
|
configure = "./configure --prefix=/usr --enable-shared --disable-static --with-curses"
|
|
# `SHLIB_LIBS` es la perilla del Makefile de readline para lo que Alpine resuelve con un parche.
|
|
compile = 'make SHLIB_LIBS=-lncursesw'
|
|
install = '''
|
|
set -e
|
|
make install DESTDIR=/out SHLIB_LIBS=-lncursesw
|
|
|
|
# La readline trae `rlconf.h` y binarios de ejemplo que no hacen falta para satisfacer un NEEDED.
|
|
rm -rf /out/usr/bin /out/usr/share
|
|
|
|
# ── GUARDIÁN 1: el soname que los consumidores piden ─────────────────────────────────────────
|
|
F=$(find /out/usr/lib -name 'libreadline.so.8*' | head -1)
|
|
test -n "$F" || { echo "!! no se generó libreadline.so.8 — ¿--enable-shared no tomó?" >&2; ls -l /out/usr/lib >&2; exit 1; }
|
|
SO=$(readelf -d "$F" 2>/dev/null | sed -n 's/.*SONAME.*\[\(.*\)\].*/\1/p')
|
|
test "$SO" = "libreadline.so.8" || { echo "!! SONAME es '$SO' y esperaba 'libreadline.so.8'" >&2; exit 1; }
|
|
echo "guardián: libreadline.so.8 ok (SONAME correcto, $(stat -Lc%s "$F") bytes)"
|
|
|
|
# ── GUARDIÁN 2: EL DE ALPINE — que no esté SUBENLAZADA ───────────────────────────────────────
|
|
# Copiado de su APKBUILD casi literal («verify that it is not underlinked as upstream designed
|
|
# it»). Sin esto la librería existe, tiene el soname correcto y sus símbolos de terminal quedan
|
|
# colgando: el fallo reaparecería en el consumidor, a un eslabón de distancia y sin nombrar a esta
|
|
# receta. Es exactamente la forma de fallo que esta receta viene a cerrar, así que dejarla sin
|
|
# comprobar sería no haber aprendido nada.
|
|
readelf -d "$F" 2>/dev/null | grep -q 'NEEDED.*ncurses' || {
|
|
echo "!! libreadline.so.8 NO está enlazada contra ncurses (subenlazada)" >&2
|
|
echo " readline hace esto por diseño de upstream; revisá SHLIB_LIBS=-lncursesw." >&2
|
|
readelf -d "$F" 2>/dev/null | grep NEEDED >&2
|
|
exit 1
|
|
}
|
|
echo "guardián: enlazada contra ncurses ($(readelf -d "$F" | sed -n 's/.*NEEDED.*\[\(.*ncurses.*\)\].*/\1/p'))"
|
|
|
|
# ── GUARDIÁN 3: la prueba del consumidor ─────────────────────────────────────────────────────
|
|
# Los símbolos que python3 y sqlite buscan de verdad. «Existe» no es «sirve».
|
|
falta=""
|
|
for s in readline add_history rl_completion_matches; do
|
|
nm -D --defined-only "$F" 2>/dev/null | grep -qE " $s(@|\$)" || falta="$falta $s"
|
|
done
|
|
test -z "$falta" || { echo "!! la .so no define:$falta" >&2; exit 1; }
|
|
echo "guardián: define los símbolos que piden python3 y sqlite"
|
|
'''
|