gioser

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 188Rust 55Shell 30Markdown 281211 Definiciones

gnome-keyring necesita la API VIEJA de gcr, y vte destapó un -c que gana sobre un -E

gnome-keyring 48 —la última que hay— sigue pidiendo `gck-1` y `gcr-base-3` (meson.build:37-38), y
el gcr sellado de esta cola (4.4.0.1) publica `gck-2.pc` y `gcr-4.pc`. No son dos versiones del
mismo paquete: son dos APIs con dos nombres de pkg-config, y upstream no migró. De ahí `gcr3.toml`,
que convive con la 4.x sin pisar un solo fichero (medido: libgcr-base-3/libgck-1 y cabeceras en
gcr-3/ y gck-1/, contra libgcr-4/libgck-2 y gcr-4/ y gck-2/).

`libcap-ng` entra aunque upstream la declare `required: false`, y la razón está en el código:
`daemon/gkd-capability.c` está entero bajo `#ifdef HAVE_LIBCAPNG` y `gkd-main.c:1019` llama a su
función lo primero. Sin la lib, quedarse con CAP_IPC_LOCK (para mlock de la memoria de los
secretos) y soltar el resto de privilegios se compila VACÍO: no falla, no hace nada.

Y los muros de vte, en orden, porque los tres son reutilizables:

1. `-nostdlib` en `cpp_args` de un target (src/meson.build:597). Con gcc/clang es inocuo al
   compilar; con `zig c++` omite también los -isystem de libc++ ⇒ `'cstdio' file not found` en UN
   fichero mientras los otros 200 compilan.
2. `minifont.cc` NO SE COMPILA NUNCA por diseño: sus #include están dentro de
   `#ifndef MINIFONT_COVERAGE` y el paso lo invoca con ese define, porque sólo se quiere el texto
   preprocesado para sacarle las etiquetas `case 0x2500...:`. La regla que meson emite es
   `hammer-zig-cxx -E -P … -o $out -c $in`: gcc y clang resuelven la fase final y -E gana; el
   driver de zig hace lo contrario y COMPILA ⇒ 30 `unknown type name 'gunichar'` que se leen como
   un fuente roto. Se quita el `-c` de ESA regla del build.ninja, con el rango acotado (el mismo
   texto está en cpp_COMPILER y un reemplazo global deja al proyecto sin compilar).
   ⚠ La causa real es del wrapper `hammer-zig-cxx`, que ya tiene rama para `-E` y debería descartar
   el `-c` ahí. Queda anotado con fichero y línea; no se toca infraestructura compartida de paso.
3. `W_EXITCODE` (widget.cc:929) es macro de glibc, no de POSIX. Primer muro de esta tanda que es de
   la distro y no de nuestras herramientas. Fallback con #ifndef y la definición literal de glibc.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

043800faad5d6eb00059a0641a57a3073983cfed · por Sergio · (hace 28 d) · padre 0808b47da · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

4 archivos · +273 −2

