tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1572Shell 203Rust 109Markdown 993728 Definitions

wasi-libcxx: el eslabón que faltaba en la cadena wasm (lo encontró el build)

El firefox con RLBox murió en el configure a los SEIS SEGUNDOS:

    /tmp/conftest.cpp:1:10: fatal error: 'cstring' file not found
    ERROR: Cannot find wasi headers or problem with the wasm compiler.

El mensaje culpa a los headers de WASI y los headers de WASI estaban perfectos.
`<cstring>` es un header de C++ y `wasi-libc` sólo trae la C: las librerías que
RLBox enjaula no son todas C —graphite2 es C++— así que el sandbox necesita una
biblioteca estándar de C++ para wasm32. Mismo patrón que la lección de los
headers UAPI: el error nombra lo que buscó, no lo que falta.

El hueco estaba en el GRAFO antes de que el build lo encontrara, y se podía ver
sin construir nada: el `wasi-sdk` de Alpine declara
`depends="wasi-libc wasi-libcxx wasi-compiler-rt"` —TRES— y nosotros teníamos
dos. Queda anotado como método: cuando se porta una cadena ajena, la lista de
depends del paquete equivalente es una comprobación de completitud gratis.

La receta es el mismo tarball de LLVM 22.1.8 que `wasi-compiler-rt` (mismo
sha256) y repite su transcripción del toolchain file de wasi-sdk, por el mismo
motivo: 38 líneas de declaraciones puras no justifican una fuente de red y una
receta. Si se toca una, se toca la otra.

Dos detalles que son trampas y no adorno:

- Se construyen los DOS triples (wasip1 y wasip1-threads). `wasi-libc` ya publica
  los dos y firefox pide el sysroot por nombre de triple, así que dejar uno sin
  libc++ sería presente-a-medias, que es peor que ausente.
- cmake instala en el triple canónico (`wasm32-unknown-wasip1`) y clang busca en
  el corto (`wasm32-wasip1`). Sin el renombre del install, libc++ queda al lado
  del sitio donde se la busca: en el artefacto e invisible para el compilador.

El guardián exige exactamente lo que el configure no encontró —`cstring`,
`libc++.a` y `libc++abi.a`— para los dos triples.

Re-hashea: wasi-sdk b3:c8a587fa -> b3:f13634c6, firefox b3:98d6899a ->
b3:2880e28a.

553fc1fb7db33fab0012832f63f8ca3455809d2d · by Sergio · (1 month ago) · parent 65ee20e43 · browse the tree at this commit

Semantic delta

No definition changed: this change is text, documentation or data.

3 files · +194 −2

diff --git a/recipes/firefox.toml b/recipes/firefox.toml
index 7e2e0c85..ab0e84af 100644
--- a/recipes/firefox.toml
+++ b/recipes/firefox.toml
@@ -411,5 +411,9 @@ build = [
   #   wasi-sdk          el `.cfg` de `/etc/clang22`, que hace el sysroot invisible para quien no
   #                     pasa el flag. Con `--with-wasi-sysroot` explícito es cinturón Y tirantes:
   #                     se declara igual porque es lo que hace Alpine y porque cuesta 28 K.
-  "wasi-libc", "wasi-compiler-rt", "wasi-sdk",
+  #   wasi-libcxx       libc++ y libc++abi para wasm32. NO es opcional: las librerías que RLBox
+  #                     enjaula no son todas C (graphite2 es C++) y sin esto el configure muere a
+  #                     los 6 segundos con «'cstring' file not found», culpando a los headers de
+  #                     WASI, que están perfectos. Es el hueco que este build encontró.
+  "wasi-libc", "wasi-libcxx", "wasi-compiler-rt", "wasi-sdk",
 ]
