receta: sonic — un `find_library` sin REQUIRED no significa «opcional»
`pcaudiolib` SELLÓ con el guardián corregido. Y espeak-ng avanzó hasta aquí:
CMake Error at sonic-git-subbuild/…/sonic-git-populate-gitclone.cmake:50 (message)
Está intentando **clonar `sonic` de git en tiempo de build**, y el sandbox no tiene red — a
propósito: una fuente que se baja al construir no es reproducible ni auditable.
La causa está en `cmake/deps.cmake` y es la lección del commit:
if (SONIC_LIB AND SONIC_INC)
set(HAVE_LIBSONIC ON)
else()
FetchContent_Declare(sonic-git GIT_REPOSITORY …/sonic.git GIT_TAG fbf75c3d…)
FetchContent_MakeAvailable(sonic-git)
set(HAVE_LIBSONIC ON) ← ON de todas formas
⚠ **Yo había leído ese fichero y escrito en la receta que «todas sus deps son opcionales, sin
REQUIRED».** Era verdad a medias y por eso engañaba: `find_library` sin REQUIRED no aborta, pero el
`else()` no se rinde — clona. Y `USE_LIBSONIC=OFF` no sirve: el fetch está ANTES de que la opción se
evalúe. **Un `find_library` sin REQUIRED no significa «opcional»; hay que leer el `else()`.**
⇒ `recipes/sonic.toml`, pineada al **mismo commit que espeak-ng declara** (`fbf75c3d…`, no el último
tag, que es anterior): es el emparejamiento que upstream prueba, y si algún día mueven su `GIT_TAG`
esta receta lo sigue y el `git log` dirá por qué.
Y un detalle medido que mata builds sin nombrar la causa: **su Makefile codifica `CC=gcc`** (línea
41, con `=` y no `?=`), así que la variable de entorno no lo cambia — hay que pasarlo en la línea de
`make`, que sí gana. En este lab `gcc` no existe (matar-gcc) y sin el override muere con
«gcc: not found». Misma familia que el crate `autotools` adivinando el host del NOMBRE de `$CC`: un
build que codifica su compilador miente sobre ser portable.
El guardián de sonic se escribió MIRANDO qué busca el consumidor —`find_library(SONIC_LIB sonic)` y
`find_path(SONIC_INC "sonic.h")`— y **no exige un `.pc`**, que es exactamente el requisito que me
inventé con pcaudiolib hace veinte minutos.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Semántico sayk'uy
Mana ima sutichaypas t'ikrakurqanchu: qillqalla, yachachiylla utaq willaylla t'ikrakurqan.
2 qillqakuna · +83 −1
- recipes/espeak-ng.toml +10 −1
- recipes/sonic.toml +73 −0
diff --git a/recipes/espeak-ng.toml b/recipes/espeak-ng.toml
index 162b232c..103ed5bb 100644
--- a/recipes/espeak-ng.toml
+++ b/recipes/espeak-ng.toml
@@ -26,6 +26,15 @@
# USE_MBROLA=OFF voces MBROLA: binario externo, no está en el corpus y son diccionarios
# por idioma aparte. La síntesis formante propia no las necesita
# USE_SPEECHPLAYER=OFF sintetizador alternativo experimental
+#
+# ⚠ **`sonic` ES DEP OBLIGATORIA AUNQUE SU `find_library` NO LO PAREZCA.** `deps.cmake` la busca sin
+# REQUIRED… y si no la encuentra **la CLONA de git** (`FetchContent_Declare(sonic-git …)`), lo que en
+# un sandbox sin red mata el build:
+# CMake Error at sonic-git-subbuild/…/sonic-git-populate-gitclone.cmake:50
+# Y `USE_LIBSONIC=OFF` no lo evita: el fetch está antes de que la opción se evalúe, y la rama
+# `else()` pone `HAVE_LIBSONIC ON` igual. ⇒ `recipes/sonic.toml` existe para que el `find_library`
+# acierte, pineada al MISMO commit que espeak-ng declara. Lección: **un `find_library` sin REQUIRED
+# no significa «opcional»; hay que leer el `else()`.**
# ESPEAK_COMPAT=ON instala también el nombre viejo `espeak`, que es el que invocan los
# scripts y las apps que no se actualizaron a `espeak-ng`
name = "espeak-ng"
@@ -87,4 +96,4 @@ echo "espeak-ng: binario + libespeak-ng.so + $d fichero(s) de datos · $v famili
# ⚠ `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 —
# un guardián que se cae solo acusa a la receta de algo que no hizo.
-build = ["cmake", "samurai", "pkgconf", "pcaudiolib", "pulseaudio", "alsa-lib", "binutils"]
+build = ["cmake", "samurai", "pkgconf", "pcaudiolib", "sonic", "pulseaudio", "alsa-lib", "binutils"]
diff --git a/recipes/sonic.toml b/recipes/sonic.toml
new file mode 100644
index 00000000..ba660d1c
--- /dev/null
+++ b/recipes/sonic.toml
@@ -0,0 +1,73 @@
+# sonic — cambia la velocidad del habla sin cambiar el tono. Dep OBLIGATORIA de espeak-ng, de hecho.
+#
+# ══ POR QUÉ ESTA RECETA EXISTE: ESPEAK-NG LA CLONA SI NO ESTÁ ══════════════════════════════════
+# `cmake/deps.cmake` de espeak-ng 1.52 dice esto, y es lo que obliga:
+#
+# if (SONIC_LIB AND SONIC_INC)
+# set(HAVE_LIBSONIC ON)
+# else()
+# FetchContent_Declare(sonic-git GIT_REPOSITORY https://github.com/waywardgeek/sonic.git
+# GIT_TAG fbf75c3d6d846bad3bb3d456cbc5d07d9fd8c104)
+# FetchContent_MakeAvailable(sonic-git) ← git clone en tiempo de build
+#
+# O sea que si sonic no está instalado, espeak-ng **la clona de git**, y el sandbox de takana no
+# tiene red (a propósito: una fuente que se baja al construir no es reproducible ni auditable). El
+# build murió exactamente ahí:
+# CMake Error at sonic-git-subbuild/…/sonic-git-populate-gitclone.cmake:50 (message)
+#
+# ⚠ **Y `USE_LIBSONIC=OFF` NO lo evita**, que fue lo primero que probé mentalmente: el fetch está en
+# `deps.cmake`, ANTES de que la opción se evalúe, y la rama `else()` pone `HAVE_LIBSONIC ON` de
+# todas formas. No hay perilla: la única salida es que `find_library(SONIC_LIB sonic)` encuentre algo.
+#
+# ══ EL COMMIT ES EL QUE ESPEAK-NG PINEA, Y ESO ES DELIBERADO ═══════════════════════════════════
+# `fbf75c3d…` es exactamente el `GIT_TAG` de arriba — no el último tag de sonic (`release-0.2.0`,
+# que es anterior). Se pinea el mismo porque es el emparejamiento que upstream prueba: si algún día
+# espeak-ng mueve su `GIT_TAG`, esta receta lo sigue, y el `git log` dirá por qué.
+#
+# ══ ⚠ `CC=gcc` ESTÁ CODIFICADO EN EL MAKEFILE ══════════════════════════════════════════════════
+# Línea 41: `CC=gcc`, con `=` y no `?=`, así que la variable de entorno NO lo cambia — hay que
+# pasarlo en la LÍNEA DE `make`, que sí gana sobre una asignación del makefile. En este lab `gcc` no
+# existe (matar-gcc, 2026-07-16) y sin el override el build muere con «gcc: not found», que no
+# nombra la causa. Es la misma familia que el crate `autotools` adivinando el host del NOMBRE de
+# `$CC`: **un build que codifica su compilador miente sobre ser portable.**
+#
+# `-fPIC` ya lo trae su `CFLAGS` (línea 39), así que no hay que añadirlo: esta `.a` puede entrar en
+# un `.so`, que es justo lo que espeak-ng necesita.
+name = "sonic"
+version = "0.3.0-fbf75c3"
+license = "Apache-2.0"
+
+[source]
+tarball = "https://github.com/waywardgeek/sonic/archive/fbf75c3d6d846bad3bb3d456cbc5d07d9fd8c104/sonic.tar.gz"
+sha256 = "715827b5a39b79e56e44397d7b845910df996d4cca74777b3b61629b1ddc98c1"
+
+[build]
+compiler = "zig-cc"
+target = "x86_64-linux-musl"
+link = "dynamic"
+flags = []
+
+[build.phases]
+configure = '''
+printf '%s\n' '#!/bin/sh' 'for a do' 'case "$a" in --target=*) a=--target=x86_64-linux-musl ;; esac' 'set -- "$@" "$a"' 'shift' 'done' 'exec /opt/zig/zig cc -mcpu=baseline "$@"' > .zcc
+chmod +x .zcc
+'''
+# `CC` en la línea de make, no en el entorno: ver la nota de arriba.
+compile = 'make CC="$PWD/.zcc" PREFIX=/usr -j"$(nproc)"'
+# Guardián escrito MIRANDO qué busca el consumidor, no lo que un paquete «debería» publicar — es la
+# lección que me costó tres guardianes demasiado estrictos hoy. espeak-ng hace exactamente:
+# find_library(SONIC_LIB sonic) ⇒ un libsonic.{so,a} en una ruta de bibliotecas
+# find_path(SONIC_INC "sonic.h") ⇒ sonic.h alcanzable por -I
+# Nada de pkg-config: NO se exige un `.pc`, que es precisamente el requisito que me inventé con
+# pcaudiolib.
+install = '''
+set -e
+make install PREFIX=/usr DESTDIR=/out
+lib=$(find /out/usr/lib -name 'libsonic.*' 2>/dev/null | head -1)
+[ -n "$lib" ] || { echo "sonic: no quedó ninguna libsonic.* — el find_library de espeak-ng no la encontraría" >&2; ls -R /out/usr 2>/dev/null | head -20 >&2; exit 1; }
+[ -f /out/usr/include/sonic.h ] || { echo "sonic: falta include/sonic.h — es lo que busca el find_path de espeak-ng" >&2; exit 1; }
+echo "sonic: $(basename "$lib") + sonic.h"
+'''
+
+[deps]
+build = ["make"]