diff --git a/recipes/incoming-gnome/gcr3.toml b/recipes/incoming-gnome/gcr3.toml
new file mode 100644
index 00000000..e84f2478
--- /dev/null
+++ b/recipes/incoming-gnome/gcr3.toml
@@ -0,0 +1,58 @@
+# gcr3 3.41.2 — la serie 3.x de gcr, que CONVIVE con la 4.x ya sellada en esta cola.
+#
+# ── POR QUÉ DOS gcr, Y NO ES UN OLVIDO NI UN DUPLICADO ─────────────────────────────────────────
+# `gnome-keyring 48` —la última versión que hay— sigue pidiendo la API vieja, y sin perilla:
+#
+#     meson.build:37  gck_dep      = dependency('gck-1',       version: '>= 3.3.4')
+#     meson.build:38  gcr_base_dep = dependency('gcr-base-3',  version: '>= 3.27.90')
+#
+# Y el artefacto de `gcr.toml` (4.4.0.1) publica `gck-2.pc` y `gcr-4.pc` — comprobado sobre el store,
+# no supuesto. Son APIs distintas con nombres distintos, no dos versiones de la misma cosa: upstream
+# renumeró al pasar a GTK4 y gnome-keyring no siguió. O se autora la 3.x, o gnome-keyring no entra.
+#
+# ⚠ NO COLISIONAN, y conviene dejarlo medido para quien dude:
+#     gcr 4.4.0.1 → libgcr-4.so, libgck-2.so, cabeceras en gcr-4/ y gck-2/, binario gcr4-ssh-askpass
+#     gcr 3.41.2  → libgcr-base-3.so, libgck-1.so, cabeceras en gcr-3/ y gck-1/
+# Ningún fichero compartido. Lo ÚNICO que podría chocar son las traducciones —las dos series usan el
+# dominio `gcr`— y hoy no chocan porque `gcr.toml` borra su `subdir('po')` entero. Si algún día se
+# le devuelven las traducciones a gcr4, hay que mirar esto.
+#
+# ── LAS PERILLAS ───────────────────────────────────────────────────────────────────────────────
+#   -Dgtk=false        (default TRUE) → **BLOQUEANTE**: la UI de esta serie es GTK**3**
+#                      (`meson.build:70`, `dependency('gtk+-3.0')`), aparcado por diseño en este
+#                      frente. Lo que se pierde es `gcr-viewer` y los diálogos de certificado de la
+#                      serie vieja; gnome-keyring sólo necesita `gcr-base-3`, que es la parte sin UI.
+#   -Dssh_agent=false  (default TRUE) → construiría un SEGUNDO agente SSH además del que el propio
+#                      gnome-keyring puede dar. Dos agentes compitiendo por `SSH_AUTH_SOCK` es peor
+#                      que ninguno. (El de gnome-keyring también queda apagado; ver su receta.)
+#   -Dsystemd=disabled → activación por socket de systemd, que acá no existe (ADR 0007).
+#   -Dintrospection=false / -Dgtk_doc=false → typelib `Gcr-3`/`Gck-1` y gtk-doc: nadie los pide. El
+#                      consumidor es gnome-keyring, que es C. ⚠ Ojo si algún día se encienden: el
+#                      typelib de la serie 3 y el de la 4 SÍ comparten espacio de nombres de fichero
+#                      por versión de API, y ahí sí habría que mirar.
+#   -Dgpg_path=/usr/bin/gpg → explícito, igual que en gcr4: sin esto el configure lo AUTODETECTA del
+#                      sysroot de build y la ruta horneada dependería de qué hubiera ese día.
+#
+# ⚠ EL `sed` DEL `ar`: `po/ar.po` trae 1 `msgstr[5]` y con uno alcanza para el SIGILL del msgfmt de
+# gettext-tiny ([[gettext-tiny-msgfmt-plural-arabe]]). Acá se saca SÓLO el árabe, en vez de borrar
+# `subdir('po')` como hizo gcr4: esta receta conserva las otras ~40 traducciones.
+name    = "gcr3"
+version = "3.41.2"
+license = "LGPL-2.1-or-later"
+
+[source]
+tarball = "https://download.gnome.org/sources/gcr/3.41/gcr-3.41.2.tar.xz"
+sha256  = "bad10f3c553a0e1854649ab59c5b2434da22ca1a54ae6138f1f53961567e1ab7"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "dynamic"
+
+[build.phases]
+configure = "sed -i '/^ar$/d' po/LINGUAS && PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload -Ddefault_library=shared -Dgtk=false -Dssh_agent=false -Dsystemd=disabled -Dintrospection=false -Dgtk_doc=false -Dgpg_path=/usr/bin/gpg -Dc_args=-Wno-error=date-time"
+compile   = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
+install   = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
+
+[deps]
+build = ["meson", "samurai", "python3", "pkgconf", "gettext-tiny", "glib", "p11-kit", "libgcrypt-shared", "libgpg-error-shared", "libffi", "pcre2", "zlib-shared"]
diff --git a/recipes/incoming-gnome/gnome-keyring.toml b/recipes/incoming-gnome/gnome-keyring.toml
new file mode 100644
index 00000000..02b2c857
--- /dev/null
+++ b/recipes/incoming-gnome/gnome-keyring.toml
@@ -0,0 +1,72 @@
+# gnome-keyring 48.0 — el demonio que guarda contraseñas: el que contesta a
+# `org.freedesktop.secrets` en D-Bus y el que tiene el almacén cifrado detrás.
+#
+# ── NO ES UN LUJO: ES LA MITAD QUE FALTABA DE UNA CADENA YA CONSTRUIDA ─────────────────────────
+# `libsecret` y `evolution-data-server` están sellados en esta cola desde hace tiempo. `libsecret`
+# es el CLIENTE del Secret Service; sin un demonio que sirva ese nombre de D-Bus, sus llamadas no
+# fallan: **contestan «no hay nada» con éxito**, que es indistinguible de un usuario que todavía no
+# guardó ninguna credencial. Media cadena de secretos es la que niega todo en silencio — el mismo
+# cuadro que el repo ya documentó con la bóveda de atuq. Esto cierra la otra mitad.
+#
+# ── POR QUÉ ARRASTRA UN `gcr3` ENTERO, y no es un descuido ─────────────────────────────────────
+#     meson.build:37  dependency('gck-1',      version: '>= 3.3.4')
+#     meson.build:38  dependency('gcr-base-3', version: '>= 3.27.90')
+# La versión 48 —la última publicada— sigue en la API vieja de gcr, y el `gcr` de esta cola (4.4.0.1)
+# publica `gck-2.pc`/`gcr-4.pc`. No son dos versiones de lo mismo con un número distinto: son dos
+# APIs con dos nombres de pkg-config. De ahí `gcr3.toml`, que explica por qué las dos conviven sin
+# pisarse un solo fichero.
+#
+# ── LAS PERILLAS, y dos son de seguridad ───────────────────────────────────────────────────────
+#   -Dpam=false        (default TRUE) → **BLOQUEANTE**: el helper PAM necesita linux-pam, que es una
+#                      de las tres deudas aparcadas del frente (GTK3 / X11 / PAM) y que además no
+#                      tendría quién lo invoque: arje-zero no abre sesiones PAM. Lo que se pierde es
+#                      **desbloquear el llavero automáticamente al iniciar sesión**: acá el llavero
+#                      se desbloquea cuando la primera aplicación lo pida y el usuario escriba la
+#                      contraseña. Es un cambio de experiencia REAL, no un detalle de empaquetado.
+#   -Dsystemd=disabled (default `enabled`) → activación por socket de systemd (ADR 0007).
+#   -Dselinux=disabled (default `auto`) → no hay SELinux acá, y con `auto` el artefacto dependería de
+#                      qué haya en el sysroot el día del build. Era una de las «fronteras» que el
+#                      seed de nixpkgs le atribuía y no lo es.
+#   -Dssh-agent=false  (ya es el default, se declara) → gnome-keyring puede hacer de agente SSH. Se
+#                      deja apagado a propósito: `openssh` del perfil `base` ya trae `ssh-agent`, y
+#                      dos agentes peleándose por `SSH_AUTH_SOCK` es peor que uno. Encenderlo es una
+#                      decisión de escritorio, no de esta receta.
+#   -Dmanpage=false    (default TRUE) → pide `xsltproc` + docbook, que no están en el catálogo.
+#   -Ddebug-mode=false (default TRUE) → compila FUERA el código de traza (`-DWITH_DEBUG=1`,
+#                      `meson.build:81-83`). En el demonio que sostiene las contraseñas en memoria,
+#                      el código de depuración es superficie que no queremos en producción. Si hace
+#                      falta diagnosticar, se re-sella con la bandera puesta.
+#
+# ── `libcap-ng` ENTRA AUNQUE UPSTREAM LA DECLARE OPCIONAL ──────────────────────────────────────
+# Es `required: false` (`meson.build:40`) y con eso el build pasa igual — pero `gkd-capability.c`
+# está entero dentro de `#ifdef HAVE_LIBCAPNG` y `gkd-main.c:1019` llama a su función SIEMPRE, lo
+# primero. Sin la lib, quedarse con `CAP_IPC_LOCK` (para `mlock()` la memoria de los secretos, que
+# no acabe en swap) y soltar el resto de privilegios se vuelve un no-op mudo. Ver `libcap-ng.toml`.
+#
+# ⚠ SIN `sed` del `ar`: medido, su `po/ar.po` trae CERO `msgstr[5]` ⇒ la traducción se conserva.
+#
+# ⚠ SIN `[[service]]` TODAVÍA, y es una decisión que hay que mirar, no un olvido: el demonio se
+# activa por D-Bus (`org.freedesktop.secrets`), que es el camino por el que libsecret lo despierta
+# solo. Declararlo además como servicio de sesión —como hace `wireplumber` en esta cola— duplicaría
+# el arranque. El día que el perfil quiera el llavero vivo ANTES de que alguien lo pida (para
+# desbloquearlo al entrar), eso es un `[[service]]` con `scope = "session"` y su decisión propia.
+name    = "gnome-keyring"
+version = "48.0"
+license = "GPL-2.0-or-later AND LGPL-2.0-or-later"
+
+[source]
+tarball = "https://download.gnome.org/sources/gnome-keyring/48/gnome-keyring-48.0.tar.xz"
+sha256  = "f20518c920e9ea3f9c9b8b44be8c50d8d7feecd0dd5624960f77bd2ca4fbeb9d"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "dynamic"
+
+[build.phases]
+configure = "PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload -Dssh-agent=false -Dpam=false -Dselinux=disabled -Dsystemd=disabled -Dmanpage=false -Ddebug-mode=false -Dc_args=-Wno-error=date-time"
+compile   = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
+install   = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
+
+[deps]
+build = ["meson", "samurai", "python3", "pkgconf", "gettext-tiny", "glib", "gcr3", "p11-kit", "libgcrypt-shared", "libgpg-error-shared", "libcap-ng", "libffi", "pcre2", "zlib-shared"]
diff --git a/recipes/incoming-gnome/libcap-ng.toml b/recipes/incoming-gnome/libcap-ng.toml
new file mode 100644
index 00000000..7ce6c59d
--- /dev/null
+++ b/recipes/incoming-gnome/libcap-ng.toml
@@ -0,0 +1,46 @@
+# libcap-ng 0.8.5 — la API sencilla de capabilities de Linux. La pide `gnome-keyring`, y aunque
+# upstream la declara `required: false` (`meson.build:40`), acá entra a propósito. La razón está en
+# el código, no en la lista de deps.
+#
+# ── QUÉ SE APAGA SI FALTA: `gkd-capability.c` ENTERO ───────────────────────────────────────────
+# `daemon/gkd-capability.c` está envuelto en `#ifdef HAVE_LIBCAPNG` de punta a punta, y su única
+# función la llama `daemon/gkd-main.c:1019` **antes de nada**:
+#
+#     gkd_capability_obtain_capability_and_drop_privileges ()
+#
+# Lo que hace: si el demonio corre con privilegios, se queda SÓLO con `CAP_IPC_LOCK` —lo que le
+# permite `mlock()` la memoria donde viven las contraseñas, para que no acabe en swap— y suelta todo
+# lo demás con `capng_change_id`, abortando si no puede. Sin libcap-ng esa función **se compila
+# vacía**: no es que falle, es que no hace nada, y el demonio de secretos se queda sin las dos
+# mitades — ni retiene lo que necesita ni suelta lo que no.
+#
+# Por eso una dep «opcional» se declara acá: el repo acaba de pagar (SDD 28 §5.11) el precio de un
+# bit de privilegio que se declaraba y no se verificaba. Ésta es la otra cara — la pieza que, si no
+# está, hace que soltar privilegios sea un no-op silencioso.
+#
+# `--without-python3`: las bindings de Python son para escribir herramientas de capabilities, no
+# para esta cadena. `--disable-static`: el consumidor es un ejecutable, pero toda la cola es la isla
+# dinámica y mezclar criterios por receta es cómo se llega a dos copias de la misma lib.
+#
+# ⚠ Fuente: el sitio del autor (Steve Grubb, Red Hat) es el upstream real de libcap-ng; no hay
+# release en GitHub. Si el mirror de fuentes (ADR 0013) no lo tiene, ésta es la URL a espejar.
+name    = "libcap-ng"
+version = "0.8.5"
+license = "LGPL-2.1-or-later"
+
+[source]
+tarball = "https://people.redhat.com/sgrubb/libcap-ng/libcap-ng-0.8.5.tar.gz"
+sha256  = "3ba5294d1cbdfa98afaacfbc00b6af9ed2b83e8a21817185dfd844cc8c7ac6ff"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "dynamic"
+
+[build.phases]
+configure = "CFLAGS='-O2 -fPIC' ./configure --build=$CBUILD --host=$CHOST --prefix=/usr --enable-shared --disable-static --without-python3 --disable-dependency-tracking"
+compile   = 'make -j"$(nproc)"'
+install   = 'make DESTDIR=/out install'
+
+[deps]
+build = ["make"]
diff --git a/recipes/incoming-gnome/vte.toml b/recipes/incoming-gnome/vte.toml
index 8448f67f..46e9cdf0 100644
--- a/recipes/incoming-gnome/vte.toml
+++ b/recipes/incoming-gnome/vte.toml
@@ -17,12 +17,107 @@
 #   -Dgtk3=false                   → GTK3 aparcado por diseño en este frente. gnome-console pide la
 #        variante `-gtk4`, que es la que queda encendida.
 #   -Dglade=false                  → sólo instala el catálogo XML del diseñador Glade, que no está.
