# 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 = [] # `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"]