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…
fix(fcitx5): el cache de cmake del intento fallido envenenaba todos los reintentos
1# fcitx5 — el marco de métodos de entrada. Lo que falta para ESCRIBIR en chino, japonés y coreano.
2#
3# ══ POR QUÉ ENTRA ══════════════════════════════════════════════════════════════════════════════
4# El 2026-10-19 entraron las fuentes Noto (`noto-fonts`, `noto-fonts-cjk`, `noto-fonts-emoji`), así
5# que la distro pasó de mostrar cuadraditos a LEER esos alfabetos. Escribirlos es otra cosa: un
6# teclado tiene cien teclas y el chino tiene decenas de miles de caracteres, así que hace falta un
7# motor que convierta lo que se teclea en lo que se escribe. `censo-distro.py` marcaba la categoría
8# «escribir en esos idiomas» 5 de 6 ausente.
9#
10# ══ LO QUE SE MIDIÓ ANTES DE ESCRIBIR ESTO ═════════════════════════════════════════════════════
11#
12# **1. NO hay muro estructural, y era la primera duda.** El camino de un IME en Wayland son dos
13# protocolos que el COMPOSITOR tiene que implementar; si no están, ningún paquete sirve y esto
14# habría sido trabajo tirado (como `kitty`, que no entra por falta de GL de escritorio).
15# `mirada-compositor` los registra los dos — `setup.rs:600-602`:
16# smithay::wayland::text_input::TextInputManagerState ⇒ zwp_text_input_v3
17# smithay::wayland::input_method::InputMethodManagerState ⇒ zwp_input_method_v2
18#
19# **2. Las dos deps que faltaban eran de COLA, no inexistentes.** `extra-cmake-modules` vivía en
20# `incoming-kde` y `iso-codes` en `incoming-gnome`, y una receta del corpus resuelve sibling-first y
21# después el catálogo padre — **nunca una cola hermana**. Se promovieron al corpus en el commit
22# anterior, verificando que es gratis: los 109 dependientes de ecm en incoming-kde conservan su hash
23# uno por uno.
24#
25# **3. Cinco deps se caen con dos perillas.** El `CMakeLists.txt` de upstream mete XCB y
26# `XCBImdkit` como REQUIRED **sólo dentro de `if(ENABLE_X11)`** (líneas 138-139), y `enchant2` sólo
27# con `ENABLE_ENCHANT`. Con las dos en Off desaparecen `xcb-imdkit`, `xcb-util-keysyms`,
28# `xcb-util-wm`, `libxkbfile` y `enchant2`. Y apagar X11 no es un recorte: **esta distro es
29# Wayland-only**, el X11 de fcitx5 sería código muerto.
30#
31# ══ LAS PERILLAS, UNA POR UNA ══════════════════════════════════════════════════════════════════
32# ENABLE_X11=Off Wayland-only por decisión de distro; se lleva cuatro deps
33# ENABLE_ENCHANT=Off predicción de palabras por diccionario: no la pide nadie y trae enchant2
34# USE_SYSTEMD=Off acá el init es `arje-zero`. Upstream dice que cae a libuv/libdbus, que SÍ
35# están — dejarlo en Auto haría que el build busque algo que no existe
36# ENABLE_TEST=Off y `ENABLE_TESTING_ADDONS=Off`, que es su requisito (su propio `option()`
37# lo dice). Los addons de prueba son un frontend falso para el test suite
38# ENABLE_DOC=Off doxygen no está en el corpus
39# BUILD_SPELL_DICT=Off construye `en_dict.fscd` para el corrector inglés — depende de enchant
40#
41# ⚠ `link = "dynamic"` **y no es opcional**: fcitx5 es un daemon cuyos métodos de entrada son
42# addons que carga con `dlopen` en tiempo de ejecución (`libexec/` + `lib/fcitx5/`). Un binario
43# `crt-static` no puede dlopen, así que estático sellaría un daemon incapaz de cargar un solo motor
44# — sellado, con contenido, reproducible e inerte.
45#
46# ══ ⚠ ESTO ES EL MARCO, NO UN MÉTODO DE ENTRADA ════════════════════════════════════════════════
47# fcitx5 solo no escribe chino: es la plomería (el daemon, el protocolo, la UI de la barra de
48# candidatos). Cada idioma es un addon APARTE y son recetas que todavía no existen:
49# fcitx5-chinese-addons pinyin (arrastra libime y libpinyin)
50# fcitx5-anthy japonés (arrastra anthy)
51# fcitx5-hangul coreano (arrastra libhangul)
52# fcitx5-rime los tres (arrastra librime, que es grande)
53# Declarar sólo esto en un perfil daría una barra de IME que no convierte nada. **Por eso NO se
54# declara en ningún perfil en este commit**: primero el marco construye, después un motor, y recién
55# entonces el par se declara junto. La alternativa —declarar el marco ya— es exactamente la figura
56# de `crun` sin podman y de `cups` sin filtros que este catálogo tiene documentada tres veces.
57name = "fcitx5"
58version = "5.1.14"
59license = "LGPL-2.1-or-later"
60
61[source]
62tarball = "https://github.com/fcitx/fcitx5/archive/refs/tags/5.1.14/fcitx5-5.1.14.tar.gz"
63sha256 = "c81bbf0156d083e4c7e7817e658122c33a8c1e585962467f251bc9614bdfee47"
64
65[build]
66compiler = "zig-cc"
67target = "x86_64-linux-musl"
68link = "dynamic"
69flags = []
70
71[build.phases]
72configure = '''
73ZW="$PWD/.zwrap"; mkdir -p "$ZW"
74printf '#!/bin/sh\nexec /opt/zig/zig cc -mcpu=baseline "$@"\n' > "$ZW/cc"
75printf '#!/bin/sh\nexec /opt/zig/zig c++ -mcpu=baseline "$@"\n' > "$ZW/cxx"
76chmod +x "$ZW/cc" "$ZW/cxx"
77# ⚠ **BORRAR `build/` ANTES DE CONFIGURAR, Y NO ES HIGIENE: ES CORRECCIÓN.** El árbol de fuentes
78# (`work/sources/<receta>-<sha>`) se REUSA entre builds — es caché por diseño—, así que un `build/`
79# de un intento anterior sobrevive con su `CMakeCache.txt`. Y `pkg_check_modules` cachea su
80# resultado: en la segunda corrida no vuelve a preguntar a pkg-config y **no recrea el target
81# importado**, así que `PkgConfig::Cairo` sigue ausente aunque el `.pc` ya resuelva.
82#
83# Medido el 2026-10-19 y cuesta un viaje entero: tras arreglar las deps que faltaban de verdad, el
84# build volvió a morir con EL MISMO error en **2 segundos** —«Generating done (0.0s)»— reusando el
85# cache del fallo anterior. Un primer fallo envenena todos los reintentos y el mensaje no lo dice:
86# es la figura de [[cache-congela-regresiones]] dentro de cmake.
87#
88# ⚠ Y esto NO es particular de fcitx5: toda receta de este repo que haga `cmake -B build` sin
89# limpiar tiene el mismo defecto latente. No se nota mientras el primer intento salga bien.
90rm -rf build
91cmake -B build -G Ninja -Wno-dev \
92 -DCMAKE_C_COMPILER="$ZW/cc" -DCMAKE_CXX_COMPILER="$ZW/cxx" -DCMAKE_ASM_COMPILER="$ZW/cc" \
93 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr \
94 -DENABLE_X11=Off -DENABLE_ENCHANT=Off -DUSE_SYSTEMD=Off \
95 -DENABLE_TEST=Off -DENABLE_TESTING_ADDONS=Off -DENABLE_DOC=Off \
96 -DBUILD_SPELL_DICT=Off
97'''
98compile = "cmake --build build"
99# El guardián de presencia, por la regla 3: lo que tiene que quedar es el DAEMON y su directorio de
100# addons. Un `cmake --install` que deje las cabeceras y los `.cmake` y ningún binario sellaría un
101# artefacto con contenido y sin función — y eso llega hasta el final diciendo que todo fue bien.
102install = '''
103set -e
104DESTDIR=/out cmake --install build
105[ -x /out/usr/bin/fcitx5 ] || { echo "fcitx5: no quedó /usr/bin/fcitx5 — NO sello un marco sin daemon" >&2; exit 1; }
106n=$(find /out/usr/lib/fcitx5 -name '*.so' 2>/dev/null | wc -l)
107echo "fcitx5: daemon + $n addon(s) de fábrica"
108[ "$n" -gt 0 ] || { echo "fcitx5: cero addons en /usr/lib/fcitx5 — el daemon no podría cargar ni su propia UI" >&2; exit 1; }
109'''
110
111[deps]
112# `iso-codes` y `extra-cmake-modules` son las dos promovidas al corpus para esto.
113# `util-linux` por `libuuid` (`find_package(LibUUID REQUIRED)`), `gettext-tiny` por `LibIntl`.
114#
115# ⚠ **EL CIERRE DE `.pc` NO ES EL DE LAS BIBLIOTECAS, Y MI PRIMERA LISTA LO IGNORÓ.** Declaré
116# `cairo`, `pango` y `glib`… bueno, `glib` ni eso, y el build murió al GENERAR —no al configurar—
117# con `Target "classicui" links to PkgConfig::Cairo but the target was not found`.
118#
119# La causa tiene dos mitades y las dos valen la pena:
120#
121# 1. `pkg_check_modules(Cairo IMPORTED_TARGET cairo)` va **SIN `REQUIRED`** (CMakeLists:162) y lo
122# mismo `Gio` (:173). Sin REQUIRED, pkg-config que no encuentra el módulo **no falla**: no crea
123# el target, el configure dice «Configuring done» y el error sale después, en `Generating`,
124# nombrando un target ausente en vez del `.pc` que falta. Dos errores distintos (Cairo y Gio)
125# con UNA sola causa, y ninguno nombra la causa.
126# 2. Un `.pc` falla si sus `Requires:` TRANSITIVOS no están. Medido en el artefacto:
127# cairo.pc Requires: zlib, libpng, fontconfig, freetype2, pixman-1
128# pangocairo.pc Requires: … fribidi, harfbuzz, fontconfig, freetype2, cairo
129# gio-2.0.pc Requires: glib-2.0, gobject-2.0, gmodule-no-export-2.0, zlib
130# Yo tenía `cairo` y `zlib`, y me faltaban los otros cuatro de cairo. Declarar la biblioteca
131# que uno usa no alcanza: hay que declarar el cierre de su `.pc`.
132#
133# ⇒ Entran `glib`, `libpng`, `fontconfig`, `freetype`, `pixman`, `fribidi`, `harfbuzz`. Comprobado
134# ANTES de relanzar, armando el `PKG_CONFIG_PATH` de este conjunto a mano y preguntando a `pkgconf`:
135# los seis módulos que fcitx5 busca —`cairo`, `gio-2.0`, `pango`, `pangocairo`, `gdk-pixbuf-2.0`,
136# `gio-unix-2.0`— resuelven. Un build de cmake cuesta minutos; esa comprobación, segundos.
137build = ["cmake", "samurai", "extra-cmake-modules", "pkgconf", "iso-codes", "xkeyboard-config",
138 "libxkbcommon", "wayland", "wayland-protocols", "cairo", "pango", "gdk-pixbuf",
139 "glib", "libpng", "fontconfig", "freetype", "pixman", "fribidi", "harfbuzz",
140 "dbus", "libuv", "nlohmann-json", "expat", "zlib", "gettext-tiny", "util-linux",
141 "libxml2", "json-c", "python3"]