-#   -Dgir=false / -Ddocs=false     → typelib y gi-docgen; el consumidor de hoy es C.
+#   -Dgir=false / -Dvapi=false / -Ddocs=false → typelib, bindings de Vala y gi-docgen; el consumidor
+#        de hoy es C. ⚠ `vapi` NO se puede omitir cuando se apaga `gir`, y el fallo es un ASSERT, no
+#        una dep faltante: `bindings/vala/meson.build:17` ⇒ `Assert failed: gir is required for vala
+#        support`. Costó la primera corrida de esta receta. Las dos vienen en `true` de fábrica, así
+#        que apagar una sola deja el proyecto en un estado que él mismo declara imposible.
 #   -Dicu=true / -Dfribidi=true / -Da11y=true → ENCENDIDAS y no es el default por casualidad: icu4c
 #        y fribidi ya están selladas. icu da las codificaciones heredadas (un `ssh` a una máquina en
 #        latin-1 deja de ser basura) y fribidi el bidireccional (árabe, hebreo). a11y es el árbol de
 #        accesibilidad: sin él un lector de pantalla no ve NADA de lo que pasa en la terminal.
 #
+# ── EL `sed` DEL `-nostdlib`: UNA BANDERA DE ENLACE PUESTA EN LAS DE COMPILAR ──────────────────
+# `src/meson.build:594-603` construye `vte-urlencode-cwd` —el ayudante de 100 líneas que codifica el
+# directorio actual para la integración con la shell— con `cpp_args: ['-nostdlib']`. La intención de
+# upstream es no arrastrar la stdlib de C++ al enlazar un binario diminuto, y con gcc/clang de
+# sistema eso es inocuo en la fase de compilar (`-nostdlib` es del enlazador). **Con `zig c++` no lo
+# es**: la bandera le hace omitir también los `-isystem` de libc++, y el fichero muere en su primer
+# `#include`:
+#
+#     ../src/urlencode.cc:22:10: fatal error: 'cstdio' file not found
+#
+# Y el resto del proyecto compila: los otros 200 `.cc` pasan sin ruido, así que el log NO se lee
+# como «falta el compilador de C++», se lee como un fichero roto. Costó una corrida.
+# El sed borra esa línea sola (aparece UNA vez en todo el fichero, comprobado). Lo que cambia es que
+# ese ayudante enlaza la libc++ de zig como todo lo demás: unos KB más en un binario de `libexec`.
+#
+# ══ `W_EXITCODE`: UN MACRO DE GLIBC QUE MUSL NO TIENE ══════════════════════════════════════════
+# `src/widget.cc:929` hace `int status = W_EXITCODE(0, SIGKILL);` para fabricar el estado de salida
+# del hijo cuando vte lo mata ella misma. Upstream sabe de dónde sale y lo escribe en el include:
+#
+#     src/widget.cc:23   #include <sys/wait.h> // for W_EXITCODE
+#
+# Sólo que **ese macro es de glibc**, no de POSIX: glibc lo define en `sys/wait.h` como
+# `__W_EXITCODE(ret, sig)`, y musl no lo define en ninguna parte. El error —`use of undeclared
+# identifier 'W_EXITCODE'`— es la primera cosa de esta receta que es un problema de la DISTRO y no
+# de nuestras herramientas.
+#
+# El sed añade el fallback justo después del include, con la definición de glibc literal
+# (`((ret) << 8 | (sig))`: el código de salida en el byte alto, la señal en el bajo — el formato que
+# `waitpid` devuelve), guardado por `#ifndef` para que en una libc que sí lo traiga no cambie nada.
+# Y borra el comentario `// for W_EXITCODE` del include, que dejaría de ser cierto.
+#
+# ══ EL MURO DE `minifont.cc`: UN `-c` QUE GANA SOBRE UN `-E` ═══════════════════════════════════
+# Éste costó tres corridas y las dos primeras hipótesis eran falsas, así que va entero.
+#
+# **El síntoma**: `../src/minifont.cc:42:9: error: unknown type name 'gunichar'`, y 30 más iguales,
+# en el paso `[156/232] Compiling C++ object src/preprocessor_0.p/minifont.cc.i`. Los otros ~200
+# `.cc` del proyecto compilan sin ruido, así que se lee como un fuente roto.
+#
+# **Lo que realmente pasa**: ese fichero NO SE COMPILA NUNCA, por diseño de upstream. Sus `#include`
+# están dentro de `#ifndef MINIFONT_COVERAGE` (`minifont.cc:21-36`), y el paso lo invoca justamente
+# con `-DMINIFONT_COVERAGE`. La razón es que `minifont-coverage.py` sólo quiere las etiquetas
+# `case 0x2500 ... 0x257f:` del fuente —de ahí saca qué glifos dibuja vte a mano— y para eso le basta
+# el texto con las directivas resueltas. De ahí `cxx.preprocess()` con `-fdirectives-only`.
+#
+# **Por qué se compila igual**: la regla que meson emite es
+#
+#     rule cpp_PREPROCESSOR
+#      command = hammer-zig-cxx -E -P -xc++ $ARGS … -o $out -c $in
+#                               ↑ preprocesar                  ↑ …y compilar
+#
+# Con gcc o clang de sistema eso es inocuo: su driver resuelve la fase final y `-E` gana sobre `-c`.
+# **El driver de zig hace lo contrario** y compila. Entonces el fichero se analiza de verdad, sin sus
+# includes (que él mismo se salta), y salen 30 tipos desconocidos.
+#
+# **El arreglo, acotado a esta receta**: quitar el `-c` DE ESA REGLA en el `build.ninja`, después del
+# `meson setup`. El rango del sed (`/^rule cpp_PREPROCESSOR$/,/^$/`) no es cosmético: el mismo
+# `-o $out -c $in` aparece en `cpp_COMPILER`, y un reemplazo global dejaría al proyecto entero sin
+# compilar.
+#
+# ⚠ **LA CAUSA NO ES DE VTE NI DE ESTA RECETA: es del wrapper del compilador.** `hammer-zig-cxx`
+# (`crates/takana-build/src/sandbox.rs::write_cc_wrappers`) ya tiene una rama especial para `-E`
+# —la puso el caso de los generadores de util-linux, que morían con un `-mcpu=` vacío—; lo que le
+# falta es, en ESA misma rama, descartar el `-c`. Arreglarlo ahí lo arregla para cualquier proyecto
+# que use `cxx.preprocess()` de meson, que no va a ser el último. No se toca de paso: es
+# infraestructura compartida y hay otro agente trabajando. Queda escrito acá con nombre y línea.
+#
+# ── LOS `-I` EN `cpp_args`: LA REGLA DE PREPROCESADO NO HEREDA LAS DEPS ────────────────────────
+# `src/meson.build:414` llama a `cxx.preprocess()` sobre `minifont.cc` —para que
+# `minifont-coverage.py` saque de ahí la tabla de glifos que vte dibuja a mano— y le pasa
+# `include_directories: [top_inc]` y NADA MÁS: ni `dependencies:`, que meson acepta y upstream no
+# usa. La regla que sale al ninja lo confirma (leída del `build.ninja` real):
+#
+#     build src/preprocessor_0.p/minifont.cc.i: cpp_PREPROCESSOR ../src/minifont.cc
+#      ARGS = -Isrc/preprocessor_0.p -Isrc -I../src -I. -I.. … -fdirectives-only -DVTE_GTK=4
+#                                                    ↑ ni un -I de glib, gtk, cairo…
+#
+# ⇒ el fichero se preprocesa sin ver `<gdk/gdk.h>` ni `<glib.h>`, y el error NO dice «falta un
+# include»: dice `unknown type name 'gunichar'`, `unknown type name 'GList'`, seis veces seguidas,
+# como si el fuente estuviera roto. Los otros ~200 `.cc` del proyecto compilan bien, que es lo que
+# hace el diagnóstico engañoso.
+#
+# La salida es no tocar el `meson.build` de upstream: `-Dcpp_args` SÍ llega a esa regla (se ve el
+# `-Wno-error=date-time` en el ARGS de arriba), así que se le añaden los `-I` de gtk4 pedidos a
+# pkg-config — que arrastra glib, cairo, pango, gdk-pixbuf, graphene y harfbuzz. Son los mismos
+# directorios que los targets normales ya reciben por sus deps: acá se vuelven globales, que es
+# inocuo, en vez de parchear una llamada de un fichero ajeno.
+# ⚠ El `PKG_CONFIG_PATH` va DENTRO del `$(...)`: un prefijo `VAR=x cmd` no está en vigor durante la
+# sustitución de comandos de esa misma línea.
+# ⚠ Y esto NO era lo que rompía `minifont.cc` —ver el bloque de arriba—, pero hacía falta igual: sin
+# los `-I`, el mismo paso fallaba antes con `'gdk/gdk.h' file not found` en cuanto dejó de compilar.
+#
 # ── `fast-float` NO es una dep opcional disfrazada ──────────────────────────────────────────────
 # `meson.build:694` compila una sonda con `#include <fast_float/fast_float.h>`; si falla, cae a un
 # subproyecto **git** que `--wrap-mode=nodownload` no puede traer. Ver `fast-float.toml`, que existe
