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…
reparación: pisé la receta de swayimg de otro agente — y el volumen
1# swayimg 5.6 — el VISOR DE IMÁGENES. Cierra un hueco que el censo marcaba 5 de 5 ausente: la
2# distro no tenía NINGUNA forma de abrir un JPEG.
3#
4# ══ POR QUÉ ESTE Y NO LOS POPULARES: SE DESCARTARON POR MEDICIÓN ═══════════════════════════════
5# `nsxiv` es un fork de sxiv, **Xlib**. Esta distro es Wayland-only ⇒ muro, no candidato
6# `feh` idem, X11
7# `imv` es el que todo el mundo recomienda para Wayland, y **no sirve acá**: sus
8# `dependency()` piden `egl`, `gl`, `opengl`, `glu` y `wayland-egl`, y este corpus **no
9# publica `libGL.so` ni `gl.pc`** (comprobado en el store; es el muro documentado de «sin
10# OpenGL de escritorio», el mismo que bloquea a `kitty`)
11# `swayimg` **cero menciones de GL** en todo su `meson.build` (medido). Pinta por software sobre
12# `wayland-client`, con fontconfig/freetype para el texto
13#
14# ⇒ La lección de método: en este corpus, «el visor de imágenes estándar para Wayland» no es una
15# recomendación transferible — hay que mirar si pide GL antes de escribir la receta.
16#
17# ══ SUS DEPS OBLIGATORIAS SON CINCO, Y TODAS ESTABAN ═══════════════════════════════════════════
18# Leídas en su `meson.build`: `xkbcommon`, `fontconfig`, `freetype2`, `threads` y `wayland-client`
19# con `wayland-protocols >= 1.35` (tenemos 1.48). **Todo lo demás va detrás de una perilla**,
20# incluida `librsvg-2.0` — o sea que el bloqueo de GNOME no toca acá.
21#
22# ⚠ Con una excepción que casi no vi: `lua = dependency(get_option('liblua'))` **no es
23# condicional** — es obligatoria, y el nombre del módulo pkg-config sale de la opción.
24#
25# ⚠⚠ **Y ACÁ ME CORRIJO, PORQUE PISÉ TRABAJO AJENO.** Escribí esta receta con `cat >` **sin mirar
26# que ya existía**: otro agente la había llevado de 4.7 a 5.5, y mi versión borró 70 líneas suyas.
27# Entre ellas, la decisión de usar el default `luajit` — por eso ese agente había escrito
28# `recipes/luajit.toml`. Mi `-Dliblua=lua` dejó **su luajit sin un solo consumidor** (medido:
29# ningún `[deps]` del catálogo lo nombraba).
30#
31# ⇒ Vuelve a `luajit`, que es el default de upstream y lo que ese agente empaquetó para esto
32# (`luajit.pc`, `libluajit-5.1.{a,so}`, sellado al hash vigente). Lo que SÍ conservo de mi pasada es
33# `-Dexif=enabled` con `exiv2`: ellos lo tenían apagado, y sin EXIF las fotos verticales de móvil
34# salen tumbadas. Eso es una mejora, no una preferencia.
35#
36# La lección, que es la regla 2 del repo por otra puerta: **`cat >` sobre un fichero del repo
37# compartido es destructivo y no avisa.** El `git add` acotado no protege de esto — el fichero ya
38# estaba sobrescrito antes de llegar a git.
39#
40# ══ ⚠ TODAS LAS PERILLAS EXPLÍCITAS, Y ESO ES EL PUNTO DE ESTA RECETA ══════════════════════════
41# Sus opciones de formato son `feature` con default **`auto`**: una dep ausente se **salta en
42# silencio** y el build sale bien. Eso es exactamente la figura que este catálogo persigue —un visor
43# sellado que no abre PNG y no te dice por qué—. ⇒ cada formato se fija `enabled` o `disabled`:
44#
45# ENCENDIDOS (la dep está en el corpus, y si faltara el build DEBE fallar):
46# png jpeg webp tiff gif los formatos que cubren casi todo lo que alguien abre
47# exif `exiv2`, y NO es un adorno: una cámara de móvil no rota los
48# píxeles, anota la orientación en EXIF. Sin esto **todas las fotos
49# verticales salen tumbadas**, sin error y sin remedio
50# wayland compositor la ventana normal
51# drm ⚠ el modo sin compositor: ver una imagen **desde una consola TTY**.
52# En una distro que arranca a texto esto no es exótico, es el caso de
53# «mirá esta captura antes de levantar el escritorio»
54#
55# APAGADOS, con el motivo:
56# svg `librsvg-2.0` sólo existe en `incoming-gnome`, enredada con su pila
57# de introspección; promoverla cuesta 35 recetas (medido). **Lo que se
58# pierde es abrir SVG**, que es real y queda dicho
59# heif avif jxl jp2 exr raw los formatos modernos y de cámara: `libheif`, `libavif`, `libjxl`,
60# sixel `openjpeg`, `OpenEXR`, `libraw`, `libsixel` NO están en el corpus
61# video `ffmpeg` está, pero reproducir vídeo es trabajo de `mpv`, que ya
62# viaja. Un visor de imágenes no necesita arrastrar esa cadena
63# tests `gtest` no está en el corpus
64name = "swayimg"
65version = "5.6"
66license = "MIT"
67
68[source]
69tarball = "https://github.com/artemsen/swayimg/archive/refs/tags/v5.6/swayimg-5.6.tar.gz"
70sha256 = "0f70cbc665217a747e8a098e1a881239e96df270930f47c262ab2ecff290e428"
71
72[build]
73compiler = "zig-cc"
74target = "x86_64-linux-musl"
75link = "dynamic"
76flags = []
77
78[build.phases]
79# `-Dversion=5.6`: su default es `0.0.0` y lo hornea en `--version`. Dejarlo así daría un binario
80# que miente sobre qué es — y además haría imposible saber qué versión corre en una imagen.
81configure = '''
82set -e
83# ⚠ **`--prefer-static` NO es una preferencia de tamaño: sin él el enlace NO CIERRA.**
84# El corpus es estático-primero, y `libfontconfig.a` referencia **11 símbolos `XML_*` sin definir**
85# (medido) porque su `.pc` declara `Requires.private: expat`. pkg-config sólo entrega las privadas
86# en modo estático; en meson eso es `--prefer-static`. Sin la bandera, lld cortó con los once:
87#
88# ld.lld: error: undefined symbol: XML_ParserCreate … (y 10 más)
89#
90# ⚠ Y esos once errores NO venían de `exiv2`, aunque al principio los atribuí ahí: expat entra en
91# `libexiv2` con visibilidad HIDDEN/LOCAL —correcto, no exporta la API de expat— y los símbolos
92# aparecen definidos. Venían de fontconfig desde el primer intento. Es la lección de
93# [[control-antes-que-precision]] por el lado del diagnóstico: el primer sospechoso plausible no es
94# el culpable, y la forma de saberlo es mirar QUIÉN tiene el símbolo sin definir.
95PKG_CONFIG_PATH=/usr/lib/pkgconfig meson setup output --prefix=/usr --buildtype=release \
96 --prefer-static \
97 -Dversion=5.6 \
98 -Dliblua=luajit \
99 -Dpng=enabled -Djpeg=enabled -Dwebp=enabled -Dtiff=enabled -Dgif=enabled \
100 -Dexif=enabled \
101 -Dwayland=enabled -Dcompositor=enabled -Ddrm=enabled \
102 -Dsvg=disabled -Dheif=disabled -Davif=disabled -Djxl=disabled -Djp2=disabled \
103 -Dexr=disabled -Draw=disabled -Dsixel=disabled -Dvideo=disabled \
104 -Dtests=disabled
105'''
106compile = 'meson compile -C output'
107# El guardián no se conforma con que el binario exista: comprueba que los formatos que PEDIMOS
108# estén de verdad enlazados. Con perillas `auto` esto sería imprescindible; con las perillas fijas
109# meson ya habría fallado, así que acá es la segunda red — y la que detectaría que alguien vuelva a
110# poner `auto` sin darse cuenta.
111install = '''
112set -e
113DESTDIR=/out meson install -C output
114[ -x /out/usr/bin/swayimg ] || { echo "swayimg: no quedó el binario — NO sello" >&2; exit 1; }
115# ⚠⚠ **EL GUARDIÁN SE COMPRUEBA POR SÍMBOLO DEFINIDO, NO POR `NEEDED` — y me costó una vuelta.**
116# Mi versión anterior exigía `libwayland-client`, `libxkbcommon` y `libdrm` en `NEEDED`, y rechazó un
117# build **correcto**: con `--prefer-static` el corpus entrega estáticas y el binario sale
118# autosuficiente. Medido sobre el artefacto real:
119#
120# readelf -d swayimg | grep NEEDED ⇒ libc.so ← y NADA MÁS
121# los once símbolos de abajo ⇒ todos DEFINIDOS
122#
123# O sea un visor de imágenes con **una sola** dependencia dinámica. Eso además hace que declararlo
124# en un perfil no cueste ningún proveedor compartido.
125#
126# ⇒ La regla, que ya pagué cinco veces hoy en recetas distintas: **un `NEEDED` no prueba que la
127# función esté, y su ausencia no prueba que falte.** Lo que prueba la capacidad es el símbolo
128# DEFINIDO. Y cuando el artefacto cambia de forma (compartido → estático), el guardián tiene que
129# cambiar con él o se convierte en un rechazo de builds buenos.
130definido() {
131 readelf -sW "$1" 2>/dev/null | awk -v s="$2" '$8==s && $7!="UND" {f=1} END{exit !f}'
132}
133falta=""
134for par in "wl_display_connect:wayland" "xkb_context_new:xkbcommon" "drmModeGetResources:drm (modo consola)" \
135 "png_create_read_struct:png" "jpeg_read_header:jpeg" "WebPGetInfo:webp" \
136 "TIFFOpen:tiff" "DGifOpen:gif" "FcInit:fontconfig" "FT_Init_FreeType:freetype" \
137 "luaJIT_setmode:luajit"; do
138 sim=${par%%:*}; que=${par##*:}
139 definido /out/usr/bin/swayimg "$sim" || falta="$falta $que($sim)"
140done
141if [ -n "$falta" ]; then
142 echo "swayimg: faltan capacidades SIN NINGÚN ERROR de build:$falta" >&2
143 echo " — con las perillas en 'auto' meson las habría saltado en silencio; están fijas justo por esto" >&2
144 exit 1
145fi
146# exiv2 entra estática (ver su receta: el cruce de C++ con una .so segfaultearía), así que se
147# comprueba su símbolo y no un NEEDED. Sin esto, el EXIF no se leería y las fotos verticales
148# saldrían tumbadas — sin error.
149readelf -sW /out/usr/bin/swayimg 2>/dev/null | grep -q 'Exiv2.*ImageFactory' || { echo "swayimg: no hay rastro de Exiv2::ImageFactory en el binario — el EXIF no se leería y las fotos verticales saldrían tumbadas" >&2; exit 1; }
150n=$(readelf -d /out/usr/bin/swayimg 2>/dev/null | grep -c NEEDED)
151echo "swayimg: binario autosuficiente ($n NEEDED) · wayland + drm + png jpeg webp tiff gif + exif"
152'''
153
154[deps]
155build = ["meson", "samurai", "pkgconf", "wayland", "wayland-protocols", "libxkbcommon",
156 "fontconfig", "freetype", "libpng", "libjpeg-turbo", "libwebp", "libtiff",
157 "giflib", "exiv2", "libdrm", "luajit", "expat", "zlib", "brotli", "binutils", "python3"]