From 9c657efe61db69145ccfc95ac23779df1df5997e Mon Sep 17 00:00:00 2001 From: Sergio Date: Fri, 4 Sep 2026 20:55:57 +0000 Subject: [PATCH] =?UTF-8?q?plataforma=20Gecko:=20nodejs=2024.18.1=20?= =?UTF-8?q?=E2=80=94=20./mach=20configure=20lo=20exige?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Firefox aborta con «Could not find a Node.js executable»: lo usa para empaquetar los bundles de JS. Waterfox y Zen lo necesitan igual ⇒ al corpus con el resto de la plataforma. TODO BUNDLEADO, a diferencia de Alpine, que lo construye contra diez deps del sistema de las cuales el corpus tiene dos. La decisión de fondo: acá Node es un COMPILADOR, no software que la distro publique — entra al sandbox de Firefox y desaparece, así que el cierre chico gana al cierre puro y el precio (binario gordo, openssl bundleado que nadie expone) no lo paga ningún usuario. Si algún día se quiere PUBLICAR Node, esa es otra receta; queda avisado en la cabecera. Dos AVX-512 apagados, y los dos por la perilla que upstream mismo deja: · simdjson → SIMDJSON_AVX512_ALLOWED=0. ⚠ EN EL .h Y EN EL .cpp: la librería se distribuye AMALGAMADA y el .cpp lleva su propia copia (línea 2493), así que tocar sólo el header no sirve — y engaña, porque ninja sigue con otros objetos y el log parece avanzar. · simdutf (dentro de V8) → se antepone SIMDUTF_IMPLEMENTATION_ICELAKE 0, que es el override que habilita su #ifndef. No se pierde nada: todo el corpus va -mcpu=baseline y ambas eligen implementación en RUNTIME. CXXFLAGS NO sirve acá — GYP no lo propaga a la línea de compilación (verificado buscando el -D en el comando que ninja reportó al fallar). EL PARALELISMO SE CAPA POR RAM Y SIN ESCRIBIR UN NÚMERO. Sin cap, ninja lanza nproc+2 y muere con `job terminated due to signal 9` en el objeto 2936/4414 compilando lo que genera Torque (~2 G por job). Un `-j2` fijo ataría el ArtifactHash a la RAM de quien escribió la receta; la cuenta es un job cada 3 GiB de MemTotal, mínimo 1, tope nproc. Da 2 en momento (7,6 GiB) y 5 en el LXC (16 GiB, 6 cores) con el MISMO texto y el mismo hash. --- recipes/nodejs.toml | 95 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 recipes/nodejs.toml diff --git a/recipes/nodejs.toml b/recipes/nodejs.toml new file mode 100644 index 00000000..658efa93 --- /dev/null +++ b/recipes/nodejs.toml @@ -0,0 +1,95 @@ +# Node.js 24.18.1 (LTS) — HERRAMIENTA DE BUILD de la plataforma Gecko, no un runtime de la distro. +# +# ══ POR QUÉ ENTRA ══════════════════════════════════════════════════════════════════════════════ +# `./mach configure` de Firefox aborta con «Could not find a Node.js executable» si no lo encuentra: +# lo usa para empaquetar los bundles de JS del navegador. No hay perilla para saltarlo. Firefox, +# Waterfox y Zen lo necesitan igual, así que va al corpus con el resto de la plataforma. +# +# ══ TODO BUNDLEADO, A DIFERENCIA DE ALPINE ═════════════════════════════════════════════════════ +# El APKBUILD de Alpine lo construye contra deps del sistema (ada, brotli, c-ares, icu, nghttp2, +# openssl, simdjson, simdutf, sqlite, zstd): de esas, el corpus tiene DOS. Escribir las otras ocho +# para que un navegador pueda compilar es la cola equivocada por la que agarrar el problema. +# +# La decisión de fondo: **acá Node es un compilador más, no software que la distro publique**. Nadie +# va a `hammer install nodejs` desde este artefacto — entra al sandbox de Firefox y desaparece. Para +# eso, el cierre chico gana al cierre puro, y el precio (un binario más gordo, un openssl bundleado +# que nadie expone) no lo paga ningún usuario. Si algún día la distro quiere PUBLICAR Node, esa es +# otra receta y otras deps, y esta nota es el aviso de que no se reutiliza tal cual. +# +# `--with-intl=small-icu`: el default `full-icu` DESCARGA el ICU completo durante el configure, y un +# build hermético no baja nada. `small-icu` usa el ICU que ya viene en el árbol. +# `--ninja`: V8 con make es notablemente más lento y acá se compila entero. +name = "nodejs" +version = "24.18.1" +license = "MIT" + +[source] +tarball = "https://nodejs.org/dist/v24.18.1/node-v24.18.1.tar.gz" +# sha256 de SHASUMS256.txt publicado por upstream, no calculado sobre lo que bajó: el fichero de +# nodejs.org/dist es un artefacto SUBIDO, no generado al vuelo por una forja ⇒ estable (misma +# distinción que en la receta de mbedtls). +sha256 = "b62cd76de0a0a28dd9ff88580c92344bdeb008f21c1d7479c5d8659cd96ef4e2" + +[build] +compiler = "zig-cc" +target = "x86_64-linux-musl" +link = "dynamic" +flags = [] + +[build.phases] +# ⚠ `SIMDJSON_IMPLEMENTATION_ICELAKE=0` — el simdjson que Node bundlea trae un kernel AVX-512 y +# zig-cc lo rechaza: `always_inline function '_mm512_loadu_si512' requires target feature 'evex512'` +# más una tanda de «AVX vector argument … without 'evex512' enabled changes the ABI». clang exige +# `evex512` además del `avx512*` que el código pide por atributo. +# +# Se apaga el kernel en vez de encender `-mevex512`, y no es una salida por lo bajo: **todo el corpus +# compila `-mcpu=baseline`**, así que ese camino no se ejecutaría ni aunque compilara — simdjson elige +# implementación en RUNTIME y caería a haswell/westmere igual. Encender AVX-512 acá produciría además +# un binario que no arranca en cualquier máquina, que es lo contrario de lo que el `baseline` protege. +# +# **Por `sed` sobre el header y NO por `CXXFLAGS`**, que fue el primer intento y no funciona: GYP no +# propaga `CXXFLAGS` del entorno a la línea de compilación (verificado buscando el `-D` en el comando +# que ninja reportó al fallar — no estaba). Se toca la perilla que el propio simdjson expone, +# `SIMDJSON_AVX512_ALLOWED` (`simdjson.h:2512`, default 1), y no la macro de resultado: apagar la +# entrada declarada por upstream es más estable ante una actualización que forzar la salida. +configure = ''' +# ⚠ EL `.h` NO ALCANZA: simdjson se distribuye AMALGAMADO y `simdjson.cpp` trae **su propia copia** +# de la perilla (`simdjson.cpp:2493`), no la incluye del header. Tocar sólo el `.h` deja el `.cpp` +# compilando el kernel AVX-512 igual — y el fallo ENGAÑA, porque ninja sigue con otros objetos y el +# log parece avanzar. Se tocan LOS DOS ficheros, y el `grep` verifica los dos. +for f in deps/simdjson/simdjson.h deps/simdjson/simdjson.cpp; do + sed -i 's/^#define SIMDJSON_AVX512_ALLOWED 1$/#define SIMDJSON_AVX512_ALLOWED 0/' "$f" + grep -q '^#define SIMDJSON_AVX512_ALLOWED 0$' "$f" # falla ruidoso si upstream mueve la línea +done +# simdutf (dentro de V8) es la MISMA falla en otra librería: apareció recién cuando simdjson dejó de +# fallar, que es cómo salen estos errores — por capas, una librería por vuelta. No expone un knob +# «ALLOWED»; lo que deja es el `#ifndef SIMDUTF_IMPLEMENTATION_ICELAKE` de `simdutf.cpp:3901`, o sea +# que el override previsto es DEFINIRLO desde afuera. Se antepone al fichero en vez de editar el +# `#define`, que ocupa dos líneas con continuación y sería más frágil ante una actualización. +sed -i '1i #define SIMDUTF_IMPLEMENTATION_ICELAKE 0' deps/v8/third_party/simdutf/simdutf.cpp +head -1 deps/v8/third_party/simdutf/simdutf.cpp | grep -q 'SIMDUTF_IMPLEMENTATION_ICELAKE 0' +python3 ./configure --prefix=/usr --ninja --with-intl=small-icu +''' +# ══ EL PARALELISMO SE CAPA POR RAM, Y SIN ESCRIBIR UN NÚMERO ═══════════════════════════════════ +# Sin cap, ninja lanza `nproc+2` jobs y el build muere con `ninja: job terminated due to signal 9` +# —SIGKILL, el OOM killer— alrededor del objeto 2900/4414, compilando los ficheros que genera Torque: +# son de los C++ más pesados que existen, del orden de 2 G por job. +# +# **No se escribe `-j2`.** Las fases entran en `hash_inputs`, así que un número fijo ataría el +# ArtifactHash a la RAM de la máquina donde se escribió la receta, y el mismo texto daría hashes +# distintos según quién lo edite. La regla del repo es que el TEXTO sea independiente de la máquina y +# el COMPORTAMIENTO se adapte — que es exactamente lo que hace el `$(nproc)` del resto del corpus. +# Acá el recurso escaso no son los cores sino la memoria, así que la cuenta es por RAM: un job cada +# 3 GiB de MemTotal, nunca menos de 1 ni más de `nproc`. En una máquina de 7 GiB da 2; en una de 64 +# daría 21 y ganaría el `nproc`. +compile = ''' +gib=$(awk "/MemTotal/{printf \"%d\", \$2/1024/1024}" /proc/meminfo) +j=$(( gib / 3 )); [ "$j" -lt 1 ] && j=1 +n=$(nproc); [ "$j" -gt "$n" ] && j=$n +echo "ninja -j$j (MemTotal ${gib} GiB, nproc $n) — V8 y Torque son de los C++ más pesados que hay" +ninja -C out/Release -j"$j" +''' +install = "DESTDIR=/out ninja -C out/Release install || (mkdir -p /out/usr/bin && cp out/Release/node /out/usr/bin/node)" + +[deps] +build = ["python3", "samurai", "pkgconf", "make", "linux-headers", "zlib"]