@@ -48,7 +143,7 @@ target   = "x86_64-linux-musl"
 link     = "dynamic"
 
 [build.phases]
-configure = "PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload -Ddefault_library=shared -D_b_symbolic_functions=false -Dgtk3=false -Dgtk4=true -Dgnutls=false -Dglade=false -Dgir=false -Ddocs=false -D_systemd=false -Dicu=true -Dfribidi=true -Da11y=true -Dc_args=-Wno-error=date-time -Dcpp_args=-Wno-error=date-time"
+configure = '''sed -i "/^    '-nostdlib',$/d" src/meson.build && sed -i 's@#include <sys/wait.h> // for W_EXITCODE@#include <sys/wait.h>\n#ifndef W_EXITCODE\n#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))\n#endif@' src/widget.cc && PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload -Ddefault_library=shared -D_b_symbolic_functions=false -Dgtk3=false -Dgtk4=true -Dgnutls=false -Dglade=false -Dgir=false -Dvapi=false -Ddocs=false -D_systemd=false -Dicu=true -Dfribidi=true -Da11y=true -Dc_args=-Wno-error=date-time -Dcpp_args="-Wno-error=date-time $(PKG_CONFIG_PATH=/usr/lib/pkgconfig pkg-config --cflags-only-I gtk4)" && sed -i '/^rule cpp_PREPROCESSOR$/,/^$/ s/ -c [$]in/ $in/' output/build.ninja'''
 compile   = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
 install   = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"