Files
Sergio 85a393aff4 cadena wasm completa: wasi-libc y wasi-sdk sellan (SDD 26, unidad 3.b)
Los cuatro eslabones que enciende RLBox en firefox, sellados de punta a punta:

  wasi-libc-headers  b3:54c6e96d  (andamio, rompe el ciclo del bootstrap)
  wasi-compiler-rt   b3:a3fe63d1  (libclang_rt.builtins-wasm32.a)
  wasi-libc          b3:8e50b145  (libc.a 970.734 bytes, 32 archivos .a)
  wasi-sdk           b3:c8a587fa  (el .cfg que hace el sysroot invisible)

Los dos primeros ya estaban construidos; los dos últimos costaron dos fallos, y
ninguno de los dos era de la receta:

1. `check-symbols` moría por SESGO DE CLANG, no por un artefacto malo. El lab
   trae clang 22.1.8 y este commit de wasi-libc (2025-06-26) congeló su snapshot
   de macros predefinidos contra un clang anterior, así que el diff completo era
   UNA línea: `+#define __wasip1__ 1`. La mitad que importa —los símbolos
   definidos e indefinidos de la libc recién construida— coincidía byte a byte.
   Por eso se RECONCILIA `expected/*/predefined-macros.txt` en vez de saltar el
   chequeo con `make no-check-symbols`, que era la salida fácil: ese target
   existe y se lleva por delante también la comparación de símbolos, que es la
   que vale. Así cualquier OTRA deriva sigue matando el build.

2. `make TARGET_TRIPLE=NOBUILD ... install` NO es un no-op. La regla `install`
   depende de `finish`, que depende de `libc`, así que make no lee el triple
   inexistente como «no construyas» sino como «construí para el triple NOBUILD»
   y muere en `build/NOBUILD/.../crt1-command.o` con `invalid thread model
   'single'` — un error que nombra un fichero que nadie pidió. Se copia
   `sysroot/{lib,share,include}` a mano, que es literalmente lo que hace la
   regla de upstream (`SYSROOT ?= $(CURDIR)/sysroot`).

Cada receta lleva su guardián de contenido, porque acá el modo de fallo caro no
es el ausente sino el vacío: un sysroot con headers y sin libc.a pasa por bueno
y revienta dentro del build de firefox, horas después y sin nombrar a nadie de
esta cadena. Verificado en verde: los builtins son objetos wasm de verdad
(magic 0061736d, no x86_64 nativos) y el .cfg de wasi-sdk apunta a un sysroot
que existe.

El segundo fallo lo diagnosticamos entre dos sesiones: hammer-f8 aportó el
`invalid thread model 'single'` que explicaba la línea que yo veía.

Queda para la próxima unidad el flip de recipes/firefox.toml:
--without-wasm-sandboxed-libraries -> --with-wasi-sysroot, que es un rebuild
largo y su propia unidad de trabajo.
2026-09-06 01:29:41 +00:00

119 lines
6.3 KiB
TOML

