gioser

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…

⎇ main recipes/nodejs.toml TOML · 100 lines · 7.0 KB History raw

takana etapa 5a: los comentarios de las 741 recetas e852f4849 · Sergio ·

1# Node.js 24.18.1 (LTS) — HERRAMIENTA DE BUILD de la plataforma Gecko, no un runtime de la distro.
2#
3# ══ POR QUÉ ENTRA ══════════════════════════════════════════════════════════════════════════════
4# `./mach configure` de Firefox aborta con «Could not find a Node.js executable» si no lo encuentra:
5# lo usa para empaquetar los bundles de JS del navegador. No hay perilla para saltarlo. Firefox,
6# Waterfox y Zen lo necesitan igual, así que va al corpus con el resto de la plataforma.
7#
8# ══ TODO BUNDLEADO, A DIFERENCIA DE ALPINE ═════════════════════════════════════════════════════
9# El APKBUILD de Alpine lo construye contra deps del sistema (ada, brotli, c-ares, icu, nghttp2,
10# openssl, simdjson, simdutf, sqlite, zstd): de esas, el corpus tiene DOS. Escribir las otras ocho
11# para que un navegador pueda compilar es la cola equivocada por la que agarrar el problema.
12#
13# La decisión de fondo: **acá Node es un compilador más, no software que la distro publique**. Nadie
14# va a `takana install nodejs` desde este artefacto — entra al sandbox de Firefox y desaparece. Para
15# eso, el cierre chico gana al cierre puro, y el precio (un binario más gordo, un openssl bundleado
16# que nadie expone) no lo paga ningún usuario. Si algún día la distro quiere PUBLICAR Node, esa es
17# otra receta y otras deps, y esta nota es el aviso de que no se reutiliza tal cual.
18#
19# `--with-intl=small-icu`: el default `full-icu` DESCARGA el ICU completo durante el configure, y un
20# build hermético no baja nada. `small-icu` usa el ICU que ya viene en el árbol.
21# `--ninja`: V8 con make es notablemente más lento y acá se compila entero.
22name    = "nodejs"
23version = "24.18.1"
24license = "MIT"
25
26[source]
27tarball = "https://nodejs.org/dist/v24.18.1/node-v24.18.1.tar.gz"
28# sha256 de SHASUMS256.txt publicado por upstream, no calculado sobre lo que bajó: el fichero de
29# nodejs.org/dist es un artefacto SUBIDO, no generado al vuelo por una forja ⇒ estable (misma
30# distinción que en la receta de mbedtls).
31sha256  = "b62cd76de0a0a28dd9ff88580c92344bdeb008f21c1d7479c5d8659cd96ef4e2"
32
33[build]
34compiler = "zig-cc"
35target   = "x86_64-linux-musl"
36link     = "dynamic"
37flags    = []
38# `strip_debug`: la primera vuelta selló SIN esto y el binario salió de **984 MB, con `.debug_info`
39# de 497 MB y `.debug_line` de 43** — más de la mitad del artefacto era información de depuración,
40# para una herramienta que nadie va a depurar. Entra en `hash_inputs` a propósito (cambia el
41# contenido) y usa `zig objcopy`, que ya está en el sandbox.
42strip_debug = true
43
44[build.phases]
45# ⚠ `SIMDJSON_IMPLEMENTATION_ICELAKE=0` — el simdjson que Node bundlea trae un kernel AVX-512 y
46# zig-cc lo rechaza: `always_inline function '_mm512_loadu_si512' requires target feature 'evex512'`
47# más una tanda de «AVX vector argument … without 'evex512' enabled changes the ABI». clang exige
48# `evex512` además del `avx512*` que el código pide por atributo.
49#
50# Se apaga el kernel en vez de encender `-mevex512`, y no es una salida por lo bajo: **todo el corpus
51# compila `-mcpu=baseline`**, así que ese camino no se ejecutaría ni aunque compilara — simdjson elige
52# implementación en RUNTIME y caería a haswell/westmere igual. Encender AVX-512 acá produciría además
53# un binario que no arranca en cualquier máquina, que es lo contrario de lo que el `baseline` protege.
54#
55# **Por `sed` sobre el header y NO por `CXXFLAGS`**, que fue el primer intento y no funciona: GYP no
56# propaga `CXXFLAGS` del entorno a la línea de compilación (verificado buscando el `-D` en el comando
57# que ninja reportó al fallar — no estaba). Se toca la perilla que el propio simdjson expone,
58# `SIMDJSON_AVX512_ALLOWED` (`simdjson.h:2512`, default 1), y no la macro de resultado: apagar la
59# entrada declarada por upstream es más estable ante una actualización que forzar la salida.
60configure = '''
61# ⚠ EL `.h` NO ALCANZA: simdjson se distribuye AMALGAMADO y `simdjson.cpp` trae **su propia copia**
62# de la perilla (`simdjson.cpp:2493`), no la incluye del header. Tocar sólo el `.h` deja el `.cpp`
63# compilando el kernel AVX-512 igual — y el fallo ENGAÑA, porque ninja sigue con otros objetos y el
64# log parece avanzar. Se tocan LOS DOS ficheros, y el `grep` verifica los dos.
65for f in deps/simdjson/simdjson.h deps/simdjson/simdjson.cpp; do
66  sed -i 's/^#define SIMDJSON_AVX512_ALLOWED 1$/#define SIMDJSON_AVX512_ALLOWED 0/' "$f"
67  grep -q '^#define SIMDJSON_AVX512_ALLOWED 0$' "$f"   # falla ruidoso si upstream mueve la línea
68done
69# simdutf (dentro de V8) es la MISMA falla en otra librería: apareció recién cuando simdjson dejó de
70# fallar, que es cómo salen estos errores — por capas, una librería por vuelta. No expone un knob
71# «ALLOWED»; lo que deja es el `#ifndef SIMDUTF_IMPLEMENTATION_ICELAKE` de `simdutf.cpp:3901`, o sea
72# que el override previsto es DEFINIRLO desde afuera. Se antepone al fichero en vez de editar el
73# `#define`, que ocupa dos líneas con continuación y sería más frágil ante una actualización.
74sed -i '1i #define SIMDUTF_IMPLEMENTATION_ICELAKE 0' deps/v8/third_party/simdutf/simdutf.cpp
75head -1 deps/v8/third_party/simdutf/simdutf.cpp | grep -q 'SIMDUTF_IMPLEMENTATION_ICELAKE 0'
76python3 ./configure --prefix=/usr --ninja --with-intl=small-icu
77'''
78# ══ EL PARALELISMO SE CAPA POR RAM, Y SIN ESCRIBIR UN NÚMERO ═══════════════════════════════════
79# Sin cap, ninja lanza `nproc+2` jobs y el build muere con `ninja: job terminated due to signal 9`
80# —SIGKILL, el OOM killer— alrededor del objeto 2900/4414, compilando los ficheros que genera Torque:
81# son de los C++ más pesados que existen, del orden de 2 G por job.
82#
83# **No se escribe `-j2`.** Las fases entran en `hash_inputs`, así que un número fijo ataría el
84# ArtifactHash a la RAM de la máquina donde se escribió la receta, y el mismo texto daría hashes
85# distintos según quién lo edite. La regla del repo es que el TEXTO sea independiente de la máquina y
86# el COMPORTAMIENTO se adapte — que es exactamente lo que hace el `$(nproc)` del resto del corpus.
87# Acá el recurso escaso no son los cores sino la memoria, así que la cuenta es por RAM: un job cada
88# 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
89# daría 21 y ganaría el `nproc`.
90compile = '''
91gib=$(awk "/MemTotal/{printf \"%d\", \$2/1024/1024}" /proc/meminfo)
92j=$(( gib / 3 )); [ "$j" -lt 1 ] && j=1
93n=$(nproc); [ "$j" -gt "$n" ] && j=$n
94echo "ninja -j$j (MemTotal ${gib} GiB, nproc $n) — V8 y Torque son de los C++ más pesados que hay"
95ninja -C out/Release -j"$j"
96'''
97install   = "DESTDIR=/out ninja -C out/Release install || (mkdir -p /out/usr/bin && cp out/Release/node /out/usr/bin/node)"
98
99[deps]
100build = ["python3", "samurai", "pkgconf", "make", "linux-headers", "zlib"]