fix(espeak-ng): el cuarto guardián mío que rechaza un build correcto — y ya es un patrón
El build **fue bueno**: cmake dijo `libpcaudio: ON (/usr/lib/libpcaudio.a)` y
`USE_LIBPCAUDIO:BOOL=ON`, compiló e instaló. Mi guardián lo rechazó:
espeak-ng: el binario NO trae salida de audio (pcaudio ausente)
Tres comprobaciones y las tres mal, por la misma razón:
· miraba `readelf -d` del BINARIO buscando «pcaudio» — y `libpcaudio` es un `.a`: un estático se
enlaza DENTRO y **nunca** produce una entrada NEEDED;
· el binario sólo enlaza `libespeak-ng.so.1`; el audio vive en la `.so`, no en él;
· y su respaldo por `strings` buscaba `pulse_simple`, que no es el nombre de ningún símbolo
(`pa_simple_new` sí lo es).
⇒ Reescrito contra HECHOS medidos sobre el build correcto: la `.so` trae
`libpulse-simple.so.0 libpulse.so.0 libasound.so.2` en NEEDED y exporta los símbolos
`audio_object_*`, que son la API de pcaudiolib. Se piden las dos cosas porque cubren fallos
distintos — los NEEDED prueban que las bibliotecas están enlazadas; los símbolos, que el código de
pcaudio entró de verdad.
⚠ **ES EL CUARTO GUARDIÁN DEMASIADO ESTRICTO QUE ESCRIBO HOY** (`hangul.so` por `libhangul.so`, el
`.pc` inexistente de pcaudiolib, su patrón `have_pulseaudio=`, y éste). Los cuatro tienen una sola
causa y conviene que esté dicha sin rodeos: **escribí el control contra mi MODELO del artefacto en
vez de contra el artefacto.** La regla que sale es operativa, no moral: *un guardián se escribe
DESPUÉS de inspeccionar un build correcto* — `readelf -d`, `nm -D`, el `CMakeCache.txt` — y lo que
afirma tiene que ser algo que uno acaba de ver con sus ojos en un artefacto que funciona.
Vale la pena decir el otro lado: los cuatro fallaron RUIDOSO y en el primer intento, que es el modo
correcto. Ninguno dejó pasar un artefacto malo, y el de los datos de voz (>50 ficheros) y el de
pcaudiolib (backends detectados) siguen siendo los que impiden sellar un sintetizador mudo — que es
para lo que existen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Semantic delta
No definition changed: this change is text, documentation or data.
1 files · +23 −13
- recipes/espeak-ng.toml +23 −13
diff --git a/recipes/espeak-ng.toml b/recipes/espeak-ng.toml
index ebbd8614..a10435d1 100644
--- a/recipes/espeak-ng.toml
+++ b/recipes/espeak-ng.toml
@@ -89,27 +89,37 @@ install = '''
set -e
DESTDIR=/out cmake --install build
[ -x /out/usr/bin/espeak-ng ] || { echo "espeak-ng: no quedó el binario — NO sello" >&2; exit 1; }
-so=$(find /out/usr/lib -name 'libespeak-ng.so*' 2>/dev/null | head -1)
+so=$(find /out/usr/lib -name 'libespeak-ng.so*' -type f 2>/dev/null | head -1)
[ -n "$so" ] || { echo "espeak-ng: no quedó libespeak-ng.so — orca y speech-dispatcher la cargan con dlopen" >&2; exit 1; }
-# ⚠ GUARDIÁN 1: que REPRODUZCA, no sólo que sintetice. `pcaudio` es opcional para cmake, así que
-# sin este control se sellaría un espeak-ng mudo — compila, instala, y `espeak-ng "hola"` no suena.
-if ! readelf -d /out/usr/bin/espeak-ng 2>/dev/null | grep -qi 'pcaudio' \
- && ! readelf -d "$so" 2>/dev/null | grep -qi 'pcaudio' \
- && ! strings -a /out/usr/bin/espeak-ng 2>/dev/null | grep -q 'pcaudiolib\|pulse_simple\|snd_pcm_open'; then
- echo "espeak-ng: el binario NO trae salida de audio (pcaudio ausente) — sintetizaría a fichero y no sonaría" >&2
- echo " pcaudiolib es dep OPCIONAL para su cmake: si no la encontró, siguió sin ella en silencio" >&2
- exit 1
-fi
+# ⚠ GUARDIÁN 1: que REPRODUZCA, no sólo que sintetice.
+#
+# **ESTE CONTROL ESTUVO MAL Y RECHAZÓ UN BUILD CORRECTO.** Mi primera versión miraba
+# `readelf -d` del BINARIO buscando «pcaudio», y eso no puede funcionar por dos razones que se
+# podían comprobar en un minuto:
+# · `libpcaudio` es un `.a`: un estático se enlaza DENTRO y **nunca** produce una entrada NEEDED.
+# · el binario sólo enlaza `libespeak-ng.so.1`; el audio vive en la `.so`, no en él.
+# Y su respaldo por `strings` buscaba `pulse_simple`, que no es el nombre de ningún símbolo
+# (`pa_simple_new` sí). O sea: tres comprobaciones y las tres contra un modelo mío del artefacto en
+# vez de contra el artefacto.
+#
+# ⇒ Lo de abajo son HECHOS medidos sobre un build correcto (cmake dijo
+# `libpcaudio: ON (/usr/lib/libpcaudio.a)` y `USE_LIBPCAUDIO:BOOL=ON`):
+# la `.so` trae `libpulse-simple.so.0 libpulse.so.0 libasound.so.2` en NEEDED, y exporta los
+# símbolos `audio_object_*` que son la API de pcaudiolib.
+# Se piden las dos cosas porque cubren fallos distintos: los NEEDED prueban que las bibliotecas de
+# audio están enlazadas; los símbolos, que el código de pcaudio entró de verdad.
+sim=$(nm -D "$so" 2>/dev/null | grep -c ' T audio_object_' || true)
+[ "${sim:-0}" -gt 0 ] || { echo "espeak-ng: la .so no exporta ningún audio_object_* — el código de pcaudiolib NO entró, sintetizaría a fichero y no sonaría" >&2; exit 1; }
+need=$(readelf -d "$so" 2>/dev/null | grep NEEDED | grep -cE 'libpulse|libasound' || true)
+[ "${need:-0}" -gt 0 ] || { echo "espeak-ng: la .so no enlaza ni libpulse ni libasound — no tiene a dónde sacar el sonido" >&2; readelf -d "$so" 2>/dev/null | grep NEEDED >&2; exit 1; }
# ⚠ GUARDIÁN 2: los datos de voz. Se compilan desde la fuente (`cmake/data.cmake`), no se bajan —
# pero si la fase de datos se saltara, quedaría un sintetizador sin fonemas que no pronuncia nada.
d=$(find /out/usr/share/espeak-ng-data -type f 2>/dev/null | wc -l)
[ "$d" -gt 50 ] || { echo "espeak-ng: sólo $d fichero(s) en espeak-ng-data — esperaba >50; sin fonemas ni voces no pronuncia" >&2; exit 1; }
-v=$(ls /out/usr/share/espeak-ng-data/lang 2>/dev/null | wc -l)
-echo "espeak-ng: binario + libespeak-ng.so + $d fichero(s) de datos · $v familia(s) de idioma"
+echo "espeak-ng: $sim símbolo(s) de audio + $need lib(s) de sonido en NEEDED + $d fichero(s) de datos"
'''
-
[deps]
# ⚠ `binutils` está acá por los GUARDIANES, no por el build: aportan `readelf` y `strings`, y sin
# ellos el control de audio fallaría por falta de herramienta en vez de por el defecto que busca —