tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 604Rust 56Shell 36Markdown 281227 Sutichaykuna

readline-shared: la .so que python3 y sqlite piden (b3:79355aad)

libreadline.so.8, 970.144 bytes. Hermana de ncurses-shared y por la misma fuga:
python3 y sqlite-shared salen con NEEDED libreadline.so.8 y la readline del
catálogo es --disable-shared, así que sólo produce libreadline.a. En el rootfs
hidratado eso se resolvía contra el sysroot Alpine DEL LAB.

Versión 8.2 y no la 8.3.3 de Alpine, a propósito: es la que ya usa
recipes/readline.toml y tener las dos variantes en versiones distintas es pedir
que diverjan sin que nadie lo note.

TRES GUARDIANES, y el segundo es de Alpine casi literal. readline sale MAL
ENLAZADA por diseño de upstream —libreadline.so no enlaza contra ncurses salvo
que se lo fuerces, y queda con tgetent y compañía sin resolver—; Alpine lo
arregla con un parche y con un check que falla si el NEEDED de ncurses no
aparece. Acá se consigue sin parche con SHLIB_LIBS=-lncursesw, que es la perilla
que el propio Makefile expone. El guardián verifica que quedó enlazada, porque
si no el fallo reaparece en el consumidor, a un eslabón de distancia y sin
nombrar a esta receta.

La dep es ncurses-shared y no ncurses: con la estática, libreadline.so.8 se
llevaría los objetos de libncursesw.a dentro en vez de declarar el NEEDED — la
misma lección que el cairo estático de waterfox.

Se promueve además sqlite-shared de incoming-gnome al catálogo canónico: python3
la necesita como dep de ejecución y una receta de recipes/ no ve las de una
cola. Sin variantes en conflicto y ya sellada, así que la promoción no cuesta un
build.

b2ff678301a4bcebc7693b5ae6702d5fee3d0ccc · ruwaq Sergio · (1 killa ñawpaq) · tayta 54729e01e · kay commitpi sach'ata qhaway

Semántico sayk'uy

Mana ima sutichaypas t'ikrakurqanchu: qillqalla, yachachiylla utaq willaylla t'ikrakurqan.

2 qillqakuna · +140 −0

diff --git a/recipes/readline-shared.toml b/recipes/readline-shared.toml
new file mode 100644
index 00000000..10cd2afa
--- /dev/null
+++ b/recipes/readline-shared.toml
@@ -0,0 +1,85 @@
+# 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: hammer 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"
+'''
diff --git a/recipes/sqlite-shared.toml b/recipes/sqlite-shared.toml
new file mode 100644
index 00000000..40c3e6a3
--- /dev/null
+++ b/recipes/sqlite-shared.toml
@@ -0,0 +1,55 @@
+# ── ⚠ VERRUGA MEDIDA (2026-09-05), sin decidir ─────────────────────────────────────────────────
+# `usr/bin/sqlite3` —el shell de la CLI, NO `libsqlite3.so.0`— sale con `NEEDED libreadline.so.8`, y
+# el `readline` canónico del corpus es `.a`. O sea que en la imagen GNOME ese comando no carga: lo
+# resolvía contra el sysroot Alpine DEL LAB. Lo cazó `scripts/vigia-sonames.py`; las APPS están bien,
+# porque la librería no lo lleva.
+#
+# Las dos salidas cuestan cosas distintas y por eso no se decide de paso:
+#   · construir `readline-shared` y sumarla de raíz a `escritorio-gnome` — 1 build nuevo, pero la
+#     imagen carga una librería más sólo para que ande un comando. (`ncurses-shared` ya es raíz del
+#     perfil, así que la cadena cierra.)
+#   · configurar acá `--disable-readline` y no instalar una CLI que nadie pidió — más limpio, pero
+#     re-hashea: `yupana radio sqlite-shared` da **6 dependientes en incoming-gnome** que caen a
+#     deuda.
+# Se paga barato el día que sqlite-shared se re-selle por otro motivo.
+
+# sqlite-shared 3.46.1 — variante DINÁMICA de sqlite para la isla dinámica de GNOME.
+#
+# Por qué existe: el sqlite canónico (recipes/sqlite.toml) es `--disable-shared --enable-static` y su
+# libsqlite3.a NO es PIC (verificado: trae reubicaciones R_X86_64_32). libsoup 3.6 lo pide DURO
+# (meson.build:123-136 cae a `dependency('sqlite3')` sin `required:false`) y libsoup es un .so ⇒
+# meter el .a no-PIC adentro corta con el mismo `relocation R_X86_64_32 ... recompile with -fPIC`
+# que frenó a mutter contra freetype. Mismo patrón y misma solución que zlib-shared/cairo-shared:
+# una variante hermana, sin tocar la canónica (su radio son cientos de sellados).
+#
+# El único cambio real frente a la canónica es --enable-shared --disable-static y sacar el
+# `-all-static -no-pie` de LDFLAGS, que es justo lo que impide producir un .so. Misma versión y mismo
+# tarball a propósito: el sqlite3.pc que consume libsoup declara la misma versión que el resto del
+# corpus, así que no se abre un skew de versiones entre el mundo estático y el dinámico.
+name    = "sqlite-shared"
+version = "3.46.1"
+
+[source]
+tarball = "https://sqlite.org/2024/sqlite-autoconf-3460100.tar.gz"
+sha256  = "67d3fe6d268e6eaddcae3727fce58fcc8e9c53869bdd07a0c61e38ddf2965071"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "dynamic"
+
+[build.phases]
+configure = "./configure --prefix=/usr --enable-shared --disable-static"
+compile   = 'make -j"$(nproc)"'
+install   = "make install DESTDIR=/out"
+
+[deps]
+# ✅ DECIDIDA 2026-09-06, y la decisión cambió porque cambió el cálculo. La verruga de arriba dejaba
+# dos salidas sin elegir, y el argumento contra la primera era «la imagen carga una librería más sólo
+# para que ande un comando». Ya no es cierto: `python3` sale con el MISMO `NEEDED libreadline.so.8`
+# y es raíz de los cuatro perfiles, así que `readline-shared` entra en la clausura igual. El coste
+# marginal de arreglar además el `sqlite3` de la CLI es CERO.
+# `runtime` no entra en el ArtifactHash ⇒ no re-hashea, y los 6 dependientes que menciona la nota de
+# arriba no se tocan. Esa era la otra mitad del precio y tampoco se paga.
+runtime = ["readline-shared"]
+build = ["make", "pkgconf"]