visor de imágenes: la distro ya puede abrir un JPEG
El censo marcaba «visores de imagen» 5 de 5 ausente. Los tres candidatos obvios
se descartaron por MEDICIÓN: nsxiv y feh son Xlib (muro en Wayland-only), e imv
—el recomendado para Wayland— pide egl/gl/opengl/glu, y este corpus no publica
libGL.so ni gl.pc (comprobado: el mismo muro que kitty). swayimg no menciona GL
ni una vez.
Resultado medido: binario AUTOSUFICIENTE, un solo NEEDED (libc.so). wayland,
xkb, drm, png, jpeg, webp, tiff, gif, fontconfig, freetype y lua entran
estáticos, así que declararlo no arrastra ningún proveedor compartido. 70 MB, de
los cuales el 85 % es .debug_* ⇒ ~10 MB desnudado.
exiv2 entra porque sin EXIF una cámara de móvil no rota los píxeles: anota la
orientación en una etiqueta, y un visor que no la lee muestra TODAS las fotos
verticales tumbadas, sin error y sin remedio. Cero deps nuevas.
⚠ CUATRO COSAS QUE AFIRMÉ Y ERAN FALSAS, corregidas acá:
1. Dije que `find_package(inih)` sin REQUIRED era «opcional de verdad». Su
Findinih.cmake hace message(FATAL_ERROR) por su cuenta. Leí la LLAMADA y no
el MÓDULO — la misma trampa que el repo documenta para find_library.
2. Dije que la exiv2 COMPARTIDA era segura «porque swayimg es un programa en C».
swayimg 5.6 es C++, y el cruce está en imageformat.cpp:124-150: un
std::unique_ptr creado en la .so y DESTRUIDO en swayimg, más una excepción
lanzada en una y capturada en la otra. Eso libera con el operator delete de un
módulo lo que asignó el new del otro y cruza dos copias estáticas de
libc++abi — la figura que segfaulteó libime_pinyindict. Y swayimg NO se puede
probar en el build (necesita display), así que «sella» no diría nada. Ahora
exiv2 es estática: un solo runtime de C++ en el proceso.
3. Dije que los once `undefined symbol: XML_*` eran la prueba de que exiv2 había
sellado roto. NO LO ERAN: expat entra en libexiv2 con visibilidad HIDDEN/LOCAL
—correcto, no exporta su API— y los símbolos están definidos. Los once venían
de libfontconfig.a, que tiene exactamente esos 11 sin definir porque su .pc
declara Requires.private: expat y meson usaba pkg-config en modo no estático.
La cura es --prefer-static, el mismo patrón que cairo y appstream. El arreglo
de exiv2 era correcto por su propio mérito (tenía un NEEDED colgante al lab,
medido), pero la evidencia que cité apuntaba a otro sitio.
4. Dije que declarar swayimg en `cli` «costaría casi nada». Son 70 MB. No lo
declaro ahí: el coste queda medido y escrito, y la decisión es del operador.
⚠ Y EL GUARDIÁN DE ESTA CAMPAÑA FALLÓ CINCO VECES, de las dos formas opuestas.
La regla que sale de eso, escrita en las dos recetas: un NEEDED no prueba que la
función esté, y su ausencia no prueba que falte. Lo que prueba la capacidad es
el símbolo DEFINIDO (sección != UND). Y cuando el artefacto cambia de forma
—compartido → estático— el guardián tiene que cambiar con él, o se convierte en
un rechazo de builds buenos:
· con exiv2 compartida pedía de MENOS y pasó un NEEDED colgante
· con exiv2 estática pedía de MÁS: exigía XML_Parse dentro de la .a, y una .a
NO contiene a sus deps. El contrato de una estática es lo que su .pc le dice
al consumidor que enlace ⇒ ahora se comprueba Requires.private
· en swayimg exigía libwayland/libxkbcommon/libdrm en NEEDED y rechazó un
build correcto, porque --prefer-static los mete dentro
Y el falso verde de vigia-sonames.py: invocado como `STORE=/store …` caía a su
default <repo>/store, que está VACÍO en un clon, y reportaba los DIEZ perfiles
con «0 sonames provistos · 0 sin proveedor» — que se lee como limpio. Ahora
acepta HAMMER_STORE/TAKANA_STORE/STORE y ABORTA si el store no tiene artefactos.
Con la variable correcta: 2192 sonames en escritorio-kde, 0 sin proveedor en los
diez perfiles.
Semantic delta
No definition changed: this change is text, documentation or data.
3 files · +343 −102
- docs/state/targets.toml +170 −0
- recipes/exiv2.toml +51 −33
- recipes/swayimg.toml +122 −69
diff --git a/docs/state/targets.toml b/docs/state/targets.toml
index 3e9e19b2..4f9de918 100644
--- a/docs/state/targets.toml
+++ b/docs/state/targets.toml
@@ -662,6 +662,40 @@ paquetes = [
# máquina. No se declara acá por simetría —se sigue dónde estaba `espeak-ng`— pero es una decisión
# pendiente y no un olvido.
"speech-dispatcher", "dotconf", "brltty", "liblouis",
+ # ── Y SE PUEDE ABRIR UNA IMAGEN (2026-10-20) ────────────────────────────────────────────────
+ # `censo-distro.py` marcaba «visores de imagen» **5 de 5 ausente**: la distro no tenía NINGUNA
+ # forma de abrir un JPEG. Los tres candidatos obvios se descartaron por MEDICIÓN, no por fama:
+ # `nsxiv`, `feh` son Xlib, y esta distro es Wayland-only ⇒ muro
+ # `imv` el recomendado para Wayland, y **no sirve acá**: pide `egl`, `gl`, `opengl`,
+ # `glu` y `wayland-egl`, y este corpus no publica `libGL.so` ni `gl.pc`
+ # (comprobado) — el mismo muro que bloquea a `kitty`
+ # `swayimg` **cero menciones de GL** en su `meson.build`. Pinta por software
+ #
+ # `swayimg` png, jpeg, webp, tiff y gif, **cada formato con su perilla FIJA**: sus opciones son
+ # `feature` con default `auto`, y una dep ausente se saltaría EN SILENCIO dejando un
+ # visor que no abre PNG y no dice por qué
+ # `exiv2` la rotación EXIF. Una cámara de móvil no rota los píxeles: anota la orientación en
+ # una etiqueta. Sin esto **todas las fotos verticales salen tumbadas**, sin error y
+ # sin remedio. ⚠ NO se declara acá: entra ESTÁTICA dentro del binario (su `.so`
+ # habría cruzado objetos de C++ entre módulos, que es lo que segfaulteó a
+ # `libime_pinyindict`)
+ #
+ # ⚠ PESO: 70 MB, y **el 85 % es `.debug_*`** (59 de 69 MB, sumado con readelf) ⇒ ~10 MB
+ # desnudado. La norma del corpus; su sitio es el SDD 23.
+ #
+ # ✅ El binario sale **autosuficiente: un solo `NEEDED`, `libc.so`** (medido). Todo lo demás
+ # —wayland, xkb, drm, png, jpeg, webp, tiff, gif, fontconfig, freetype, lua— entra estático, así
+ # que declararlo no arrastra ningún proveedor compartido.
+ #
+ # ⚠ QUEDA AFUERA Y SE DICE: `svg=disabled`, porque `librsvg` sólo existe en `incoming-gnome`
+ # enredada con su pila de introspección (promoverla cuesta 35 recetas, medido). **No abre SVG.**
+ # Y `heif/avif/jxl/jp2/exr/raw` tampoco: esas bibliotecas no están en el corpus.
+ #
+ # ⚠ Y UNA DECISIÓN QUE NO TOMO ACÁ: `swayimg` se construyó con `drm=enabled`, o sea que puede
+ # mostrar una imagen **desde una consola TTY, sin compositor**. Eso es exactamente lo que querría
+ # el perfil `cli`, que hoy no lleva visor. No se declara ahí porque son 70 MB en una imagen que no
+ # me pidieron cambiar — pero el coste está medido y la capacidad existe.
+ "swayimg",
"fontconfig-shared", # /etc/fonts/fonts.conf y el soname que enlaza el riel
"freetype-shared", # libfontconfig.so.1 pide libfreetype.so.6: sin ella el riel muere al cargar
"libpng-shared", # y freetype pide libpng16.so.16 — la cadena entera entro por querer letras
@@ -895,6 +929,40 @@ paquetes = [
# máquina. No se declara acá por simetría —se sigue dónde estaba `espeak-ng`— pero es una decisión
# pendiente y no un olvido.
"speech-dispatcher", "dotconf", "brltty", "liblouis",
+ # ── Y SE PUEDE ABRIR UNA IMAGEN (2026-10-20) ────────────────────────────────────────────────
+ # `censo-distro.py` marcaba «visores de imagen» **5 de 5 ausente**: la distro no tenía NINGUNA
+ # forma de abrir un JPEG. Los tres candidatos obvios se descartaron por MEDICIÓN, no por fama:
+ # `nsxiv`, `feh` son Xlib, y esta distro es Wayland-only ⇒ muro
+ # `imv` el recomendado para Wayland, y **no sirve acá**: pide `egl`, `gl`, `opengl`,
+ # `glu` y `wayland-egl`, y este corpus no publica `libGL.so` ni `gl.pc`
+ # (comprobado) — el mismo muro que bloquea a `kitty`
+ # `swayimg` **cero menciones de GL** en su `meson.build`. Pinta por software
+ #
+ # `swayimg` png, jpeg, webp, tiff y gif, **cada formato con su perilla FIJA**: sus opciones son
+ # `feature` con default `auto`, y una dep ausente se saltaría EN SILENCIO dejando un
+ # visor que no abre PNG y no dice por qué
+ # `exiv2` la rotación EXIF. Una cámara de móvil no rota los píxeles: anota la orientación en
+ # una etiqueta. Sin esto **todas las fotos verticales salen tumbadas**, sin error y
+ # sin remedio. ⚠ NO se declara acá: entra ESTÁTICA dentro del binario (su `.so`
+ # habría cruzado objetos de C++ entre módulos, que es lo que segfaulteó a
+ # `libime_pinyindict`)
+ #
+ # ⚠ PESO: 70 MB, y **el 85 % es `.debug_*`** (59 de 69 MB, sumado con readelf) ⇒ ~10 MB
+ # desnudado. La norma del corpus; su sitio es el SDD 23.
+ #
+ # ✅ El binario sale **autosuficiente: un solo `NEEDED`, `libc.so`** (medido). Todo lo demás
+ # —wayland, xkb, drm, png, jpeg, webp, tiff, gif, fontconfig, freetype, lua— entra estático, así
+ # que declararlo no arrastra ningún proveedor compartido.
+ #
+ # ⚠ QUEDA AFUERA Y SE DICE: `svg=disabled`, porque `librsvg` sólo existe en `incoming-gnome`
+ # enredada con su pila de introspección (promoverla cuesta 35 recetas, medido). **No abre SVG.**
+ # Y `heif/avif/jxl/jp2/exr/raw` tampoco: esas bibliotecas no están en el corpus.
+ #
+ # ⚠ Y UNA DECISIÓN QUE NO TOMO ACÁ: `swayimg` se construyó con `drm=enabled`, o sea que puede
+ # mostrar una imagen **desde una consola TTY, sin compositor**. Eso es exactamente lo que querría
+ # el perfil `cli`, que hoy no lleva visor. No se declara ahí porque son 70 MB en una imagen que no
+ # me pidieron cambiar — pero el coste está medido y la capacidad existe.
+ "swayimg",
# `dejavu-fonts-nerd` es la MISMA DejaVu Sans Mono parcheada con Nerd Fonts (~10.000 glifos de
# iconos: Powerline, Font Awesome, Devicons…) que usan starship, lsd, eza, neovim y las
# statuslines; sin ellos dibujan cuadraditos. Se AÑADE, no reemplaza: la licencia de Bitstream
@@ -1638,6 +1706,40 @@ paquetes = [
# máquina. No se declara acá por simetría —se sigue dónde estaba `espeak-ng`— pero es una decisión
# pendiente y no un olvido.
"speech-dispatcher", "dotconf", "brltty", "liblouis",
+ # ── Y SE PUEDE ABRIR UNA IMAGEN (2026-10-20) ────────────────────────────────────────────────
+ # `censo-distro.py` marcaba «visores de imagen» **5 de 5 ausente**: la distro no tenía NINGUNA
+ # forma de abrir un JPEG. Los tres candidatos obvios se descartaron por MEDICIÓN, no por fama:
+ # `nsxiv`, `feh` son Xlib, y esta distro es Wayland-only ⇒ muro
+ # `imv` el recomendado para Wayland, y **no sirve acá**: pide `egl`, `gl`, `opengl`,
+ # `glu` y `wayland-egl`, y este corpus no publica `libGL.so` ni `gl.pc`
+ # (comprobado) — el mismo muro que bloquea a `kitty`
+ # `swayimg` **cero menciones de GL** en su `meson.build`. Pinta por software
+ #
+ # `swayimg` png, jpeg, webp, tiff y gif, **cada formato con su perilla FIJA**: sus opciones son
+ # `feature` con default `auto`, y una dep ausente se saltaría EN SILENCIO dejando un
+ # visor que no abre PNG y no dice por qué
+ # `exiv2` la rotación EXIF. Una cámara de móvil no rota los píxeles: anota la orientación en
+ # una etiqueta. Sin esto **todas las fotos verticales salen tumbadas**, sin error y
+ # sin remedio. ⚠ NO se declara acá: entra ESTÁTICA dentro del binario (su `.so`
+ # habría cruzado objetos de C++ entre módulos, que es lo que segfaulteó a
+ # `libime_pinyindict`)
+ #
+ # ⚠ PESO: 70 MB, y **el 85 % es `.debug_*`** (59 de 69 MB, sumado con readelf) ⇒ ~10 MB
+ # desnudado. La norma del corpus; su sitio es el SDD 23.
+ #
+ # ✅ El binario sale **autosuficiente: un solo `NEEDED`, `libc.so`** (medido). Todo lo demás
+ # —wayland, xkb, drm, png, jpeg, webp, tiff, gif, fontconfig, freetype, lua— entra estático, así
+ # que declararlo no arrastra ningún proveedor compartido.
+ #
+ # ⚠ QUEDA AFUERA Y SE DICE: `svg=disabled`, porque `librsvg` sólo existe en `incoming-gnome`
+ # enredada con su pila de introspección (promoverla cuesta 35 recetas, medido). **No abre SVG.**
+ # Y `heif/avif/jxl/jp2/exr/raw` tampoco: esas bibliotecas no están en el corpus.
+ #
+ # ⚠ Y UNA DECISIÓN QUE NO TOMO ACÁ: `swayimg` se construyó con `drm=enabled`, o sea que puede
+ # mostrar una imagen **desde una consola TTY, sin compositor**. Eso es exactamente lo que querría
+ # el perfil `cli`, que hoy no lleva visor. No se declara ahí porque son 70 MB en una imagen que no
+ # me pidieron cambiar — pero el coste está medido y la capacidad existe.
+ "swayimg",
# `dejavu-fonts-nerd` es la MISMA DejaVu Sans Mono parcheada con Nerd Fonts (~10.000 glifos de
# iconos: Powerline, Font Awesome, Devicons…) que usan starship, lsd, eza, neovim y las
# statuslines; sin ellos dibujan cuadraditos. Se AÑADE, no reemplaza: la licencia de Bitstream
@@ -2021,6 +2123,40 @@ paquetes = [
# máquina. No se declara acá por simetría —se sigue dónde estaba `espeak-ng`— pero es una decisión
# pendiente y no un olvido.
"speech-dispatcher", "dotconf", "brltty", "liblouis",
+ # ── Y SE PUEDE ABRIR UNA IMAGEN (2026-10-20) ────────────────────────────────────────────────
+ # `censo-distro.py` marcaba «visores de imagen» **5 de 5 ausente**: la distro no tenía NINGUNA
+ # forma de abrir un JPEG. Los tres candidatos obvios se descartaron por MEDICIÓN, no por fama:
+ # `nsxiv`, `feh` son Xlib, y esta distro es Wayland-only ⇒ muro
+ # `imv` el recomendado para Wayland, y **no sirve acá**: pide `egl`, `gl`, `opengl`,
+ # `glu` y `wayland-egl`, y este corpus no publica `libGL.so` ni `gl.pc`
+ # (comprobado) — el mismo muro que bloquea a `kitty`
+ # `swayimg` **cero menciones de GL** en su `meson.build`. Pinta por software
+ #
+ # `swayimg` png, jpeg, webp, tiff y gif, **cada formato con su perilla FIJA**: sus opciones son
+ # `feature` con default `auto`, y una dep ausente se saltaría EN SILENCIO dejando un
+ # visor que no abre PNG y no dice por qué
+ # `exiv2` la rotación EXIF. Una cámara de móvil no rota los píxeles: anota la orientación en
+ # una etiqueta. Sin esto **todas las fotos verticales salen tumbadas**, sin error y
+ # sin remedio. ⚠ NO se declara acá: entra ESTÁTICA dentro del binario (su `.so`
+ # habría cruzado objetos de C++ entre módulos, que es lo que segfaulteó a
+ # `libime_pinyindict`)
+ #
+ # ⚠ PESO: 70 MB, y **el 85 % es `.debug_*`** (59 de 69 MB, sumado con readelf) ⇒ ~10 MB
+ # desnudado. La norma del corpus; su sitio es el SDD 23.
+ #
+ # ✅ El binario sale **autosuficiente: un solo `NEEDED`, `libc.so`** (medido). Todo lo demás
+ # —wayland, xkb, drm, png, jpeg, webp, tiff, gif, fontconfig, freetype, lua— entra estático, así
+ # que declararlo no arrastra ningún proveedor compartido.
+ #
+ # ⚠ QUEDA AFUERA Y SE DICE: `svg=disabled`, porque `librsvg` sólo existe en `incoming-gnome`
+ # enredada con su pila de introspección (promoverla cuesta 35 recetas, medido). **No abre SVG.**
+ # Y `heif/avif/jxl/jp2/exr/raw` tampoco: esas bibliotecas no están en el corpus.
+ #
+ # ⚠ Y UNA DECISIÓN QUE NO TOMO ACÁ: `swayimg` se construyó con `drm=enabled`, o sea que puede
+ # mostrar una imagen **desde una consola TTY, sin compositor**. Eso es exactamente lo que querría
+ # el perfil `cli`, que hoy no lleva visor. No se declara ahí porque son 70 MB en una imagen que no
+ # me pidieron cambiar — pero el coste está medido y la capacidad existe.
+ "swayimg",
# ⚠ «sin puntero» lo decía este comentario desde que se escribió y NO era cierto: `cosmic-icons`
# instala iconos de aplicación, no cursores, así que este perfil llegó a 43/43 con el puntero
# INVISIBLE. Lo cazó `vigia-imagen.py` el 2026-09-04. Los cursores son su propia raíz.
@@ -2423,6 +2559,40 @@ paquetes = [
# máquina. No se declara acá por simetría —se sigue dónde estaba `espeak-ng`— pero es una decisión
# pendiente y no un olvido.
"speech-dispatcher", "dotconf", "brltty", "liblouis",
+ # ── Y SE PUEDE ABRIR UNA IMAGEN (2026-10-20) ────────────────────────────────────────────────
+ # `censo-distro.py` marcaba «visores de imagen» **5 de 5 ausente**: la distro no tenía NINGUNA
+ # forma de abrir un JPEG. Los tres candidatos obvios se descartaron por MEDICIÓN, no por fama:
+ # `nsxiv`, `feh` son Xlib, y esta distro es Wayland-only ⇒ muro
+ # `imv` el recomendado para Wayland, y **no sirve acá**: pide `egl`, `gl`, `opengl`,
+ # `glu` y `wayland-egl`, y este corpus no publica `libGL.so` ni `gl.pc`
+ # (comprobado) — el mismo muro que bloquea a `kitty`
+ # `swayimg` **cero menciones de GL** en su `meson.build`. Pinta por software
+ #
+ # `swayimg` png, jpeg, webp, tiff y gif, **cada formato con su perilla FIJA**: sus opciones son
+ # `feature` con default `auto`, y una dep ausente se saltaría EN SILENCIO dejando un
+ # visor que no abre PNG y no dice por qué
+ # `exiv2` la rotación EXIF. Una cámara de móvil no rota los píxeles: anota la orientación en
+ # una etiqueta. Sin esto **todas las fotos verticales salen tumbadas**, sin error y
+ # sin remedio. ⚠ NO se declara acá: entra ESTÁTICA dentro del binario (su `.so`
+ # habría cruzado objetos de C++ entre módulos, que es lo que segfaulteó a
+ # `libime_pinyindict`)
+ #
+ # ⚠ PESO: 70 MB, y **el 85 % es `.debug_*`** (59 de 69 MB, sumado con readelf) ⇒ ~10 MB
+ # desnudado. La norma del corpus; su sitio es el SDD 23.
+ #
+ # ✅ El binario sale **autosuficiente: un solo `NEEDED`, `libc.so`** (medido). Todo lo demás
+ # —wayland, xkb, drm, png, jpeg, webp, tiff, gif, fontconfig, freetype, lua— entra estático, así
+ # que declararlo no arrastra ningún proveedor compartido.
+ #
+ # ⚠ QUEDA AFUERA Y SE DICE: `svg=disabled`, porque `librsvg` sólo existe en `incoming-gnome`
+ # enredada con su pila de introspección (promoverla cuesta 35 recetas, medido). **No abre SVG.**
+ # Y `heif/avif/jxl/jp2/exr/raw` tampoco: esas bibliotecas no están en el corpus.
+ #
+ # ⚠ Y UNA DECISIÓN QUE NO TOMO ACÁ: `swayimg` se construyó con `drm=enabled`, o sea que puede
+ # mostrar una imagen **desde una consola TTY, sin compositor**. Eso es exactamente lo que querría
+ # el perfil `cli`, que hoy no lleva visor. No se declara ahí porque son 70 MB en una imagen que no
+ # me pidieron cambiar — pero el coste está medido y la capacidad existe.
+ "swayimg",
# `dejavu-fonts-nerd` es la MISMA DejaVu Sans Mono parcheada con Nerd Fonts (~10.000 glifos de
# iconos: Powerline, Font Awesome, Devicons…) que usan starship, lsd, eza, neovim y las
# statuslines; sin ellos dibujan cuadraditos. Se AÑADE, no reemplaza: la licencia de Bitstream
diff --git a/recipes/exiv2.toml b/recipes/exiv2.toml
index 27e3b293..be8d6b04 100644
--- a/recipes/exiv2.toml
+++ b/recipes/exiv2.toml
@@ -72,10 +72,25 @@
# `appstream` y `brltty` — **cinco recetas con el mismo parche** ya empieza a parecer un caso para
# decidir en el lab y no receta por receta, pero eso es su propia unidad de trabajo.
#
-# ⚠ `BUILD_SHARED_LIBS=ON` y es SEGURO acá, a diferencia de `libime`: `swayimg` es un programa en C
-# que enlaza `libexiv2.so`, así que el runtime de C++ vive ENTERO dentro de la biblioteca y ningún
-# objeto de C++ cruza el límite de módulo. El problema de las cuatro copias de libc++ aparece cuando
-# un `std::` creado en un módulo se usa en otro — acá no pasa.
+# ══ ⚠ `BUILD_SHARED_LIBS=OFF`, Y ME CORRIJO: ESCRIBÍ LO CONTRARIO SOBRE UNA PREMISA FALSA ══════
+# Puse `ON` argumentando que era seguro «porque `swayimg` es un programa en C, así que el runtime de
+# C++ vive entero dentro de la biblioteca y ningún objeto de C++ cruza el límite». **swayimg 5.6 es
+# C++**, no C (compila `.cpp`), así que la premisa era falsa. Y el cruce no es teórico — está en
+# `src/imageformat.cpp:124-150`:
+#
+# Exiv2::Image::UniquePtr exiv2 = Exiv2::ImageFactory::open(...); // creado en la .so…
+# } // …y DESTRUIDO en swayimg
+# catch (Exiv2::Error&) { // lanzada en la .so, capturada acá
+#
+# Un `std::unique_ptr` construido en un módulo y destruido en otro libera con el `operator delete`
+# del consumidor memoria que asignó el `new` de la biblioteca, y la excepción cruza dos copias
+# ESTÁTICAS de libc++abi. Es la misma figura que segfaulteó `libime_pinyindict`
+# ([[cuatro-libcxx-en-un-proceso]]), con el agravante de que **swayimg no se puede probar en el
+# build** —necesita un display Wayland—, así que «sella» no diría nada.
+#
+# ⇒ Estática: el código de exiv2 entra en el binario de swayimg y hay **un solo** runtime de C++ en
+# el proceso. `CMAKE_POSITION_INDEPENDENT_CODE=ON` para que la `.a` sirva también si algún día la
+# necesita una compartida.
name = "exiv2"
version = "0.28.9"
license = "GPL-2.0-or-later"
@@ -105,7 +120,7 @@ cmake -B build -G Ninja -Wno-dev \
-DCMAKE_INSTALL_LIBDIR=lib \
-DPKG_CONFIG_ARGN=--static \
-DCMAKE_C_FLAGS=-Wno-error=date-time -DCMAKE_CXX_FLAGS=-Wno-error=date-time \
- -DBUILD_SHARED_LIBS=ON \
+ -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DEXIV2_ENABLE_XMP=ON -DEXIV2_ENABLE_BROTLI=ON \
-DEXIV2_ENABLE_WEBREADY=OFF -DEXIV2_ENABLE_NLS=OFF \
-DEXIV2_ENABLE_BMFF=ON \
@@ -122,8 +137,10 @@ compile = "cmake --build build"
install = '''
set -e
DESTDIR=/out cmake --install build
-so=$(find /out/usr/lib -name 'libexiv2.so*' -type f 2>/dev/null | head -1)
-[ -n "$so" ] || { echo "exiv2: no quedó libexiv2.so — swayimg la enlaza" >&2; find /out -name 'libexiv2*' >&2; exit 1; }
+so=$(find /out/usr/lib -name 'libexiv2.a' 2>/dev/null | head -1)
+[ -n "$so" ] || { echo "exiv2: no quedó libexiv2.a — NO sello" >&2; find /out -name 'libexiv2*' >&2; exit 1; }
+# PIC, que es lo que permitiría meterla en una compartida el día que haga falta.
+readelf -r "$so" 2>/dev/null | grep -qE 'R_X86_64_(GOTPCREL|REX_GOTP|PLT32)' || { echo "exiv2: libexiv2.a no parece PIC" >&2; exit 1; }
[ -f /out/usr/include/exiv2/exiv2.hpp ] || { echo "exiv2: falta include/exiv2/exiv2.hpp" >&2; exit 1; }
pc=$(find /out/usr/lib -name 'exiv2.pc' 2>/dev/null | head -1)
[ -n "$pc" ] || { echo "exiv2: falta exiv2.pc — swayimg la busca por pkg-config (dependency('exiv2'))" >&2; exit 1; }
@@ -132,35 +149,36 @@ pc=$(find /out/usr/lib -name 'exiv2.pc' 2>/dev/null | head -1)
# XMP necesita expat y brotli necesita libbrotlidec: si las perillas no se materializaron, no
# aparecen en NEEDED. `.a` del corpus no declararían NEEDED, así que se admiten las dos formas:
# o el soname en NEEDED, o el símbolo exportado si entró estático.
-# ⚠ **ESTE CONTROL ESTUVO MAL Y DEJÓ PASAR EL ARTEFACTO ROTO.** Mi versión anterior aceptaba
-# «`libexpat` aparece en NEEDED **o** el símbolo `XML_Parse` existe en la tabla», y las dos ramas
-# daban verde sobre el fallo: el NEEDED estaba ahí **y era colgante**, y `readelf -s | grep XML_Parse`
-# casa igual con una entrada **UND** (sin definir) que con una definida.
-#
-# ⇒ Ahora se exige que los símbolos estén **DEFINIDOS** —columna de sección distinta de `UND`— y
-# que NO quede ningún NEEDED hacia una biblioteca que el corpus sólo publica estática. Un símbolo
-# presente no es un símbolo resuelto.
-definido() {
- readelf -sW "$1" 2>/dev/null | awk -v s="$2" '$8==s && $7!="UND" {found=1} END{exit !found}'
-}
-definido "$so" XML_Parse || {
- echo "exiv2: XML_Parse no está DEFINIDO en la compartida — expat no entró (o entró como referencia colgante) y el XMP no funcionaría" >&2
- readelf -sW "$so" 2>/dev/null | awk '/XML_Parse/{print " "$7, $8}' >&2
- exit 1
-}
-definido "$so" BrotliDecoderDecompress || definido "$so" BrotliDecoderCreateInstance || {
- echo "exiv2: ningún símbolo BrotliDecoder* DEFINIDO — los metadatos comprimidos no se leerían" >&2
- exit 1
-}
-# Y el control que faltaba: NINGÚN NEEDED hacia lo que el corpus sólo tiene estático. Si aparece,
-# salió del LAB y la imagen no lo tendrá.
-for mal in libexpat libz.so libbrotli; do
- readelf -d "$so" 2>/dev/null | grep NEEDED | grep -q "$mal" && {
- echo "exiv2: NEEDED hacia $mal — el corpus sólo publica esa dep ESTÁTICA, así que esa .so salió del lab y no viajaría en ninguna imagen" >&2
- readelf -d "$so" 2>/dev/null | grep NEEDED >&2
+# ⚠⚠ **ESTE CONTROL FALLÓ DOS VECES, DE LAS DOS FORMAS OPUESTAS. Vale anotar las dos.**
+#
+# 1. Con la biblioteca COMPARTIDA aceptaba «`libexpat` en NEEDED **o** el símbolo `XML_Parse`
+# existe», y las dos ramas daban verde sobre un fallo real: el NEEDED estaba ahí **y era
+# colgante** (apuntaba a la `libexpat.so` del LAB, que no viaja), y
+# `readelf -s | grep XML_Parse` casa igual con una entrada **UND** que con una definida.
+# *Un símbolo presente no es un símbolo resuelto.*
+#
+# 2. Al pasar a ESTÁTICA lo endurecí exigiendo que `XML_Parse` estuviera **definido dentro** de la
+# biblioteca… y eso rechaza un build correcto: **una `.a` no contiene a sus deps.** Es una
+# colección de objetos propios; quien enlaza expat es el CONSUMIDOR. El guardián pedía algo que
+# no debe estar.
+#
+# ⇒ El contrato de una estática no son sus símbolos ajenos: es **lo que su `.pc` le dice al
+# consumidor que tiene que enlazar**. Si `Requires.private` no nombra expat/brotli/zlib, el
+# consumidor no lo sabrá, y el fallo saldrá en ÉL con once `undefined symbol: XML_*` que no mencionan
+# a exiv2 — pasó exactamente así con `libfontconfig.a` y costó dos vueltas de diagnóstico.
+#
+# Y la prueba de que las perillas se materializaron pasa a ser la CLI: se enlaza en este mismo build
+# con expat y brotli de verdad, así que si no entraran, no habría binario que arrancara.
+for req in expat brotli zlib; do
+ grep -E '^Requires\.private' "$pc" | grep -q "$req" || {
+ echo "exiv2: exiv2.pc no declara '$req' en Requires.private — el consumidor no sabría que debe enlazarlo, y su fallo serían símbolos sin resolver que NO mencionan a exiv2" >&2
+ grep -E '^Requires|^Libs' "$pc" >&2
exit 1
}
done
+# Y los símbolos PROPIOS de exiv2 sí tienen que estar en la `.a`: es lo único que ella aporta.
+readelf -sW "$so" 2>/dev/null | grep -q 'ImageFactory' || { echo "exiv2: libexiv2.a no trae ningún símbolo de Exiv2::ImageFactory — es la API que usa el consumidor" >&2; exit 1; }
+
# Y que la CLI ARRANQUE: es C++ y una ruta mal resuelta la deja muerta aunque el fichero exista.
# Ejecución y truncado SEPARADOS — el estado de una tubería es el del último comando, y eso ya me
# selló un fallo hoy (ver `recipes/automake.toml`).
diff --git a/recipes/swayimg.toml b/recipes/swayimg.toml
index 2684390c..c91dc2e3 100644
--- a/recipes/swayimg.toml
+++ b/recipes/swayimg.toml
@@ -1,68 +1,59 @@
-# swayimg 4.7 — visor de imágenes Wayland-nativo, para las CUATRO imágenes.
+# swayimg 5.6 — el VISOR DE IMÁGENES. Cierra un hueco que el censo marcaba 5 de 5 ausente: la
+# distro no tenía NINGUNA forma de abrir un JPEG.
#
-# ══ POR QUÉ ESTA Y NO `imv`, QUE ERA LA QUE DECÍA EL PLAN ══════════════════════════════════════
-# `docs/plan-apps-usuario-final.md` proponía `imv` como paso 4 —«7 faltantes, todos cargadores de
-# formato opcionales, sin muros»—. Al ir a escribirla, la medición dijo otra cosa:
+# ══ POR QUÉ ESTE Y NO LOS POPULARES: SE DESCARTARON POR MEDICIÓN ═══════════════════════════════
+# `nsxiv` es un fork de sxiv, **Xlib**. Esta distro es Wayland-only ⇒ muro, no candidato
+# `feh` idem, X11
+# `imv` es el que todo el mundo recomienda para Wayland, y **no sirve acá**: sus
+# `dependency()` piden `egl`, `gl`, `opengl`, `glu` y `wayland-egl`, y este corpus **no
+# publica `libGL.so` ni `gl.pc`** (comprobado en el store; es el muro documentado de «sin
+# OpenGL de escritorio», el mismo que bloquea a `kitty`)
+# `swayimg` **cero menciones de GL** en todo su `meson.build` (medido). Pinta por software sobre
+# `wayland-client`, con fontconfig/freetype para el texto
#
-# imv/src/canvas.c hace `#include <GL/gl.h>` y dibuja con `glBegin`/`glOrtho`/`GL_TRIANGLE_FAN`,
-# o sea OpenGL de FUNCIÓN FIJA (perfil de compatibilidad). Su meson pide `dependency('gl')` y,
-# si falta, `dependency('opengl')` SIN `required:false` ⇒ configure muere.
+# ⇒ La lección de método: en este corpus, «el visor de imágenes estándar para Wayland» no es una
+# recomendación transferible — hay que mirar si pide GL antes de escribir la receta.
#
-# Y esta distro **no tiene ningún proveedor de OpenGL de escritorio**. Medido en los artefactos, no
-# supuesto: las TRES variantes de mesa (`mesa`, `mesa-swrast`, `mesa-llvmpipe`) van
-# `-Dglx=disabled -Dglvnd=false` ⇒ publican `libEGL.so.1` y `libGLESv2.so.2` y **ni `libGL.so*` ni
-# `gl.pc` ni `opengl.pc`**; no hay receta `libglvnd` en ninguna cola. La trampa fina es que mesa SÍ
-# instala `/usr/include/GL/gl.h` ⇒ una app así compila y muere recién al LIGAR.
-# El muro está anotado en el plan; darlo vuelta es cambiar mesa (radio 139) + autorar libglvnd, o
-# sea una decisión de distro, no un ticket de visor de imágenes.
+# ══ SUS DEPS OBLIGATORIAS SON CINCO, Y TODAS ESTABAN ═══════════════════════════════════════════
+# Leídas en su `meson.build`: `xkbcommon`, `fontconfig`, `freetype2`, `threads` y `wayland-client`
+# con `wayland-protocols >= 1.35` (tenemos 1.48). **Todo lo demás va detrás de una perilla**,
+# incluida `librsvg-2.0` — o sea que el bloqueo de GNOME no toca acá.
#
-# swayimg cubre exactamente el mismo caso de uso **sin GL**: rasteriza a un buffer y lo entrega por
-# `wl_shm`. Encaja con la distro en vez de pelearse con ella, y de yapa trae backend **DRM**, que
-# muestra imágenes en una TTY pelada sin compositor.
+# ⚠ Con una excepción que casi no vi: `lua = dependency(get_option('liblua'))` **no es
+# condicional** — es obligatoria, y el nombre del módulo pkg-config sale de la opción. Su default es
+# `luajit`, que no tenemos; nuestra `lua` 5.4.8 publica `lua.pc`, así que se pasa el nombre a mano.
#
-# ══ 5.5, DESPUÉS DE ESCRIBIR `luajit` ══════════════════════════════════════════════════════════
-# Entró primero como 4.7 —la última sin Lua— porque desde la 5.0 `dependency('luajit')` es
-# OBLIGATORIA y no había receta; la `lua5.2` del OSC de mpv no sirve, es otra ABI (LuaJIT es Lua 5.1
-# + FFI + JIT). Se escribió `luajit` el mismo día y esto subió a 5.5. Lo que se gana: el motor de
-# configuración pasó a ser Lua (`src/luaengine.cpp`), y con él los perfiles de teclas y el `.lua` de
-# ejemplo que se instala con `-Dluameta=true`.
-# Dos cambios de forma respecto de la 4.7: `compositor` ya NO pide `json-c` (la integración con sway
-# se rehizo sin JSON), y la man page viene PRE-GENERADA en `extra/swayimg.1` en vez de armarse con
-# scdoc ⇒ las dos deps se fueron de `[deps]`. `-Ddoc=false` porque ese target regenera markdown con
-# dos scripts de Python y lo que instala son `.md`, no páginas de manual.
+# ══ ⚠ TODAS LAS PERILLAS EXPLÍCITAS, Y ESO ES EL PUNTO DE ESTA RECETA ══════════════════════════
+# Sus opciones de formato son `feature` con default **`auto`**: una dep ausente se **salta en
+# silencio** y el build sale bien. Eso es exactamente la figura que este catálogo persigue —un visor
+# sellado que no abre PNG y no te dice por qué—. ⇒ cada formato se fija `enabled` o `disabled`:
#
-# ══ `-Dversion=5.5` NO ES COSMÉTICO ════════════════════════════════════════════════════════════
-# Su default es la cadena `0.0.0`, y meson.build:19-31 la interpreta como «averiguala vos»: corre
-# `git describe --tags --long --always --dirty` sobre el árbol. O sea que **la versión estampada
-# DENTRO del binario dependería del estado del checkout** (si hay `.git`, si trajo los tags, si
-# quedó sucio) y dos builds del mismo commit podrían dar bytes distintos. Misma familia que el
-# `-Dbuild-date` de mpv: la perilla que se busca en toda app nueva.
+# ENCENDIDOS (la dep está en el corpus, y si faltara el build DEBE fallar):
+# png jpeg webp tiff gif los formatos que cubren casi todo lo que alguien abre
+# exif `exiv2`, y NO es un adorno: una cámara de móvil no rota los
+# píxeles, anota la orientación en EXIF. Sin esto **todas las fotos
+# verticales salen tumbadas**, sin error y sin remedio
+# wayland compositor la ventana normal
+# drm ⚠ el modo sin compositor: ver una imagen **desde una consola TTY**.
+# En una distro que arranca a texto esto no es exótico, es el caso de
+# «mirá esta captura antes de levantar el escritorio»
#
-# ══ OPCIONES TODAS EXPLÍCITAS ══════════════════════════════════════════════════════════════════
-# Las doce de formato nacen `auto`, o sea que miran el sandbox y se prenden con lo que encuentren:
-# el artefacto pasaría a depender de qué otra cosa quedó montada en el lab. Se enumeran una por una.
-# ENCENDIDAS (la dep ya está en el corpus): jpeg, png, tiff, webp, gif, y `compositor` (json-c, es
-# la integración por IPC con sway).
-# APAGADAS por falta de receta: exr, heif, avif, jp2, jxl, sixel, raw, bash.
-# APAGADAS POR COLA — y son dos, no una: `svg` pide `librsvg-2.0`, que vive sólo en
-# `incoming-gnome`, y `exif` pide `exiv2`, que vive sólo en `incoming-kde`. Las dos EXISTEN en el
-# disco y ninguna es alcanzable desde el corpus: una receta resuelve sibling-first y después el
-# catálogo padre, nunca una cola hermana. Es el mismo hueco que dejó mudo a wf-recorder, y es la
-# razón por la que este visor no muestra metadatos EXIF.
-#
-# `-Dprefer_static=true` como mpv: fontconfig, freetype, libpng, libjpeg, libtiff, libwebp, expat y
-# json-c son `.a` en el corpus, y sin esta perilla meson resuelve los `.pc` sin `Libs.private` y el
-# link muere con símbolos de expat «en libfontconfig.a», culpando a fontconfig. `link=dynamic`
-# porque wayland, libxkbcommon, libdrm y zstd sí publican `.so`.
-#
-# Fuente por commit git (ADR 0006): `v5.5` es un tag LIVIANO ⇒ éste es su commit.
+# APAGADOS, con el motivo:
+# svg `librsvg-2.0` sólo existe en `incoming-gnome`, enredada con su pila
+# de introspección; promoverla cuesta 35 recetas (medido). **Lo que se
+# pierde es abrir SVG**, que es real y queda dicho
+# heif avif jxl jp2 exr raw los formatos modernos y de cámara: `libheif`, `libavif`, `libjxl`,
+# sixel `openjpeg`, `OpenEXR`, `libraw`, `libsixel` NO están en el corpus
+# video `ffmpeg` está, pero reproducir vídeo es trabajo de `mpv`, que ya
+# viaja. Un visor de imágenes no necesita arrastrar esa cadena
+# tests `gtest` no está en el corpus
name = "swayimg"
-version = "5.5"
+version = "5.6"
license = "MIT"
[source]
-repo = "https://github.com/artemsen/swayimg.git"
-commit = "682fecf358c0a2da1f98422b6a013dc822c74c5b"
+tarball = "https://github.com/artemsen/swayimg/archive/refs/tags/v5.6/swayimg-5.6.tar.gz"
+sha256 = "0f70cbc665217a747e8a098e1a881239e96df270930f47c262ab2ecff290e428"
[build]
compiler = "zig-cc"
@@ -71,20 +62,82 @@ link = "dynamic"
flags = []
[build.phases]
-configure = "PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release -Dprefer_static=true -Dversion=5.5 -Dwayland=enabled -Ddrm=enabled -Dcompositor=enabled -Djp2=disabled -Djpeg=enabled -Dpng=enabled -Dtiff=enabled -Dwebp=enabled -Dgif=enabled -Dexr=disabled -Dheif=disabled -Davif=disabled -Djxl=disabled -Dsvg=disabled -Dsixel=disabled -Draw=disabled -Dexif=disabled -Dbash=disabled -Dzsh=disabled -Ddesktop=true -Dman=true -Dlicense=true -Ddoc=false -Dluameta=true -Dtests=disabled"
-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"
+# `-Dversion=5.6`: su default es `0.0.0` y lo hornea en `--version`. Dejarlo así daría un binario
+# que miente sobre qué es — y además haría imposible saber qué versión corre en una imagen.
+configure = '''
+set -e
+# ⚠ **`--prefer-static` NO es una preferencia de tamaño: sin él el enlace NO CIERRA.**
+# El corpus es estático-primero, y `libfontconfig.a` referencia **11 símbolos `XML_*` sin definir**
+# (medido) porque su `.pc` declara `Requires.private: expat`. pkg-config sólo entrega las privadas
+# en modo estático; en meson eso es `--prefer-static`. Sin la bandera, lld cortó con los once:
+#
+# ld.lld: error: undefined symbol: XML_ParserCreate … (y 10 más)
+#
+# ⚠ Y esos once errores NO venían de `exiv2`, aunque al principio los atribuí ahí: expat entra en
+# `libexiv2` con visibilidad HIDDEN/LOCAL —correcto, no exporta la API de expat— y los símbolos
+# aparecen definidos. Venían de fontconfig desde el primer intento. Es la lección de
+# [[control-antes-que-precision]] por el lado del diagnóstico: el primer sospechoso plausible no es
+# el culpable, y la forma de saberlo es mirar QUIÉN tiene el símbolo sin definir.
+PKG_CONFIG_PATH=/usr/lib/pkgconfig meson setup output --prefix=/usr --buildtype=release \
+ --prefer-static \
+ -Dversion=5.6 \
+ -Dliblua=lua \
+ -Dpng=enabled -Djpeg=enabled -Dwebp=enabled -Dtiff=enabled -Dgif=enabled \
+ -Dexif=enabled \
+ -Dwayland=enabled -Dcompositor=enabled -Ddrm=enabled \
+ -Dsvg=disabled -Dheif=disabled -Davif=disabled -Djxl=disabled -Djp2=disabled \
+ -Dexr=disabled -Draw=disabled -Dsixel=disabled -Dvideo=disabled \
+ -Dtests=disabled
+'''
+compile = 'meson compile -C output'
+# El guardián no se conforma con que el binario exista: comprueba que los formatos que PEDIMOS
+# estén de verdad enlazados. Con perillas `auto` esto sería imprescindible; con las perillas fijas
+# meson ya habría fallado, así que acá es la segunda red — y la que detectaría que alguien vuelva a
+# poner `auto` sin darse cuenta.
+install = '''
+set -e
+DESTDIR=/out meson install -C output
+[ -x /out/usr/bin/swayimg ] || { echo "swayimg: no quedó el binario — NO sello" >&2; exit 1; }
+# ⚠⚠ **EL GUARDIÁN SE COMPRUEBA POR SÍMBOLO DEFINIDO, NO POR `NEEDED` — y me costó una vuelta.**
+# Mi versión anterior exigía `libwayland-client`, `libxkbcommon` y `libdrm` en `NEEDED`, y rechazó un
+# build **correcto**: con `--prefer-static` el corpus entrega estáticas y el binario sale
+# autosuficiente. Medido sobre el artefacto real:
+#
+# readelf -d swayimg | grep NEEDED ⇒ libc.so ← y NADA MÁS
+# los once símbolos de abajo ⇒ todos DEFINIDOS
+#
+# O sea un visor de imágenes con **una sola** dependencia dinámica. Eso además hace que declararlo
+# en un perfil no cueste ningún proveedor compartido.
+#
+# ⇒ La regla, que ya pagué cinco veces hoy en recetas distintas: **un `NEEDED` no prueba que la
+# función esté, y su ausencia no prueba que falte.** Lo que prueba la capacidad es el símbolo
+# DEFINIDO. Y cuando el artefacto cambia de forma (compartido → estático), el guardián tiene que
+# cambiar con él o se convierte en un rechazo de builds buenos.
+definido() {
+ readelf -sW "$1" 2>/dev/null | awk -v s="$2" '$8==s && $7!="UND" {f=1} END{exit !f}'
+}
+falta=""
+for par in "wl_display_connect:wayland" "xkb_context_new:xkbcommon" "drmModeGetResources:drm (modo consola)" \
+ "png_create_read_struct:png" "jpeg_read_header:jpeg" "WebPGetInfo:webp" \
+ "TIFFOpen:tiff" "DGifOpen:gif" "FcInit:fontconfig" "FT_Init_FreeType:freetype" \
+ "lua_newstate:lua"; do
+ sim=${par%%:*}; que=${par##*:}
+ definido /out/usr/bin/swayimg "$sim" || falta="$falta $que($sim)"
+done
+if [ -n "$falta" ]; then
+ echo "swayimg: faltan capacidades SIN NINGÚN ERROR de build:$falta" >&2
+ echo " — con las perillas en 'auto' meson las habría saltado en silencio; están fijas justo por esto" >&2
+ exit 1
+fi
+# exiv2 entra estática (ver su receta: el cruce de C++ con una .so segfaultearía), así que se
+# comprueba su símbolo y no un NEEDED. Sin esto, el EXIF no se leería y las fotos verticales
+# saldrían tumbadas — sin error.
+readelf -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; }
+n=$(readelf -d /out/usr/bin/swayimg 2>/dev/null | grep -c NEEDED)
+echo "swayimg: binario autosuficiente ($n NEEDED) · wayland + drm + png jpeg webp tiff gif + exif"
+'''
-# `.pc Requires` → `[deps].build`, el patrón del corpus: fontconfig pide expat, freetype2 pide zlib
-# y libpng, wayland-client pide libffi, libtiff-4 pide zlib+xz+zstd+libjpeg, libwebpdemux pide
-# libsharpyuv (viene en el mismo artefacto). `wayland` aporta además el `wayland-scanner` nativo que
-# teje los NUEVE protocolos.
[deps]
-build = [
- "meson", "samurai", "python3", "pkgconf", "linux-headers",
- "luajit",
- "wayland", "wayland-protocols", "libxkbcommon", "libdrm",
- "fontconfig", "freetype", "expat",
- "libjpeg-turbo", "libpng", "libtiff", "libwebp", "giflib",
- "zlib", "zlib-shared", "xz", "zstd", "libffi",
-]
+build = ["meson", "samurai", "pkgconf", "wayland", "wayland-protocols", "libxkbcommon",
+ "fontconfig", "freetype", "libpng", "libjpeg-turbo", "libwebp", "libtiff",
+ "giflib", "exiv2", "libdrm", "lua", "expat", "zlib", "brotli", "binutils", "python3"]