diff --git a/recipes/wasi-libcxx.toml b/recipes/wasi-libcxx.toml
new file mode 100644
index 00000000..6afc0573
--- /dev/null
+++ b/recipes/wasi-libcxx.toml
@@ -0,0 +1,184 @@
+# wasi-libcxx — libc++ y libc++abi compilados a wasm32. EL ESLABÓN QUE FALTABA.
+#
+# POR QUÉ EXISTE ESTA RECETA, y no es una suposición: el build de firefox con RLBox encendido murió
+# en el configure, a los SEIS SEGUNDOS, con
+#
+#     /tmp/conftest.cpp:1:10: fatal error: 'cstring' file not found
+#     ERROR: Cannot find wasi headers or problem with the wasm compiler.
+#
+# El mensaje culpa a los headers de WASI y los headers de WASI estaban perfectos. Lo que falta es
+# otra cosa: `<cstring>` es un header de C++, y `wasi-libc` sólo trae la C. Las librerías que RLBox
+# enjaula NO son todas C —graphite2 es C++— así que el sandbox necesita una biblioteca estándar de
+# C++ para wasm32. Es el mismo patrón que la lección de los headers UAPI: el error nombra lo que
+# buscó, no lo que falta.
+#
+# Contrastado contra Alpine, que es nuestro upstream: su `wasi-sdk` declara
+# `depends="wasi-libc wasi-libcxx wasi-compiler-rt"` — TRES, y nosotros teníamos dos. El hueco
+# estaba en el grafo antes de que el build lo encontrara.
+#
+# ⚠ LA VERSIÓN SIGUE A LA DEL LAB, igual que `wasi-compiler-rt` y por la misma razón: es el mismo
+# tarball de LLVM (22.1.8, mismo sha256) y libc++ es un contrato con el clang que la va a usar. Si
+# el lab sube de LLVM, `TOOLCHAIN_PREFIXES` mueve la huella y esto re-hashea solo.
+#
+# DÓNDE ATERRIZA: `/usr/share/wasi-sysroot`, el MISMO prefijo que `wasi-libc`. No se pisan: las deps
+# se apilan como overlay y overlayfs FUSIONA directorios, así que uno aporta `lib/wasm32-wasip1/
+# libc.a` y el otro `libc++.a` en esa misma carpeta. Es exactamente el reparto que hace Alpine con
+# dos paquetes sobre un solo sysroot.
+name    = "wasi-libcxx"
+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]
+# `wasi-libc` aporta el sysroot contra el que compila libc++ (headers y `libc.a`). NO va
+# `wasi-compiler-rt`: acá sólo se producen archivos estáticos (`LIBCXX_ENABLE_SHARED=OFF`), y sin
+# paso de enlace los builtins no hacen falta — es también lo que declara Alpine.
+build = ["cmake", "samurai", "python3", "wasi-libc"]
+
+[build.phases]
+configure = '''
+set -e
+
+# El mismo toolchain file que escribe `wasi-compiler-rt`, transcrito por el mismo motivo: son 38
+# líneas de declaraciones puras repartidas en dos ficheros del tarball de wasi-sdk, y traerlas
+# costaría una fuente de red y una receta enteras. Si se toca uno, se toca el otro.
+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})
+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
+
+# Los flags del entorno se limpian igual que en `wasi-compiler-rt`: un `-static` o un `-march`
+# pensados para el x86_64 nativo son veneno en un enlace a wasm32 y el error no se parece a la causa.
+unset CFLAGS CXXFLAGS LDFLAGS
+'''
+compile = '''
+set -e
+
+# `-fno-exceptions`: libc++ para wasm se construye SIN excepciones (`LIBCXX_ENABLE_EXCEPTIONS=OFF`
+# abajo), y si los flags no acompañan a la opción de cmake el resultado es una librería a medias.
+export CFLAGS="-fno-exceptions --sysroot=/usr/share/wasi-sysroot"
+export CXXFLAGS="-fno-exceptions --sysroot=/usr/share/wasi-sysroot"
+
+# Una función y dos llamadas, porque los dos triples se configuran IGUAL salvo por los threads. El
+# `-threads` no es opcional: firefox pide el sysroot por el nombre del triple y `wasi-libc` ya
+# publica los dos, así que dejar uno sin libc++ sería el hueco de siempre — presente a medias, que
+# es peor que ausente.
+conf() {
+  t="$1"; d="$2"; thr=OFF; extra=""
+  case "$t" in *-threads) thr=ON; extra="-pthread";; esac
+  cmake -B "$d" -G Ninja -S runtimes -Wno-dev \
+    -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \
+    -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON \
+    -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 \
+    -DCMAKE_C_FLAGS="$CFLAGS $extra --target=$t" \
+    -DCMAKE_CXX_FLAGS="$CXXFLAGS $extra --target=$t" \
+    -DCMAKE_ASM_COMPILER_TARGET="$t" \
+    -DCMAKE_CXX_COMPILER_TARGET="$t" \
+    -DCMAKE_C_COMPILER_TARGET="$t" \
+    -DCMAKE_AR=/usr/bin/llvm-ar \
+    -DCMAKE_RANLIB=/usr/bin/llvm-ranlib \
+    -DLLVM_DEFAULT_TARGET_TRIPLE="$t" \
+    -DCMAKE_STAGING_PREFIX=/usr/share/wasi-sysroot \
+    -DCXX_SUPPORTS_CXX11=ON \
+    -DLIBCXX_ABI_VERSION=2 \
+    -DLIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY=OFF \
+    -DLIBCXX_CXX_ABI=libcxxabi \
+    -DLIBCXX_CXX_ABI_INCLUDE_PATHS=libcxxabi/include \
+    -DLIBCXX_ENABLE_EXCEPTIONS=OFF \
+    -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=OFF \
+    -DLIBCXX_ENABLE_FILESYSTEM=OFF \
+    -DLIBCXX_ENABLE_SHARED=OFF \
+    -DLIBCXX_ENABLE_THREADS=$thr \
+    -DLIBCXX_HAS_EXTERNAL_THREAD_API=OFF \
+    -DLIBCXX_HAS_MUSL_LIBC=ON \
+    -DLIBCXX_HAS_PTHREAD_API=$thr \
+    -DLIBCXX_HAS_WIN32_THREAD_API=OFF \
+    -DLIBCXX_INCLUDE_TESTS=OFF \
+    -DLIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY=OFF \
+    -DLIBCXXABI_ENABLE_EXCEPTIONS=OFF \
+    -DLIBCXXABI_ENABLE_PIC=OFF \
+    -DLIBCXXABI_ENABLE_SHARED=OFF \
+    -DLIBCXXABI_ENABLE_THREADS=$thr \
+    -DLIBCXXABI_HAS_EXTERNAL_THREAD_API=OFF \
+    -DLIBCXXABI_HAS_PTHREAD_API=$thr \
+    -DLIBCXXABI_HAS_WIN32_THREAD_API=OFF \
+    -DLIBCXXABI_INCLUDE_TESTS=OFF \
+    -DLIBCXXABI_LIBCXX_INCLUDES=/src/build-libcxx/include/c++/v1 \
+    -DLIBCXXABI_LIBCXX_PATH=libcxx \
+    -DLIBCXXABI_SILENT_TERMINATE:BOOL=ON \
+    -DLIBCXXABI_USE_LLVM_UNWINDER=OFF \
+    -DUNIX=ON \
+    -DWASI_SDK_PREFIX=/usr \
+    -DLIBCXX_INSTALL_INCLUDE_DIR="include/$t/c++/v1" \
+    -DLIBCXX_INSTALL_INCLUDE_TARGET_DIR="include/$t/c++/v1" \
+    -DLIBCXXABI_INSTALL_INCLUDE_DIR="include/$t/c++/v1"
+}
+
+conf wasm32-wasip1         build
+cmake --build build
+conf wasm32-wasip1-threads build-threads
+cmake --build build-threads
+'''
+install = '''
+set -e
+DESTDIR=/out cmake --install build
+DESTDIR=/out cmake --install build-threads
+
+S=/out/usr/share/wasi-sysroot
+
+# El triple con el que cmake NOMBRA los directorios es el canónico (`wasm32-unknown-wasip1`) y el
+# que clang BUSCA es el corto (`wasm32-wasip1`) — el mismo que ya publica `wasi-libc`. Sin este
+# renombre libc++ quedaría instalada al lado del sitio donde se la busca: presente en el artefacto e
+# invisible para el compilador, que es el modo de fallo más caro de todos.
+cd "$S/lib"
+for t in wasm32-unknown-wasip1 wasm32-unknown-wasip1-threads; do
+  [ -d "$t" ] && mv -v "$t" "${t/unknown-/}"
+done
+cd /src
+
+# GUARDIÁN. Se exige exactamente lo que el configure de firefox no encontró: el header de C++ que
+# disparó todo esto y la librería que lo respalda, PARA LOS DOS TRIPLES. Un `cmake --install` que no
+# instala nada sale con 0, y un sysroot con headers y sin `.a` pasa por bueno y revienta dentro del
+# build de firefox, horas después y sin nombrar a esta receta.
+for t in wasm32-wasip1 wasm32-wasip1-threads; do
+  H="$S/include/$t/c++/v1/cstring"
+  A="$S/lib/$t/libc++.a"
+  B="$S/lib/$t/libc++abi.a"
+  for f in "$H" "$A" "$B"; do
+    test -s "$f" || {
+      echo "!! falta (o está vacío) $f" >&2
+      echo "   contenido real del sysroot:" >&2
+      find "$S" -maxdepth 3 \( -name 'libc++*.a' -o -name 'cstring' \) 2>/dev/null | head -20 >&2
+      exit 1
+    }
+  done
+  echo "guardián: $t ok — libc++.a $(stat -c%s "$A") bytes, libc++abi.a $(stat -c%s "$B") bytes"
+done
+'''
diff --git a/recipes/wasi-sdk.toml b/recipes/wasi-sdk.toml
index 98cb6e9a..0bf7d1a6 100644
--- a/recipes/wasi-sdk.toml
+++ b/recipes/wasi-sdk.toml
@@ -25,7 +25,11 @@ dir = "wasi-sdk"
 compiler = "clang"
 
 [deps]
-build = ["wasi-libc"]
+# Las TRES que declara el `wasi-sdk` de Alpine (`depends="wasi-libc wasi-libcxx
+# wasi-compiler-rt"`), verificado contra su APKBUILD el 2026-09-06. Acá `wasi-libcxx` no es
+# decorativa: sin ella el sysroot al que apunta el .cfg tiene la C y no la C++, y el guardián de
+# abajo —que sólo mira `libc.a`— lo daría por bueno.
+build = ["wasi-libc", "wasi-libcxx"]
 
 [build.phases]
 configure = "true"