Barrido de TEXTO puro: 1427 líneas de comentario TOML. Cero ArtifactHash movidos, y eso está MEDIDO, no deducido: hasheé las 741 antes y después y los ficheros de hashes son idénticos byte a byte (723 con hash real + 18 que ya no hasheaban de antes). El guardián valió la pena: el primer barrido, filtrando por 'la línea empieza con #', movió el hash de helix, lsof y steam-runtime-sniper. La causa es que una fase se escribe como compile = <triple> ... <triple> y sus comentarios de SHELL también empiezan con #, pero viven dentro del VALOR — y las fases sí entran en hash_inputs. El barrido ahora calcula los rangos de las cadenas multilínea de TOML y no entra ahí. Quedan intactos a propósito: .hammer-zig-cc y .hammer-cargo-vendor (literales dentro de fases), hammerd, hammer-recover y toda ruta que empiece por /
101 lines
7.0 KiB
TOML
101 lines
7.0 KiB
TOML
# 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 `takana 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 = []
|
|
# `strip_debug`: la primera vuelta selló SIN esto y el binario salió de **984 MB, con `.debug_info`
|
|
# de 497 MB y `.debug_line` de 43** — más de la mitad del artefacto era información de depuración,
|
|
# para una herramienta que nadie va a depurar. Entra en `hash_inputs` a propósito (cambia el
|
|
# contenido) y usa `zig objcopy`, que ya está en el sandbox.
|
|
strip_debug = true
|
|
|
|
[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"]
|