# ncurses-shared 6.5 — la MISMA ncurses de `recipes/ncurses.toml` pero `.so`. Existe por una fuga # concreta, y conviene contar cuál porque el modo de fallar es de manual. # # ══ POR QUÉ HACE FALTA: `pw-top` ENLAZA CONTRA EL LAB DESDE AGOSTO ═════════════════════════════ # `recipes/pipewire.toml:85-88` dice, textualmente, que quitando la dep de ncurses «meson saltea # pw-top y el resto construye». **Es falso, y llevaba así desde al menos el 2026-08-29.** Quitar la # dep no desactivó nada: el guardián de upstream es `if ncurses_dep.found()`, y meson lo encontró # igual — en el **sysroot Alpine DEL LAB**. Resultado: `pw-top` se construye, se sella, y sale con # # NEEDED libncursesw.so.6 # # que **ningún artefacto del cierre publica**, porque la ncurses del catálogo es `--without-shared`. # O sea una herramienta rota dentro de las CUATRO imágenes, invisible para el store porque el lab no # entra en `hash_inputs`. Lo reporta `scripts/vigia-sonames.py` en los cuatro perfiles. # # **La lección, que es más grande que pw-top: quitar una dep de `[deps]` NO apaga la función.** # Cambia de dónde sale. Para apagarla de verdad hay que decírselo a la perilla del proyecto; si no # la hay, la dep tiene que estar declarada y satisfecha desde el store. # # ══ POR QUÉ ESTA RECETA Y NO RE-SELLAR pipewire ════════════════════════════════════════════════ # El arreglo LIMPIO es declarar la dep en pipewire y reconstruir. Cuesta: `yupana radio pipewire` da # **10 dependientes directos y 7 sellados que caen a deuda**, y entre ellos están # `xdg-desktop-portal-cosmic` y `cosmic-settings-daemon`, que son Rust —el portal murió por OOM tres # veces y el que selló tardó 48 min con un pico de 5,4 GiB de swap—. No se paga eso hoy por una # herramienta de diagnóstico, y menos con otro agente compilando en la misma máquina. # # Lo que cruza acá es un **SONAME**, y para eso el repo ya tiene regla escrita: # # > Enlazar contra una variante y CORRER contra otra es legítimo cuando lo que cruza es un SONAME # > (misma ABI). Lo que no se puede es hidratar dos artefactos distintos en la misma ruta. # # `libncursesw.so.6` es la misma ABI en 6.5 que en la 6.x de Alpine, y pw-top usa un puñado de # llamadas de curses. Poniendo esta receta de raíz en los perfiles, la imagen provee el SONAME y # pw-top corre. Cero rebuilds. # # ⚠ **QUEDA DEUDA, y está anotada a propósito:** pipewire sigue enlazando contra el lab en BUILD. # El día que pipewire se re-selle por cualquier otro motivo, hay que declarar `ncurses-shared` en # sus `[deps]` y corregir el comentario mentiroso. Esto tapa el síntoma en runtime, no la causa. # # ══ QUÉ CAMBIA RESPECTO DE LA ESTÁTICA ═════════════════════════════════════════════════════════ # `--with-shared --without-normal` en vez de `--without-shared --with-normal`. TODO lo demás se deja # idéntico —widec, los mismos `--with-fallbacks`, sin ada/tests/debug— para que el terminfo empotrado # sea el mismo: `install.libs` no instala la base de terminfo, así que lo único que hace funcionar a # un binario curses sin `/usr/share/terminfo` son esos fallbacks compilados adentro. # No hay colisión con la estática: los ficheros son `libncursesw.so*` frente a `libncursesw.a`. # El `.pc` SÍ se llama igual en las dos ⇒ **no declarar las dos en la misma receta**. # # ══ ⚠ EL `sed` DEL `-stats`, QUE ES POR QUÉ ESTA RECETA NO ES DE TRES LÍNEAS ════════════════════ # La regla de link compartido que genera el `configure` de ncurses es, literalmente: # # -Wl,-soname,`basename $@ .6.5`.6,-stats,-lc # # y `-stats` es de GNU ld: el lld que trae zig lo rechaza con `error: unsupported linker arg: # -stats` y la `.so` no se liga. No se puede pasar por `LDFLAGS` porque no es un argumento suelto, # viene DENTRO del token `-Wl,...` que el propio Makefile arma, y `MK_SHARED_LIB` no es una perilla # de `configure`. Tampoco sirve el patrón `.zwrap` de poppler tal cual, que filtra argumentos # COMPLETOS y acá hay que reescribir uno. # Y no es sólo `-stats`: quitándolo, el siguiente en caer es el `-lc` del mismo token # (`error: unsupported linker arg: -lc`). El driver de zig valida lo que va dentro de `-Wl,` y no # deja pasar ninguno de los dos; libc la liga él solo, así que la cola `,-stats,-lc` se va ENTERA. # Se quita del Makefile GENERADO, después de configure: es una sustitución exacta, acotada al # fichero que la produce, y no toca el árbol de fuentes (no hay `.patch` que mantener contra # upstream). El `grep` de antes es la parte que importa: si algún día el `configure` deja de # emitirlo o lo emite distinto, esto falla en vez de seguir en silencio. name = "ncurses-shared" version = "6.5" license = "MIT" [source] tarball = "https://ftp.gnu.org/gnu/ncurses/ncurses-6.5.tar.gz" sha256 = "136d91bc269a9a5785e5f9e980bc76ab57428f604ce3e5a5a90cebc767971cc6" [build] compiler = "zig-cc" target = "x86_64-linux-musl" link = "dynamic" [build.phases] configure = ''' set -e ./configure --prefix=/usr --with-shared --without-normal --enable-widec --without-debug --without-ada --without-tests --enable-pc-files --with-pkg-config-libdir=/usr/lib/pkgconfig --with-fallbacks=linux,vt100,vt220,xterm,xterm-256color,screen,tmux,tmux-256color,ansi # Ver la cabecera: la cola `,-stats,-lc` del token `-Wl,...` la rechaza el driver de zig entera. grep -q ',-stats,-lc' ncurses/Makefile || { echo "ERROR: no aparece ',-stats,-lc' — ¿cambió el configure de ncurses?" >&2; exit 1; } find . -name Makefile -exec sed -i 's/,-stats,-lc//g' {} + ''' compile = "make" install = ''' set -e make install.libs install.includes DESTDIR=/out # La receta EXISTE para publicar este SONAME: si no está, el artefacto no sirve para nada y hay que # enterarse acá, no en la imagen. test -e /out/usr/lib/libncursesw.so.6 || { echo "ERROR: no se generó libncursesw.so.6 — ¿--with-shared no tomó?" >&2 ls -l /out/usr/lib >&2; exit 1 } ''' [deps] build = ["binutils"]