From 85a393aff40a324f5546260f630787c4267f4ad6 Mon Sep 17 00:00:00 2001 From: Sergio Date: Sun, 6 Sep 2026 01:29:41 +0000 Subject: [PATCH] cadena wasm completa: wasi-libc y wasi-sdk sellan (SDD 26, unidad 3.b) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- recipes/wasi-compiler-rt.toml | 141 ++++++++++++++++++ recipes/wasi-libc-headers.toml | 59 ++++++++ recipes/wasi-libc.toml | 118 +++++++++++++++ recipes/wasi-sdk.toml | 57 +++++++ .../wasm32-unknown-wasip1-threads.cfg | 1 + recipes/wasi-sdk/wasm32-unknown-wasip1.cfg | 1 + 6 files changed, 377 insertions(+) create mode 100644 recipes/wasi-compiler-rt.toml create mode 100644 recipes/wasi-libc-headers.toml create mode 100644 recipes/wasi-libc.toml create mode 100644 recipes/wasi-sdk.toml create mode 100644 recipes/wasi-sdk/wasm32-unknown-wasip1-threads.cfg create mode 100644 recipes/wasi-sdk/wasm32-unknown-wasip1.cfg diff --git a/recipes/wasi-compiler-rt.toml b/recipes/wasi-compiler-rt.toml new file mode 100644 index 00000000..36242943 --- /dev/null +++ b/recipes/wasi-compiler-rt.toml @@ -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)" +''' diff --git a/recipes/wasi-libc-headers.toml b/recipes/wasi-libc-headers.toml new file mode 100644 index 00000000..b380ad50 --- /dev/null +++ b/recipes/wasi-libc-headers.toml @@ -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/` 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)" +''' diff --git a/recipes/wasi-libc.toml b/recipes/wasi-libc.toml new file mode 100644 index 00000000..6a4c4111 --- /dev/null +++ b/recipes/wasi-libc.toml @@ -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)" +''' diff --git a/recipes/wasi-sdk.toml b/recipes/wasi-sdk.toml new file mode 100644 index 00000000..98cb6e9a --- /dev/null +++ b/recipes/wasi-sdk.toml @@ -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/.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)" +''' diff --git a/recipes/wasi-sdk/wasm32-unknown-wasip1-threads.cfg b/recipes/wasi-sdk/wasm32-unknown-wasip1-threads.cfg new file mode 100644 index 00000000..1d8f3832 --- /dev/null +++ b/recipes/wasi-sdk/wasm32-unknown-wasip1-threads.cfg @@ -0,0 +1 @@ +--sysroot /usr/share/wasi-sysroot diff --git a/recipes/wasi-sdk/wasm32-unknown-wasip1.cfg b/recipes/wasi-sdk/wasm32-unknown-wasip1.cfg new file mode 100644 index 00000000..1d8f3832 --- /dev/null +++ b/recipes/wasi-sdk/wasm32-unknown-wasip1.cfg @@ -0,0 +1 @@ +--sysroot /usr/share/wasi-sysroot