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.
This commit is contained in:
Sergio
2026-09-06 01:29:41 +00:00
parent 78a7f87836
commit 85a393aff4
6 changed files with 377 additions and 0 deletions
+141
View File
@@ -0,0 +1,141 @@
# wasi-compiler-rt — los builtins de compiler-rt compilados a wasm32.
#
# QUÉ ES: la runtime del compilador para WebAssembly (`libclang_rt.builtins-wasm32.a`). Sin esto no
# se puede enlazar NADA a wasm, y por eso es el primer eslabón real del sandbox RLBox de firefox
# (SDD 26 §3.bis, lectura 1: RLBox apagado es una desventaja de SEGURIDAD — es la jaula wasm
# alrededor de los parsers de fuentes y medios, o sea justo el código que come entrada no confiable).
#
# NO CONSTRUYE LLVM. El lab ya trae LLVM 22.1.8 CON el backend de WebAssembly compilado dentro
# (comprobado: `wasm32`, `wasm64` y las descripciones "WebAssembly 32-bit/64-bit" están en
# `libLLVM.so.22.1`). De acá sale sólo la runtime, que son ~100 ficheros C: minutos, no horas.
#
# ⚠ LA VERSIÓN TIENE QUE SEGUIR A LA DEL LAB. Los builtins son un contrato con el clang que los va a
# usar: Alpine lo escribe como `wasi-compiler-rt~$_llvmver` en las makedepends de firefox. Acá el
# tarball es 22.1.8 y el lab tiene llvm22 22.1.8-r1 — MISMA versión upstream. Si el lab sube de
# LLVM, esta receta sube con él. Y no queda al aire: `clang` y `llvm` son prefijos de
# `TOOLCHAIN_PREFIXES` (hammer-core/src/lab.rs), así que un bump del lab MUEVE la huella y re-hashea
# esto solo. La alineación es un invariante vigilado, no una nota al pie.
#
# DÓNDE ATERRIZA: `/usr/lib/llvm22/lib/clang/22/lib/wasi/`, que es el resource dir donde clang
# busca los builtins sin que nadie le pase un flag. En el lab ese `lib/` NO existe (sólo hay
# `include/`), y las deps se apilan como capas overlay BAJO el rootfs ⇒ esta receta lo CREA sin
# pisar nada del lab.
#
# Verificado: el sha512 del tarball coincide byte a byte con el del APKBUILD de Alpine.
name = "wasi-compiler-rt"
version = "22.1.8"
license = "Apache-2.0 WITH LLVM-exception"
[source]
tarball = "https://github.com/llvm/llvm-project/releases/download/llvmorg-22.1.8/llvm-project-22.1.8.src.tar.xz"
sha256 = "922f1817a0df7b1489272d18134ee0087a8b068828f87ac63b9861b1a9965888"
[build]
compiler = "clang"
[deps]
# `python3`: el CMakeLists de compiler-rt busca Python3 y, si no lo encuentra, cae a un
# `find_package(Python2 ... REQUIRED)` que MUERE. El error dice "Could NOT find Python2" y lo
# que falta es python3 — el mensaje nombra el fallback, no la causa.
build = ["cmake", "samurai", "python3", "wasi-libc-headers"]
[build.phases]
configure = '''
set -e
# El toolchain file de wasi-sdk, ESCRITO ACÁ EN VEZ DE TRAÍDO. Upstream son 38 líneas repartidas en
# dos ficheros del tarball de wasi-sdk (`wasi-sdk.cmake` + `cmake/Platform/WASI.cmake`, y el segundo
# es literalmente `set(WASI 1)`). Traerlos costaría una fuente de red y una receta enteras para 38
# líneas de declaraciones puras — peor trato. Se transcriben de wasi-sdk-27, que es el que Alpine
# pinea para esta misma versión de compiler-rt.
mkdir -p cmake/Platform
echo 'set(WASI 1)' > cmake/Platform/WASI.cmake
cat > wasi-sdk.cmake <<'EOF'
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
set(CMAKE_SYSTEM_NAME WASI)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR wasm32)
set(triple wasm32-wasi)
set(CMAKE_C_COMPILER ${WASI_SDK_PREFIX}/bin/clang)
set(CMAKE_CXX_COMPILER ${WASI_SDK_PREFIX}/bin/clang++)
set(CMAKE_ASM_COMPILER ${WASI_SDK_PREFIX}/bin/clang)
set(CMAKE_AR ${WASI_SDK_PREFIX}/bin/llvm-ar)
set(CMAKE_RANLIB ${WASI_SDK_PREFIX}/bin/llvm-ranlib)
set(CMAKE_C_COMPILER_TARGET ${triple})
set(CMAKE_CXX_COMPILER_TARGET ${triple})
set(CMAKE_ASM_COMPILER_TARGET ${triple})
# No buscar EJECUTABLES en el sysroot (los de correr durante el build son del host); el resto,
# SÓLO en el sysroot, para que no se cuele una lib nativa x86_64 en un enlace a wasm.
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
EOF
# CFLAGS/LDFLAGS del entorno se limpian a propósito: cualquier flag pensado para el x86_64 nativo
# (un `-static`, un `-march`) es veneno en un enlace a wasm32 y el error que produce no se parece
# en nada a la causa.
unset CFLAGS CXXFLAGS LDFLAGS
cmake -B build -G Ninja -S compiler-rt -Wno-dev \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DCMAKE_MODULE_PATH=/src/cmake \
-DCMAKE_TOOLCHAIN_FILE=/src/wasi-sdk.cmake \
-DCMAKE_C_COMPILER_WORKS=ON \
-DCMAKE_CXX_COMPILER_WORKS=ON \
-DCOMPILER_RT_BAREMETAL_BUILD=ON \
-DCOMPILER_RT_INCLUDE_TESTS=OFF \
-DCOMPILER_RT_HAS_FPIC_FLAG=OFF \
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \
-DCOMPILER_RT_OS_DIR=wasi \
-DCMAKE_AR=/usr/bin/llvm-ar \
-DCMAKE_RANLIB=/usr/bin/llvm-ranlib \
-DWASI_SDK_PREFIX=/usr \
-DCMAKE_INSTALL_PREFIX=/usr/lib/llvm22/lib/clang/22/ \
-DCMAKE_SYSROOT=/usr/share/wasi-sysroot-bootstrap
'''
compile = 'cmake --build build'
install = '''
set -e
DESTDIR=/out cmake --install build
RES=/out/usr/lib/llvm22/lib/clang/22
# El `include/` del resource dir pertenece al LAB (son los headers de clang). Instalarlo desde acá
# lo taparía con una copia del tarball: misma trampa que las deps `clang18`/`llvm18` que había que
# quitar de firefox. Fuera.
rm -rf "$RES/include"
# Los alias que espera clang según cómo se nombre el target. `wasm32-wasi` se renombró a
# `wasm32-wasip1` en LLVM 22.1 (lo dice el propio configure de Mozilla), así que el mismo `.a`
# tiene que responder a los dos nombres o el enlace falla por un alias que no existe.
for p in 1 2; do
ln -s ./wasi "$RES/lib/wasm32-wasip$p"
ln -s ./wasi "$RES/lib/wasm32-unknown-wasip$p"
done
ln -s ./libclang_rt.builtins-wasm32.a "$RES/lib/wasi/libclang_rt.builtins.a"
# GUARDIÁN. Un `cmake --install` que no instala nada sale con 0 y deja el árbol vacío — que en el
# store es un cache-hit envenenado, no un fallo. Se exige el fichero Y que sea un archivo wasm de
# verdad, no un `.a` vacío ni uno de objetos x86_64.
A="$RES/lib/wasi/libclang_rt.builtins-wasm32.a"
test -s "$A" || { echo "!! no se instaló $A" >&2; find /out -name 'libclang_rt*' >&2; exit 1; }
N=$(llvm-nm --print-file-name "$A" 2>/dev/null | wc -l)
test "$N" -gt 0 || { echo "!! $A no tiene símbolos: archivo vacío" >&2; exit 1; }
# Que los miembros sean WASM y no x86_64 nativos. Es LA comprobación que importa: si el sysroot o el
# triple se configuran mal, cmake compila igual pero produce objetos nativos, el `.a` queda lleno y
# con símbolos, y el fallo recién aparece al enlazar firefox — lejos y sin nombrar a esta receta.
# Se mira el número mágico del objeto (`\0asm`), no el nombre del fichero: la primera versión de
# este guardián exigía que el miembro terminara en `.o` y lo rechazó estando BIEN construido,
# porque compiler-rt los nombra de otro modo. Una convención de nombre no es una propiedad.
M=$(llvm-ar t "$A" | head -1)
mkdir -p /tmp/guardian && (cd /tmp/guardian && llvm-ar x "$A" "$M")
MAGIC=$(od -An -tx1 -N4 "/tmp/guardian/$M" | tr -d ' \n')
test "$MAGIC" = "0061736d" || {
echo "!! los objetos de $A NO son wasm (magic=$MAGIC, esperaba 0061736d)" >&2
echo " primer miembro: $M" >&2
exit 1
}
echo "guardián: builtins wasm32 instalados ($(llvm-ar t "$A" | wc -l) objetos, magic wasm ok, $(stat -c%s "$A") bytes)"
'''
+59
View File
@@ -0,0 +1,59 @@
# wasi-libc-headers — SÓLO los headers de wasi-libc, para ROMPER el ciclo del bootstrap wasm.
#
# EL CICLO: `wasi-libc` necesita `libclang_rt.builtins-wasm32.a` para enlazar, y
# `wasi-compiler-rt` necesita los headers de wasi-libc para compilar. Ninguno de los dos puede ir
# primero. Se rompe por acá: los headers NO necesitan compilar nada —el target
# `copy-include-headers.stamp` sólo copia ficheros— así que esta receta sale sin builtins y le da a
# `wasi-compiler-rt` el `CMAKE_SYSROOT` que le falta.
#
# ⚠ POR QUÉ ESTE COMMIT Y NO EL DE `wasi-libc`: acá se pinea `ac020b86` (viejo) y en `wasi-libc`
# `3f7eb4c7` (nuevo), igual que Alpine. NO es un descuido. El árbol instala los headers en
# `sysroot/include/$(TARGET_TRIPLE)`, y el TRIPLE POR DEFECTO cambió entre los dos commits:
# `wasm32-wasi` en el viejo, `wasm32-wasip1` en el nuevo. El toolchain file de wasi-sdk que usa
# `wasi-compiler-rt` fija `wasm32-wasi`, así que con el árbol nuevo clang buscaría
# `include/wasm32-wasi` y encontraría `include/wasm32-wasip1` — sysroot vacío y build muerto.
# El artefacto FINAL que consume firefox es el de `wasi-libc` (wasip1, el triple que clang 22.1
# usa de verdad); éste es andamio de bootstrap y muere acá.
#
# Verificado: el sha512 de este tarball coincide byte a byte con el que publica Alpine en su
# APKBUILD de `wasi-compiler-rt` — o sea que la descarga está contrastada contra una fuente
# independiente, no sólo consigo misma.
name = "wasi-libc-headers"
version = "0.20250521"
license = "Apache-2.0 WITH LLVM-exception AND MIT AND CC0-1.0 AND BSD-2-Clause"
[source]
# Tarball `/archive/<commit>` de GitHub: se genera al vuelo, pero va pineado por COMMIT (no por tag
# móvil) y su sha256 está fijado acá, así que un cambio de bytes falla ruidosamente en el fetch.
# El repo trae un `.gitmodules` con `tools/wasi-headers/WASI`, que en el tarball llega VACÍO: es el
# generador de headers desde la espec WASI, y su salida ya está commiteada en el árbol. El Makefile
# no lo toca. No hace falta modo git.
tarball = "https://github.com/WebAssembly/wasi-libc/archive/ac020b86fd44bafe60aa4fa12f407d16e3731329.tar.gz"
sha256 = "d44bd7fa456aa42c1494767e5ffa00cdbab182d8497a577592a6562629f6f49e"
[build]
compiler = "clang"
[deps]
build = ["make"]
[build.phases]
configure = "true"
# `install-include-headers.sh` necesita un shell POSIX y `find`; los dos están en el lab.
compile = 'make build/wasm32-wasi/copy-include-headers.stamp'
install = '''
set -e
mkdir -p /out/usr/share/wasi-sysroot-bootstrap
cp -a sysroot/. /out/usr/share/wasi-sysroot-bootstrap/
# GUARDIÁN. El target de la stamp es un `touch`: si el script de copia fallara sin salir con
# error, la stamp existiría igual y esta receta sellaría un sysroot VACÍO — que es un cache-hit
# envenenado, no un fallo (regla 3 del CLAUDE.md). Se exige un header concreto, no el directorio.
test -f /out/usr/share/wasi-sysroot-bootstrap/include/wasm32-wasi/stdlib.h || {
echo "!! el sysroot de bootstrap no tiene include/wasm32-wasi/stdlib.h" >&2
echo " (¿cambió TARGET_TRIPLE por defecto en este commit de wasi-libc?)" >&2
ls -R /out/usr/share/wasi-sysroot-bootstrap 2>/dev/null | head -30 >&2
exit 1
}
echo "guardián: headers wasm32-wasi presentes ($(find /out/usr/share/wasi-sysroot-bootstrap -name '*.h' | wc -l) .h)"
'''
+118
View File
@@ -0,0 +1,118 @@
# 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)"
'''
+57
View File
@@ -0,0 +1,57 @@
# wasi-sdk — el fichero de configuración que le dice a clang dónde está el sysroot de wasm.
#
# Es la pieza más chica de la cadena y la que la vuelve INVISIBLE para quien la usa: sin esto,
# firefox tendría que enterarse por un flag de cómo llegar al sysroot; con esto, `clang
# --target=wasm32-wasip1` lo encuentra solo. El clang de Alpine lee `/etc/clang22/<triple>.cfg`
# —el lab ya trae ahí su propio `x86_64-alpine-linux-musl.cfg`, así que el mecanismo está probado en
# esta misma máquina— y overlayfs FUSIONA directorios, así que esta dep suma su fichero sin pisar el
# del lab.
#
# NO TIENE FUENTE UPSTREAM porque el contenido es nuestro: una línea. Usa `[source] dir`, el modo
# que se agregó para `atuq` (SDD 26 §2.ter). Es su segundo consumidor, y el primero fuera del caso
# que lo motivó.
#
# ⚠ `/etc/clang22` lleva la versión del lab en la RUTA. No es una constante que se pueda olvidar: si
# el lab sube de LLVM, esta ruta deja de existir y el sysroot se vuelve invisible en silencio — por
# eso el guardián de abajo comprueba que el directorio del lab exista ANTES de escribir dentro.
name = "wasi-sdk"
version = "27"
license = "Apache-2.0"
[source]
dir = "wasi-sdk"
[build]
compiler = "clang"
[deps]
build = ["wasi-libc"]
[build.phases]
configure = "true"
compile = "true"
install = '''
set -e
# Si el lab cambió de versión de LLVM, esta ruta ya no es la que clang lee. Fallar acá es barato;
# fallar dentro del build de firefox, cuatro horas después y con un error sobre un header de wasm
# que no nombra a esta receta, no lo es.
test -d /etc/clang22 || {
echo "!! el lab no tiene /etc/clang22: ¿subió de versión de LLVM?" >&2
ls -d /etc/clang* 2>/dev/null >&2
exit 1
}
mkdir -p /out/etc/clang22
cp /src/wasm32-unknown-wasip1.cfg /out/etc/clang22/
cp /src/wasm32-unknown-wasip1-threads.cfg /out/etc/clang22/
# GUARDIÁN: que el sysroot al que apunta el .cfg EXISTA. Un `--sysroot` que señala a la nada no da
# error: clang sigue adelante y falla mucho después por headers que no encuentra.
S=$(sed -n 's/^--sysroot //p' /out/etc/clang22/wasm32-unknown-wasip1.cfg)
test -f "$S/lib/wasm32-wasip1/libc.a" || {
echo "!! el .cfg apunta a $S y ahí no hay libc.a de wasm32-wasip1" >&2
exit 1
}
echo "guardián: /etc/clang22 apunta a un sysroot wasm real ($S)"
'''
@@ -0,0 +1 @@
--sysroot /usr/share/wasi-sysroot
@@ -0,0 +1 @@
--sysroot /usr/share/wasi-sysroot