diff --git a/docs/runbooks/cosmic-desktop.md b/docs/runbooks/cosmic-desktop.md index c315a3ce..08efe24b 100644 --- a/docs/runbooks/cosmic-desktop.md +++ b/docs/runbooks/cosmic-desktop.md @@ -107,8 +107,10 @@ Más `cosmic-settings-daemon` y `xdg-desktop-portal-cosmic` fuera de esa lista. | `cosmic-workspaces-epoch` | ✅ sellado (necesitó `mesa`, ver gotcha 11) | `b3:a031249e` | | **`cosmic-applets`** (19 binarios en uno) | ✅ **sellado** (necesitó `dbus-shared`, ver gotcha 10) | `b3:3e53a325` | | `pop-launcher` 1.2.7 (otro repo, ver abajo) | ✅ sellado a la primera | `b3:64a5cbaa` | +| `gmp` 6.3.0 · `mpfr` 4.2.2 (cadena de la calculadora) | ✅ sellados a la primera | `b3:d99a0a5d` · `b3:13982d20` | +| `libqalculate` 5.12.0 (`qalc`) | ✅ sellado — **pero el plugin del lanzador no lo puede usar, ver abajo** | `b3:6bb435a7` | -**La cola está COMPLETA: 27 recetas, `escritorio-cosmic` 63/63.** +**La cola está COMPLETA: 30 recetas, `escritorio-cosmic` 68/68.** **El mínimo viable de una sesión son cuatro**: `cosmic-comp` + `cosmic-settings-daemon` + `cosmic-notifications` + `cosmic-panel` (los tres `.expect` de la tabla de arriba). @@ -479,6 +481,39 @@ plugin, que contesta «qalc command is not installed»**. Esa respuesta es la me disponible: el proceso hijo corrió, evaluó la consulta y devolvió una fila. Lo que falta ahora es `libqalculate` (el binario `qalc`), que es un paquete, no un problema. +### 🧮 `libqalculate`: empaquetado y andando, e inservible para el plugin + +`qalc` está sellado y **funciona**: `qalc -t '2+2'` → `4`, `-f fichero`, y el modo interactivo sobre +una terminal calcula perfecto (`123 × 456 = 56088`). La cadena que baja desde una tecla —`Super` → +cosmic-launcher → pop-launcher → plugin `calc` → `qalc` → **mpfr → gmp**— está entera en el catálogo. + +**Y aun así el lanzador sigue mostrando una fila vacía.** El plugin no le pasa la cuenta por argv: +arranca `qalc` SIN expresión, con stdin y stdout en tubería, le ESCRIBE la expresión y cierra. Ese +modo, en nuestro binario, no lee nada. Acotado con dos invocaciones que sólo difieren en cuándo llega +el EOF: + +```sh +{ printf '123*456\n'; sleep 3; } | qalc # LEE (aparece la pregunta de primer arranque) + printf '123*456\n' | qalc # NO lee NADA: imprime el prompt y sale con rc=0 +``` + +O sea: **con el EOF ya pendiente en un stdin que no es terminal, `readline()` devuelve NULL antes de +entregar la línea que sí está en el búfer** — y así es exactamente como lo invoca el plugin. + +Lo que ya se DESCARTÓ midiendo, para que nadie lo repita: +- **No es el toolchain.** Una sonda estática musl del propio sandbox (C y C++) lee la tubería sin + problema. El binario no tiene nada raro: un solo `NEEDED`, `libc.so`. +- **No es readline vs no-readline.** Sin readline es peor (no lee nunca, ni con la tubería abierta); + con readline al menos lee cuando el escritor no ha cerrado. +- **No es la versión de readline.** Se construyó una 8.3 como sombra de cola y el síntoma no se + movió; la sombra se descartó en vez de dejar una receta duplicada que no arregla nada. +- **No es el descriptor 0.** `qalc -f /dev/stdin` —el MISMO pipe, reabierto por ruta— sí funciona. + El que no sirve es el `FILE*` `stdin`. + +La pista que queda es justamente esa última asimetría. Y el aviso de método: **empaquetar el binario +que falta no garantiza que el consumidor lo pueda usar** — «qalc no está instalado» y «qalc está y no +contesta» son dos estados distintos, y el segundo se ve peor porque la fila sale en blanco. + ### ⏱ El panel tiene un DEADLINE de arranque: con 4 vCPU sale mutilado Medido: con `-smp 4` el panel arranca **sin ala izquierda, sin reloj y sin dock** —sólo la bandeja diff --git a/docs/state/build-state-cosmic.json b/docs/state/build-state-cosmic.json index 556898d4..9c5bfd95 100644 --- a/docs/state/build-state-cosmic.json +++ b/docs/state/build-state-cosmic.json @@ -3,9 +3,8 @@ "totals": { "recipes": 800, "nodes": 800, - "sealed": 797, - "never": 2, - "debt": 1 + "sealed": 798, + "never": 2 }, "by_class": { "c": 160, @@ -15,7 +14,7 @@ "rust": 241 }, "debt_by_class": { - "c": 3 + "c": 2 }, "by_queue": { "corpus": { @@ -23,8 +22,7 @@ "never": 2 }, "incoming-cosmic": { - "sealed": 29, - "debt": 1 + "sealed": 30 } }, "by_profile": { @@ -41,8 +39,7 @@ "escritorio-cosmic": { "raices": 20, "clausura": 68, - "sealed": 67, - "debt": 1 + "sealed": 68 }, "escritorio-mirada": { "raices": 14, @@ -4898,7 +4895,7 @@ "hash": "b3:d99a0a5d6fb0e301523c3797d899e7c1002c58f282865df87e221b4e47fd0642", "state": "sealed", "blocked_by": [], - "unblocks": 1, + "unblocks": 0, "perfiles": [ "escritorio-cosmic" ], @@ -8229,7 +8226,7 @@ "cls": "c", "queue": "incoming-cosmic", "hash": "b3:6bb435a7e54f9b83eb44133b75cd684161da7a03135a44ee22063bdba687b88c", - "state": "debt", + "state": "sealed", "blocked_by": [], "unblocks": 0, "perfiles": [ @@ -8452,7 +8449,7 @@ "hash": "b3:c4c65c4b17b86211c4a7f076e6693aedb9168d72cc8e45a4a9022fdd75f79494", "state": "sealed", "blocked_by": [], - "unblocks": 1, + "unblocks": 0, "perfiles": [ "escritorio-cosmic", "escritorio-gnome" @@ -8804,7 +8801,7 @@ "hash": "b3:fbad44acdc76df4b081cccd3cc02666664b6d1a03cd6fa482f85791fa533a602", "state": "sealed", "blocked_by": [], - "unblocks": 2, + "unblocks": 1, "perfiles": [ "base", "cli", @@ -9471,7 +9468,7 @@ "hash": "b3:13982d20e404affb9ab825c157a50efc2f0370e1befe75cb7ce93b914d55d497", "state": "sealed", "blocked_by": [], - "unblocks": 1, + "unblocks": 0, "perfiles": [ "escritorio-cosmic" ], @@ -9695,7 +9692,7 @@ "hash": "b3:a3be97622d20cd8d831a25403e00eccb23f2585ed78670a4e12d6cbe519fb8ec", "state": "sealed", "blocked_by": [], - "unblocks": 1, + "unblocks": 0, "perfiles": [ "base", "cli", @@ -10617,7 +10614,7 @@ "hash": "b3:f0b5d0b1cb4321b3c61f24a871b9a58da3ebb7eb903af4015e35bd41a6465437", "state": "sealed", "blocked_by": [], - "unblocks": 1, + "unblocks": 0, "perfiles": [ "base", "cli", @@ -11053,7 +11050,7 @@ "hash": "b3:03c0eb9ccaf42a65d876c0778b7ee53695f6389bbe5c4c9bcf606f8aa328ec36", "state": "sealed", "blocked_by": [], - "unblocks": 1, + "unblocks": 0, "perfiles": [ "base", "cli", diff --git a/docs/state/targets.toml b/docs/state/targets.toml index 956f1728..e27675c8 100644 --- a/docs/state/targets.toml +++ b/docs/state/targets.toml @@ -104,6 +104,9 @@ paquetes = [ # El MOTOR del lanzador, de otro repo y fuera del pin `epoch-N`: `cosmic-launcher` sólo dibuja y # lanza a `pop-launcher` como proceso hijo por PATH. Sin él, `Super` no abre nada. "pop-launcher", + # Y el `qalc` al que el plugin `calc` le pasa la expresión: tercer nivel de hijo por PATH. Es la + # primera raíz del perfil que existe para que una TECLA dé un resultado, no para que algo enlace. + "libqalculate", # Datos, no binarios: el tema de iconos (y el hicolor del que hereda), las tablas de xkb y una # tipografía. Ninguno es dep de build de nadie y sin ellos el escritorio arranca roto — sin puntero, # sin teclado o con tofu. diff --git a/recipes/incoming-cosmic/gmp.toml b/recipes/incoming-cosmic/gmp.toml new file mode 100644 index 00000000..ce7b7b0c --- /dev/null +++ b/recipes/incoming-cosmic/gmp.toml @@ -0,0 +1,45 @@ +# gmp — aritmética de precisión arbitraria. Entra al corpus por abajo del lanzador: el plugin de la +# calculadora de pop-launcher llama al binario `qalc`, `qalc` es libqalculate, y libqalculate corta el +# configure con «libgmp not found» si no está. O sea que la cadena de una tecla del escritorio baja +# hasta la aritmética de enteros grandes — y ese es justo el tipo de dep que no se ve venir mirando +# el paquete de arriba. +# +# ── `--disable-assembly` NO ES PEREZA ─────────────────────────────────────────────────────────── +# GMP trae rutinas en ensamblador por microarquitectura y su `configfsf.guess` elige una mirando la +# CPU de QUIEN COMPILA. Eso es exactamente lo que este lab no puede permitir: hornearía la ISA del +# laptop en el artefacto y el hash dejaría de significar lo mismo en la granja (el mismo modo de +# falla que `-mcpu=baseline` corrige en el wrapper de zig). Con `--disable-assembly` GMP usa su +# implementación en C portable: más lenta, y a nadie le importa — acá la usa una calculadora de +# escritorio, no un criptosistema. +# Además zig/clang no digiere varias de esas rutinas (`.align` y sintaxis de gas antigua), así que +# la alternativa realista tampoco era «assembly sí». +name = "gmp" +version = "6.3.0" + +[source] +tarball = "https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz" +sha256 = "a3c2b80201b89e68616f4ad30bc66aee4927c3ce50e33929ca819d5c43538898" + +[build] +compiler = "zig-cc" +target = "x86_64-linux-musl" +link = "static" +flags = [] + +[build.phases] +# `--enable-cxx` va APAGADO: libqalculate usa la API C de GMP (`__gmpz_init` es lo que su configure +# busca), y `libgmpxx` arrastraría el runtime de C++ a un paquete que no lo necesita — justo la deuda +# que la campaña «matar gcc» viene pagando en el resto del árbol. +configure = ''' +./configure \ + --build=$CBUILD --host=$CHOST \ + --prefix=/usr \ + --disable-shared --enable-static \ + --disable-assembly \ + --enable-fat=no +''' +compile = 'make -j"$(nproc)"' +install = 'make DESTDIR=/out install' + +[deps] +build = ["make", "m4"] diff --git a/recipes/incoming-cosmic/libqalculate.toml b/recipes/incoming-cosmic/libqalculate.toml new file mode 100644 index 00000000..621a1dff --- /dev/null +++ b/recipes/incoming-cosmic/libqalculate.toml @@ -0,0 +1,76 @@ +# libqalculate — la calculadora que le falta al lanzador. El plugin `calc` de pop-launcher no calcula +# nada por su cuenta: arma una línea y se la pasa al binario **`qalc`**, que es de este paquete. Sin +# él, tecleando `=2+2` el lanzador contesta —correctamente y sin fallar— «qalc command is not +# installed». Es el primer paquete del catálogo que existe para que una TECLA del escritorio dé un +# resultado, no para que otra librería enlace. +# +# ── LA CADENA QUE NADIE ADIVINA MIRANDO ARRIBA ────────────────────────────────────────────────── +# `Super` → cosmic-launcher → pop-launcher → plugin calc → qalc → libqalculate → **mpfr → gmp**. +# Seis saltos desde una tecla hasta la aritmética de precisión arbitraria, y los dos últimos son +# obligatorios: el configure corta con «libgmp not found» y «libmpfr not found or uses a different +# ABI». Por eso [[gmp]] y [[mpfr]] entraron primero. +# +# ── LO QUE SE APAGA, Y POR QUÉ CADA UNO ───────────────────────────────────────────────────────── +# · `--without-libcurl`: es para BAJARSE tipos de cambio de internet. Un paquete de una distro +# reproducible no tiene por qué traer un cliente HTTP para sumar; y la clausura se ahorra curl +# entero. Las tasas quedan las del fichero de definiciones, que es lo honesto: un dato con fecha. +# · `--without-icu`: sólo aporta comparación de cadenas Unicode insensible a mayúsculas. Traería +# ICU —decenas de MB de tablas— para que `SIN` funcione igual que `sin`. +# · `--disable-nls`: no hay locales en la imagen (los clientes ya avisan «failed to get system +# locale, falling back to en-US»), así que gettext sólo agregaría dependencia sin traducir nada. +# +# ── ⚠ READLINE NO ES OPCIONAL ACÁ, Y ESO SE MIDIÓ ─────────────────────────────────────────────── +# Yo había razonado que era indiferente «porque el plugin usa qalc de forma no interactiva». **Es +# falso, y el código del plugin lo dice**: `Command::new("qalc")` sin expresión, con `stdin` en pipe, +# le ESCRIBE la expresión por stdin y descarta las dos primeras líneas de stdout. O sea que lo usa en +# modo INTERACTIVO con stdin redirigido — el modo en que `-t ` no participa. +# Sin readline ese modo no funciona: el binario imprime el prompt `>` y no evalúa nada, así que la +# fila del lanzador sale VACÍA (no «no está instalado»: está, y no contesta). Con readline el bucle +# de entrada es el que espera el plugin. +# La lección es la de siempre en esta campaña, otra vez: **la dep no se deduce de para qué sirve el +# paquete, se lee de cómo lo INVOCA quien lo usa.** «Es una calculadora, la llamarán con la cuenta +# en argv» era una suposición, no una medición. +name = "libqalculate" +version = "5.12.0" + +[source] +tarball = "https://github.com/Qalculate/libqalculate/releases/download/v5.12.0/libqalculate-5.12.0.tar.gz" +sha256 = "f3dfdcf97d5a9e3a5bc0ebe66afd184721b606276eee3ba0ada8c92a5e71d44c" + +[build] +# C++ de verdad (la librería entera lo es), y con `compiler = "zig-cc"` el sandbox pone +# CXX=hammer-zig-cxx, o sea `zig c++` con la libc++ de LLVM enlazada ESTÁTICA. Eso es lo que evita +# que el artefacto pida `libstdc++.so.6`/`libgcc_s.so.1` de Alpine — la deuda que la campaña +# «matar gcc» viene pagando en el resto del árbol. +compiler = "zig-cc" +target = "x86_64-linux-musl" +link = "static" +flags = [] + +[build.phases] +configure = ''' +# ── ALIAS DE CURSES, PORQUE EL CORPUS SÓLO EMPAQUETA LA VARIANTE WIDE ─────────────────────────── +# El configure de libqalculate busca readline probando `-lreadline` junto a `-lncurses`, `-lcurses`, +# `-ltermcap` y `-ltinfo`, en ese orden. Nuestro `ncurses` instala **sólo `libncursesw.a`** (la +# variante de caracteres anchos, que es la correcta y la única que hace falta), así que las cuatro +# pruebas fallan con «unable to find static system library» y el configure concluye —sin error— que +# no hay readline. Que el paquete se llame `ncurses` no significa que provea `-lncurses`. +# Los alias van en un directorio LOCAL y no tocando `/usr/lib`: la vista de deps del sandbox es la +# evidencia de qué se declaró, y ensuciarla para que un test pase deja mintiendo justo al mecanismo +# que existe para no mentir. +mkdir -p .curses-compat +for a in libncurses libcurses libtinfo libtermcap; do ln -sf /usr/lib/libncursesw.a ".curses-compat/$a.a"; done +./configure \ + --build=$CBUILD --host=$CHOST \ + --prefix=/usr \ + --disable-shared --enable-static \ + --without-libcurl \ + --without-icu \ + --disable-nls \ + LDFLAGS="$LDFLAGS -L$PWD/.curses-compat" +''' +compile = 'make -j"$(nproc)"' +install = 'make DESTDIR=/out install' + +[deps] +build = ["make", "gmp", "mpfr", "libxml2", "pkgconf", "readline", "ncurses"] diff --git a/recipes/incoming-cosmic/mpfr.toml b/recipes/incoming-cosmic/mpfr.toml new file mode 100644 index 00000000..bd98eca0 --- /dev/null +++ b/recipes/incoming-cosmic/mpfr.toml @@ -0,0 +1,37 @@ +# mpfr — coma flotante de precisión arbitraria con redondeo correcto, sobre gmp. El segundo eslabón +# de la cadena que baja desde una tecla del escritorio hasta la aritmética: libqalculate corta el +# configure con «libmpfr not found or uses a different ABI» si no está. +# +# «or uses a different ABI» en ese mensaje no es adorno: el test de upstream enlaza contra `mpfr_get_version`, +# así que un mpfr construido contra OTRO gmp falla igual que uno ausente. Por eso [[gmp]] se declara +# acá y no se da por sentado: los dos artefactos tienen que venir del mismo grafo. +name = "mpfr" +version = "4.2.2" + +[source] +tarball = "https://www.mpfr.org/mpfr-4.2.2/mpfr-4.2.2.tar.xz" +sha256 = "b67ba0383ef7e8a8563734e2e889ef5ec3c3b898a01d00fa0a6869ad81c6ce01" + +[build] +compiler = "zig-cc" +target = "x86_64-linux-musl" +link = "static" +flags = [] + +[build.phases] +# `--with-gmp=/usr` apunta al gmp del sandbox —el que proyecta la dep, no uno del sistema—, que es +# donde `hammer` monta los artefactos declarados. Sin el flag, el configure de mpfr busca en rutas +# del host y el error que da («gmp.h can't be found») manda a instalar algo, que es justo lo que en +# este lab no hay que hacer. +configure = ''' +./configure \ + --build=$CBUILD --host=$CHOST \ + --prefix=/usr \ + --disable-shared --enable-static \ + --with-gmp=/usr +''' +compile = 'make -j"$(nproc)"' +install = 'make DESTDIR=/out install' + +[deps] +build = ["make", "gmp"] diff --git a/scripts/cosmic/hydrate-cosmic.sh b/scripts/cosmic/hydrate-cosmic.sh index 377530a2..7b442faa 100755 --- a/scripts/cosmic/hydrate-cosmic.sh +++ b/scripts/cosmic/hydrate-cosmic.sh @@ -52,6 +52,9 @@ else # …y su MOTOR, que es otro binario y de otro repo: cosmic-launcher sólo dibuja, `pop-launcher` # busca. Lo lanza como proceso hijo por PATH, así que —otra vez— ningún grafo de deps lo ve. recipes/incoming-cosmic/pop-launcher.toml + # …y `qalc`, que es a lo que el plugin `calc` del lanzador le pasa la expresión. Tercer nivel de + # hijo invisible para el grafo: sesión → lanzador → pop-launcher → qalc, todos por PATH. + recipes/incoming-cosmic/libqalculate.toml recipes/incoming-cosmic/cosmic-app-library.toml recipes/incoming-cosmic/cosmic-workspaces-epoch.toml # Ni binario ni librería: DATOS. El tema de iconos de COSMIC — sin él el escritorio no se ve