# brltty 6.9.1 — el driver de DISPLAYS BRAILLE. Cierra el hueco de accesibilidad para quien no ve # y no usa voz. # # ══ POR QUÉ ES SU PROPIO FRENTE, Y NO «lo mismo que la voz» ════════════════════════════════════ # La voz y el braille no son alternativas de gusto. Braille es lo que permite leer código, # ortografía, tablas y matemáticas —cosas donde escuchar no alcanza— y es el único camino para quien # además no oye. Una distro con voz y sin braille deja afuera a sordociegos por completo. # # brltty lee la pantalla (la consola de Linux y, vía BrlAPI, las apps) y la escribe en el display. # Trae **42 drivers de braille** para hardware de distintos fabricantes. # # ══ LAS PERILLAS QUE IMPORTAN ══════════════════════════════════════════════════════════════════ # --enable-api **BrlAPI**: el protocolo por el que una aplicación —`orca`, un editor— toma # el display en vez de dejárselo a la lectura de pantalla. Sin esto brltty # sirve para la consola y nada más # --enable-liblouis braille CONTRAÍDO. Sin liblouis es una celda por carácter: legible, tres # veces más largo, y nadie lee así un texto. Ver `recipes/liblouis.toml` # --disable-x la distro es Wayland-only # --disable-icu `icu` no está en el corpus. Lo que se pierde es normalización Unicode fina # en la conversión de texto; `--enable-iconv` cubre el caso general # --disable-polkit no hay polkit en esta pila # --disable-gpm el ratón de consola; no está en el corpus # # ⚠ **`--disable-python-bindings`, Y ES UNA PÉRDIDA CONCRETA QUE SE DICE EN VEZ DE DISIMULARSE.** # El binding es un `.pyx` y necesita **Cython** (`Bindings/Python/bindings.m4:108`: # `AC_PATH_PROGS([CYTHON], [cython3 cython])`), que **no está en el corpus ni en ninguna cola** # (comprobado). Y el `configure` sólo emite un `AC_MSG_WARN` si falta: o sea que **sin apagarlo # explícitamente el binding se salta EN SILENCIO** y el artefacto sale igual. # # Lo que eso bloquea, concreto: `orca` importa el módulo `brlapi` de Python para manejar el # display. ⇒ con esta receta brltty funciona para la CONSOLA y para cualquier app que use BrlAPI en # C, pero **orca no podrá usar braille hasta que exista una receta de `cython`**. Se apaga a # propósito para que el día que alguien lo necesite el motivo esté escrito, en vez de descubrir un # hueco que nadie decidió. # # Los otros bindings (java, lisp, lua, ocaml, tcl, emacs) se apagan por lo mismo: sus lenguajes no # están en el corpus y el `configure` los saltaría sin avisar. # # ⚠ `--sysconfdir=/etc`: con `--prefix=/usr` a secas autotools deriva `/usr/etc` en SILENCIO, y el # binario hornea esa ruta — el artefacto queda auto-consistente y la configuración, donde nadie la # busca. Pasó con `speech-dispatcher` el mismo día; 31 recetas del repo ya lo pasan. # # ✅ **`--enable-i18n` CON las nueve traducciones, incluida `ar.po` — y eso es MEDIDO, no un # descuido.** Este repo tiene documentado que el `msgfmt` de `gettext-tiny` muere con el árabe # (SIGILL y un `.mo` de 0 bytes), así que iba a parchear `ar.po` fuera. Antes lo probé: el # `ar.po` de brltty **compila bien** (rc=0, `.mo` de 67 300 bytes), igual que `fr` y `zh`. La nota # de la memoria vale para un caso concreto de plurales que este fichero no dispara. *Una memoria # describe lo que era cierto cuando se escribió; se verifica antes de actuar sobre ella.* name = "brltty" version = "6.9.1" license = "LGPL-2.1-or-later" [source] # ⚠ El tarball OFICIAL de brltty.app, no el archive del tag de GitHub: el del tag trae sólo # `configure.ac` y el lab no tiene autoconf ni automake. Tercera vez que mirar si upstream publica # un tarball de release ahorra escribir un autoconf. tarball = "https://brltty.app/archive/brltty-6.9.1.tar.xz" sha256 = "cf4619ce1471690e4ecc5544ee6289cef6c5bdf5855a1ac8dcc63f5beedf108d" [build] compiler = "zig-cc" target = "x86_64-linux-musl" link = "dynamic" flags = [] [build.phases] configure = ''' set -e [ -f ./configure ] || { echo "brltty: el tarball no trae ./configure — ¿se cambió por el archive del tag?" >&2; exit 1; } # ⚠ **PARCHE: el `msgfmt` de `gettext-tiny` no soporta la opción LARGA `--output-file`.** # `Messages/Makefile.in:57` invoca así: # # $(MSGFMT) --output-file $@ -- .po # ⇒ fopen: No such file or directory … y **sale con rc=0** # # Medido aislando cada parte: con `-o` el mismo `ar.po` compila (67 300 bytes); con `--output-file` # falla, y falla igual el francés. O sea que **no es el idioma, es la opción**, y `ar.po` sólo era # el primero por orden alfabético. # # ⚠ **Y me equivoqué antes de llegar acá, en dos pasos que vale anotar.** (1) Este repo tiene # documentado que el msgfmt de gettext-tiny muere con el árabe, así que iba a quitar `ar.po`; probé # primero y «compilaba bien» — cierto, pero con `-o`, que **no es la invocación que usa el build**. # Verifiqué el fichero correcto con el comando equivocado. (2) El tool devuelve **rc=0 mientras no # escribe nada**: si `make` no comprobara que el `.mo` existe, esto habría pasado en silencio. Es la # misma familia que el `INSTALL_ROOT` de abajo — *un fallo que sale con éxito.* # # ⇒ Se cambia a `-o`, que gettext-tiny sí entiende, y así entran **las nueve traducciones** en vez # de perderlas con `--disable-i18n`. El hueco de `gettext-tiny` es real y va a morder a otras # recetas; barrerlo es su propia unidad de trabajo, no algo que se hace de paso. MF=Messages/Makefile.in grep -q -- '--output-file' "$MF" || { echo "brltty: $MF ya no usa --output-file; el parche de gettext-tiny sobra o cambió de forma — REVISAR" >&2; exit 1; } sed -i 's/--output-file \$@ --/-o $@/' "$MF" grep -q -- '--output-file' "$MF" && { echo "brltty: el parche de --output-file no se aplicó" >&2; grep -n 'MSGFMT' "$MF" >&2; exit 1; } grep -q -- '-o \$@' "$MF" || { echo "brltty: tras el parche no aparece '-o \$@' en $MF" >&2; grep -n 'MSGFMT' "$MF" >&2; exit 1; } echo "brltty: msgfmt pasa a la opción corta (gettext-tiny no entiende --output-file)" # ⚠ `-Wno-error=date-time`: `Headers/spk_driver.h:52` y `scr_driver.h:46` usan `__DATE__`/`__TIME__` # y **el lab compila con `-Werror=date-time`** — su política de reproducibilidad, que acá hizo # exactamente su trabajo y paró el build en los drivers de voz y de pantalla. # # Desactivarlo es SEGURO **porque el sandbox exporta `SOURCE_DATE_EPOCH=1`**: con esa variable # definida clang hace que `__DATE__`/`__TIME__` rindan esa fecha fija en vez de la del reloj, así # que el binario sigue siendo determinista. Sin `SOURCE_DATE_EPOCH` esto sería hornear la hora del # build dentro del artefacto, que es justo lo que el warning previene. Mismo razonamiento y misma # cura que `fastfetch`, `cairo` y `appstream` en este repo — no es una excepción nueva. CFLAGS="${CFLAGS:-} -Wno-error=date-time" \ ./configure --build=$CBUILD --host=$CHOST --prefix=/usr --sysconfdir=/etc \ --enable-api --enable-liblouis --enable-i18n --enable-iconv --enable-expat \ --disable-x --disable-icu --disable-polkit --disable-gpm \ --disable-python-bindings --disable-java-bindings --disable-lisp-bindings \ --disable-lua-bindings --disable-ocaml-bindings --disable-tcl-bindings \ --disable-emacs-bindings ''' compile = 'make -j"$(nproc)"' # El guardián se escribe contra lo que el `install` de upstream PROMETE —leído en # `Programs/Makefile.in:1199`: programas, tablas, drivers, cabeceras, mensajes, el `.pc` y la # API— y busca por PATRÓN y no por ruta exacta, para no rechazar un build correcto por haberme # equivocado de directorio. Es la lección de los cuatro guardianes demasiado estrictos del 20-oct. install = ''' set -e # ⚠ **`INSTALL_ROOT` Y NO `DESTDIR`, Y ESTO ESTUVO A UN PASO DE SELLAR UN ARTEFACTO VACÍO.** # `common.mk` de brltty no menciona `DESTDIR` **ni una vez** (medido): usa su propia variable, # `INSTALL_ROOT`, para prefijar cada directorio de instalación. El sandbox exporta `DESTDIR=/out` # para todos, así que la forma habitual pasa inadvertida — y acá era un no-op: # # /usr/bin/install -c -d /usr/bin # /usr/bin/install -c -d /usr/libexec/brltty # install: cannot create directory '/usr/libexec/brltty': Value too large for data type # # Estaba instalando **en la raíz del sandbox**, no en `/out`. Falló sólo porque el overlay no lo # dejó escribir. **Si lo hubiera dejado, el build habría terminado con éxito y `/out` vacío** — y # un directorio vacío en el store no es un artefacto, es un nombre: se sella, es un cache-hit, y el # fallo llega hasta el final diciendo que todo fue bien. Es exactamente la regla 3 del repo, y la # única razón de que no pasara fue el permiso. # # ⇒ Corolario para cualquier receta nueva: **que `make install` no falle no prueba que haya # instalado donde creés.** El guardián de abajo lo comprueba igual, buscando los ficheros en `/out`. make install INSTALL_ROOT=/out b=$(find /out -name brltty -type f -perm -u+x 2>/dev/null | head -1) [ -n "$b" ] || { echo "brltty: no quedó el binario — NO sello" >&2; find /out -maxdepth 4 -type f -perm -u+x 2>/dev/null | head -20 >&2; exit 1; } # ⚠ EL CONTROL DECISIVO: que liblouis esté CABLEADA de verdad. # `--enable-liblouis` no garantiza nada por sí solo: brltty la busca por pkg-config y le pide la # variable `tablesdir` para hornearla como `LOUIS_TABLES_DIRECTORY` (`configure.ac:1214-1220`). Si # el `.pc` no definiera `tablesdir`, el valor quedaría VACÍO, el build saldría igual y brltty # tendría «soporte de braille contraído» sin saber dónde están las tablas — sellado, con contenido # y sin la función. Se comprueba en el BINARIO, que es donde el valor vive: strings "$b" 2>/dev/null | grep -q 'liblouis/tables' || { echo "brltty: el binario no trae la ruta de tablas de liblouis — el braille CONTRAÍDO no funcionaría, y sin error" >&2 strings "$b" 2>/dev/null | grep -i louis | head -5 >&2 exit 1 } # BrlAPI: sin esto ninguna aplicación puede tomar el display. api=$(find /out -name 'libbrlapi.so*' -o -name 'libbrlapi.a' 2>/dev/null | head -1) [ -n "$api" ] || { echo "brltty: no quedó libbrlapi — ninguna app podría manejar el display, sólo la consola" >&2; exit 1; } # Los drivers: 42 en el árbol. El piso es bajo a propósito —según cómo se enlacen pueden quedar # dentro del binario en vez de como módulos— pero CERO ficheros de datos de driver sí es un fallo. drv=$(find /out -name 'libbrltty*.so' 2>/dev/null | wc -l) # Las tablas de texto y de contracción propias de brltty. tbl=$(find /out -path '*brltty*' \( -name '*.ttb' -o -name '*.ctb' -o -name '*.ktb' -o -name '*.tti' \) 2>/dev/null | wc -l) [ "$tbl" -gt 50 ] || { echo "brltty: sólo $tbl tabla(s) propias — esperaba >50; sin ellas no sabe traducir a celdas" >&2; find /out -path '*brltty*' -name '*.ttb' 2>/dev/null | head -5 >&2; exit 1; } # La herramienta de tablas de contracción: es lo que prueba que ese camino se construyó. [ -n "$(find /out -name 'brltty-ctb' -type f 2>/dev/null | head -1)" ] || { echo "brltty: falta brltty-ctb — el compilador de tablas de contracción no se construyó" >&2; exit 1; } echo "brltty: binario + brlapi + $drv driver(s) externo(s) + $tbl tabla(s) + liblouis cableada" ''' [deps] build = ["make", "pkgconf", "liblouis", "ncurses", "expat", "alsa-lib", "gettext-tiny", "libtool", "python3", # ⚠ `binutils` por el GUARDIÁN (aporta `strings`), no por el build: sin declararlo el # control de liblouis fallaría por falta de herramienta y acusaría a la receta de algo que # no hizo. Misma nota que `espeak-ng` y `speech-dispatcher`. "binutils"]