# wasi-libc — la libc de WebAssembly. Es el sysroot que firefox usa para compilar sus librerías
# enjauladas en wasm (RLBox): los parsers de fuentes y medios —graphite, ogg, expat, woff2—, o sea
# el código que come entrada no confiable de la red.
#
# ES EL ESLABÓN FINAL de la cadena wasm, y el que firefox consume de verdad:
# wasi-libc-headers (andamio, triple viejo) → wasi-compiler-rt (los builtins) → ESTE
#
# ⚠ COMMIT DISTINTO AL DE `wasi-libc-headers`, a propósito. Acá va el NUEVO (`3f7eb4c7`), cuyo
# triple por defecto es `wasm32-wasip1`. Ése es el que importa: en LLVM 22.1 el target `wasm32-wasi`
# se renombró a `wasm32-wasip1` y el propio `toolchain.configure` de Mozilla lo contempla
# explícitamente, así que el clang 22.1 del lab va a pedir el sysroot con ESE nombre. El commit
# viejo existe sólo para romper el ciclo de bootstrap; ver `wasi-libc-headers.toml`.
#
# Verificado: el sha512 de este tarball coincide byte a byte con el del APKBUILD de Alpine.
name = "wasi-libc"
version = "27.20250626"
license = "Apache-2.0 WITH LLVM-exception AND Apache-2.0 AND MIT AND CC0-1.0 AND BSD-2-Clause"
[source]
tarball = "https://github.com/WebAssembly/wasi-libc/archive/3f7eb4c7d6ede4dde3c4bffa6ed14e8d656fe93f.tar.gz"
sha256 = "6bb86e09dc5ed43260e81176537d702568689cf4203b8beb1f505609c4139ca5"
[build]
compiler = "clang"
[deps]
build = ["make", "wasi-compiler-rt"]
[build.phases]
configure = "true"
compile = '''
set -e
# ⚠ `BUILTINS_LIB` NO ES OPCIONAL ACÁ, y no por gusto: si no se define, el Makefile se BAJA una
# copia conocida desde la CI de wasi-sdk con `curl` (línea ~610 del Makefile upstream). Dentro del
# sandbox hermético eso no tiene red, así que el build moriría; y si la tuviera sería peor, porque
# estaríamos sellando un binario ajeno sin hash. Se le pasa el que construyó `wasi-compiler-rt`.
#
# Ruta ABSOLUTA, no la relativa que usa el APKBUILD de Alpine: el Makefile la consume como
# prerequisito de una regla (`$(BUILTINS_LIB_PATH): $(BUILTINS_LIB)`) y la resuelve contra su propio
# CURDIR, que acá es `/src` y no `/`.
BUILTINS=/usr/lib/llvm22/lib/clang/22/lib/wasi/libclang_rt.builtins-wasm32.a
test -f "$BUILTINS" || { echo "!! falta $BUILTINS (¿no llegó la dep wasi-compiler-rt?)" >&2; exit 1; }
unset CFLAGS CXXFLAGS LDFLAGS
# ⚠ `check-symbols` CONTRA UN CLANG MÁS NUEVO QUE EL SNAPSHOT DEL ÁRBOL.
#
# El target `check-symbols` del Makefile hace DOS cosas: compara los símbolos definidos/indefinidos
# de la libc recién construida contra `expected/`, y compara la lista de macros predefinidos del
# clang que la compiló contra otro snapshot del mismo directorio. Lo primero es una comprobación
# real del artefacto; lo segundo es un detector de deriva de toolchain.
#
# El lab trae clang 22.1.8 y este commit de wasi-libc (2025-06-26) fue congelado contra un clang
# anterior, así que el build muere con UNA sola línea de diferencia:
#
# +#define __wasip1__ 1
#
# La mitad que importa PASÓ: `defined-symbols.txt` y `undefined-symbols.txt` coinciden byte a byte;
# el diff completo son esas 3.196 líneas iguales y ese macro de más. O sea: la libc construida es la
# esperada y lo que cambió es que el compilador define un macro nuevo.
#
# Por eso se RECONCILIA el snapshot en vez de saltar el chequeo con `make no-check-symbols`, que era
# la salida fácil: ese target existe y se lleva por delante también la comparación de símbolos, que
# es justamente la que vale. Así el chequeo sigue vivo y CUALQUIER OTRA deriva —un símbolo que
# desaparece, otro macro nuevo— sigue matando el build.
#
# Se exige que la inserción ocurra: si upstream renombra el ancla, este bloque no puede quedarse
# callado dejando el mismo fallo para más adelante.
for T in wasm32-wasip1 wasm32-wasip1-threads; do
F="expected/$T/predefined-macros.txt"
grep -q '^#define __wasip1__ 1$' "$F" && continue
sed -i 's/^#define __wasm 1$/#define __wasip1__ 1\n#define __wasm 1/' "$F"
grep -q '^#define __wasip1__ 1$' "$F" || {
echo "!! no se pudo reconciliar $F: no apareció el ancla '#define __wasm 1'" >&2
exit 1
}
done
# Los dos triples que firefox puede pedir. NO se construye `wasm32-wasip2`: el APKBUILD de Alpine lo
# hace para rust, que acá no lo consume, y cada triple de más es tiempo de build sin destinatario.
make CC=clang TARGET_TRIPLE=wasm32-wasip1 BUILTINS_LIB="$BUILTINS"
make CC=clang TARGET_TRIPLE=wasm32-wasip1-threads THREAD_MODEL=posix BUILTINS_LIB="$BUILTINS"
# `make install` copia `sysroot/{lib,share,include}` en bloque y falla si `share/` no existe.
mkdir -p sysroot/share
'''
install = '''
set -e
mkdir -p /out/usr/share/wasi-sysroot
# SE COPIA A MANO EN VEZ DE `make install`, y no es atajo — `make install` NO SIRVE ACÁ.
#
# La regla de upstream son dos líneas: `mkdir -p $(INSTALL_DIR)` y
# `cp -p -r $(SYSROOT)/{lib,share,include} $(INSTALL_DIR)`, con `SYSROOT ?= $(CURDIR)/sysroot`.
# O sea que copia el sysroot ENTERO, sin mirar el triple. Pero la regla declara `install: finish`
# y `finish` depende de `libc`, así que invocarla vuelve a entrar al grafo de compilación.
#
# El truco de pasarle un triple inexistente (`TARGET_TRIPLE=NOBUILD`, que es lo que hacía la
# primera versión de esta receta) NO lo evita: make no lo lee como «no construyas», lo lee como
# «construí para el triple NOBUILD» y muere compilando `build/NOBUILD/.../crt1-command.o` — con
# un error que habla de un fichero que nadie pidió. Las dos vueltas de arriba ya dejaron el
# sysroot completo; lo único que falta es moverlo.
cp -p -r sysroot/lib sysroot/share sysroot/include /out/usr/share/wasi-sysroot/
# GUARDIÁN. Un sysroot con headers pero SIN `libc.a` es exactamente la clase de artefacto que pasa
# por bueno y revienta 50 minutos después, dentro del build de firefox, con un error que no nombra
# a wasi-libc. Se exige la libc del triple que firefox va a pedir.
LIBC=/out/usr/share/wasi-sysroot/lib/wasm32-wasip1/libc.a
test -s "$LIBC" || {
echo "!! el sysroot no trae $LIBC" >&2
find /out/usr/share/wasi-sysroot -name '*.a' 2>/dev/null | head -20 >&2
exit 1
}
test -f /out/usr/share/wasi-sysroot/include/wasm32-wasip1/stdlib.h || {
echo "!! el sysroot no trae los headers de wasm32-wasip1" >&2; exit 1; }
echo "guardián: sysroot wasm32-wasip1 completo (libc.a $(stat -c%s "$LIBC") bytes, $(find /out/usr/share/wasi-sysroot -name '*.a' | wc -l) archivos .a)"
'''