firefox pasa a clang+lld con LTO: la puerta de las optimizaciones costaba apk add lld, no una receta de LLVM
El SDD 26 estimó que habilitar PGO/LTO exigía una receta `llvm-toolchain` (clang+lld+libc++ desde fuente). ERA CARO DE MÁS. Al mirar el lab en vez de suponerlo: - `.dev-fs/alpine` YA TRAE clang22 + llvm22 22.1.8 — la MISMA major que usa el APKBUILD de Alpine para este mismo Firefox (`_llvmver=22`). - `Compiler::Clang` YA EXISTE en hammer, cableado de punta a punta: `parse_compiler` lo acepta y `hammer-build/src/lib.rs` pone CC=clang, CXX=clang++ y AR=llvm-ar. NINGUNA receta lo usaba. - Lo único que faltaba era `ld.lld`. `apk add lld` ⇒ lld22 22.1.8, dos paquetes, cero upgrades. CON ESO CAEN LOS TRES MUROS QUE OBLIGABAN A gcc, sin perder lo que gcc daba: el sondeo de linker se satisface con `--enable-linker=lld`, el `ar` lo pone hammer solo, y el `NEEDED` de la stdlib de C++ existe porque clang++ de Alpine usa la libstdc++ COMPARTIDA — la prueba no es teórica, Alpine construye este Firefox con clang22 y sin libcxx en sus makedepends. LA HUELLA DEL LAB NO SE MOVIÓ, Y SE MIDIÓ ANTES DE TOCAR NADA. `lld` no casa ningún prefijo de TOOLCHAIN_PREFIXES (hammer-core/src/lab.rs), así que los 43 paquetes que entran en `hash_inputs` salieron idénticos ⇒ los 837 artefactos sellados quedan intactos. Eso es lo que hace barato el cambio HOY, y a la vez es un agujero escrito en los dos sitios: la versión de lld no es parte de la identidad del artefacto, y sólo expone a las recetas `compiler="clang"`, que hoy es una. Meter "lld" en la lista de prefijos es lo correcto y cuesta re-hashear el corpus entero: próxima campaña. En el mozconfig entran, además de lld: `--enable-lto=cross`, `--enable-packed-relative-relocs` y `--with-unsigned-addon-scopes=app,system`. El último no es cosmético: sin él un Firefox de release rechaza las extensiones que la distro deja en distribution/extensions/, así que la capacidad de atuq de shipear su propio `sct` se decide ACÁ, en la base, y no en el overlay del derivado. PGO no entra en esta pasada y el porqué queda escrito en la receta: el perfil se junta corriendo el navegador (Alpine y Arch usan xvfb-run; nosotros no tenemos X11 ⇒ sway headless) y el profdata NO es determinista, así que tiene que sellarse como artefacto propio y consumirse por hash. ThinLTO se capa con la misma cuenta que -j y por la misma razón que ella no es un literal: un número fijo ataría el ArtifactHash a la RAM de quien escribió la receta. Nuevo ArtifactHash: b3:6f2a3b2f6db4452ed0d2d3f4e2ff7cd6562a86878d4360653859720be1c3d94d (el firefox 154.0 sellado con gcc queda SUPERADO, no perdido).
This commit is contained in:
@@ -72,6 +72,8 @@ libtool-2.5.4-r2
|
|||||||
libunistring-1.4.2-r0
|
libunistring-1.4.2-r0
|
||||||
libxml2-2.13.9-r2
|
libxml2-2.13.9-r2
|
||||||
linux-headers-7.1.5-r0
|
linux-headers-7.1.5-r0
|
||||||
|
lld22-22.1.8-r0
|
||||||
|
lld22-libs-22.1.8-r0
|
||||||
llvm22-22.1.8-r1
|
llvm22-22.1.8-r1
|
||||||
llvm22-libs-22.1.8-r1
|
llvm22-libs-22.1.8-r1
|
||||||
llvm22-linker-tools-22.1.8-r1
|
llvm22-linker-tools-22.1.8-r1
|
||||||
|
|||||||
+64
-16
@@ -83,28 +83,40 @@ patches = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
# ══ `gcc` Y NO `zig-cc` — TRES MUROS DE UNA VEZ ════════════════════════════════════════════════
|
# ══ `clang` — Y POR QUÉ YA NO ES `gcc` (2026-09-05) ════════════════════════════════════════════
|
||||||
# El resto del corpus va con zig-cc y esta receta es una EXCEPCIÓN consciente, del mismo tipo que la
|
# HISTORIA: esta receta nació con `compiler = "gcc"` porque con zig-cc el configure de Firefox murió
|
||||||
# que el repo ya mantiene para el kernel y cmake (ADR 0011). Se llegó acá por eliminación, no por
|
# tres veces seguidas. Los tres muros eran REALES y siguen siéndolo para zig:
|
||||||
# comodidad — con zig-cc el configure de Firefox murió tres veces seguidas:
|
|
||||||
#
|
#
|
||||||
# 1. «Could not use lld as linker» — zig se identifica como `zig ld 0.16.0` y el sondeo de Mozilla
|
# 1. «Could not use lld as linker» — zig se identifica como `zig ld 0.16.0` y el sondeo de Mozilla
|
||||||
# clasifica por esa cadena buscando «LLD»/«GNU ld»/«GNU gold».
|
# clasifica por esa cadena buscando «LLD»/«GNU ld»/«GNU gold».
|
||||||
# 2. «Cannot find ar» — zig trae `ar` como SUBCOMANDO y `check_prog` busca un ejecutable.
|
# 2. «Cannot find ar» — zig trae `ar` como SUBCOMANDO y `check_prog` busca un ejecutable.
|
||||||
# 3. **«Firefox does not support linking statically with libstdc++»** — y éste no es un flag:
|
# 3. «Firefox does not support linking statically with libstdc++» — `flags.configure:79` compila un
|
||||||
# `flags.configure:79` compila un C++ mínimo, lo pasa por `llvm-objdump --private-headers` y
|
# C++ mínimo, lo pasa por `llvm-objdump --private-headers` y exige un `NEEDED` de la stdlib de
|
||||||
# exige encontrar un `NEEDED …libc++`. zig enlaza libc++ ESTÁTICA para musl, así que ese NEEDED
|
# C++. zig enlaza libc++ ESTÁTICA para musl, así que ese NEEDED no existe nunca.
|
||||||
# no existe nunca. No hay perilla que apagar; es una negativa de upstream.
|
|
||||||
#
|
#
|
||||||
# El gcc del lab (15.2.0, con `libstdc++` COMPARTIDA) satisface los tres: `NEEDED libstdc++.so.6`,
|
# gcc satisfacía los tres, pero al precio de quedar FUERA de la cadena de optimización de Gecko:
|
||||||
# un `ar` de verdad y un linker que se anuncia como «GNU ld».
|
# **PGO, LTO y BOLT son cadena de clang en Firefox** (`--enable-lto=cross` quiere clang+lld,
|
||||||
|
# `--enable-profile-use=cross` espera `-fprofile-instr-use`). Con gcc no hay perilla que encender.
|
||||||
|
# Medido contra el APKBUILD de `community/firefox` de aports —nuestro propio upstream, de donde
|
||||||
|
# salen los once parches de musl— y contra el PKGBUILD de Arch: **las dos hacen LTO y PGO**. No
|
||||||
|
# estábamos adelante de nadie; estábamos atrás, y la puerta era el compilador.
|
||||||
#
|
#
|
||||||
# ⚠ EL PRECIO, ESCRITO: **el lab NO entra en `hash_inputs`**, así que un Firefox construido con el
|
# clang RESUELVE LOS TRES MUROS SIN PERDER NADA:
|
||||||
# gcc del lab queda más expuesto a la deriva del rootfs que uno con zig-cc — dos labs con gcc
|
# 1. `--enable-linker=lld` + `lld` en el lab (añadido a `bootstrap-devfs.sh` el 2026-09-05).
|
||||||
# distinto pueden sellar bytes distintos sin que el store lo note. Es la misma deuda que ya cargan el
|
# 2. `AR=llvm-ar` lo pone hammer solo con `compiler="clang"` (hammer-build/src/lib.rs), y la suite
|
||||||
# kernel y las otras recetas `compiler=gcc`, y la razón por la que conviene no ampliar esta lista sin
|
# `llvm-*` está expuesta en `/usr/bin` por el paso 3a-ter del bootstrap.
|
||||||
# haber agotado antes el camino de zig.
|
# 3. clang++ de Alpine usa la `libstdc++` COMPARTIDA de gcc ⇒ el `NEEDED` existe. La prueba no es
|
||||||
compiler = "gcc"
|
# teórica: Alpine construye este mismo Firefox con clang22 y **sin** `libcxx` en sus makedepends.
|
||||||
|
#
|
||||||
|
# El lab ya traía `clang22`/`llvm22` 22.1.8 (la MISMA major que usa Alpine: `_llvmver=22`), así que
|
||||||
|
# esto no costó una receta de LLVM: costó `apk add lld`.
|
||||||
|
#
|
||||||
|
# ⚠ EL PRECIO, ESCRITO: el toolchain del lab SÍ entra en `hash_inputs` desde el 2026-08-10
|
||||||
|
# (`hammer-core/src/lab.rs`), pero **`lld` no casa ningún prefijo de `TOOLCHAIN_PREFIXES`** ⇒ su
|
||||||
|
# versión NO está en la huella. Eso es lo que permitió añadirlo sin re-hashear los 837 artefactos
|
||||||
|
# sellados —medido: la huella no se movió—, y a la vez deja un agujero que sólo expone a las recetas
|
||||||
|
# `compiler="clang"`, que hoy es ésta. Cerrarlo cuesta un re-hasheo del corpus entero.
|
||||||
|
compiler = "clang"
|
||||||
target = "x86_64-linux-musl"
|
target = "x86_64-linux-musl"
|
||||||
link = "dynamic"
|
link = "dynamic"
|
||||||
flags = []
|
flags = []
|
||||||
@@ -158,6 +170,18 @@ ac_add_options --enable-default-toolkit=cairo-gtk3-wayland
|
|||||||
ac_add_options --enable-release
|
ac_add_options --enable-release
|
||||||
ac_add_options --enable-optimize
|
ac_add_options --enable-optimize
|
||||||
ac_add_options --enable-hardening
|
ac_add_options --enable-hardening
|
||||||
|
# ── LA CADENA DE OPTIMIZACIÓN (2026-09-05) ────────────────────────────────────────────────────
|
||||||
|
# Las tres primeras son lo que Alpine y Arch ya hacían y nosotros no. `--enable-linker=lld` además
|
||||||
|
# resuelve el muro 1 del sondeo de linker (ver el bloque [build]).
|
||||||
|
ac_add_options --enable-linker=lld
|
||||||
|
ac_add_options --enable-lto=cross
|
||||||
|
ac_add_options --enable-packed-relative-relocs
|
||||||
|
# ── LO QUE HABILITA A `atuq` (SDD 26) ─────────────────────────────────────────────────────────
|
||||||
|
# Sin esto un Firefox de release rechaza las extensiones que la distro deja en
|
||||||
|
# `distribution/extensions/`. Es flag de CONFIGURE, o sea que NO se puede resolver en el overlay del
|
||||||
|
# artefacto derivado: la capacidad de `atuq` de shipear sus propias extensiones (el `sct` v1) se
|
||||||
|
# decide acá, en la base. Alpine pasa exactamente este flag y por el mismo motivo.
|
||||||
|
ac_add_options --with-unsigned-addon-scopes=app,system
|
||||||
ac_add_options --with-branding=browser/branding/unofficial
|
ac_add_options --with-branding=browser/branding/unofficial
|
||||||
ac_add_options --with-libclang-path=/usr/lib
|
ac_add_options --with-libclang-path=/usr/lib
|
||||||
ac_add_options --disable-bootstrap
|
ac_add_options --disable-bootstrap
|
||||||
@@ -177,6 +201,30 @@ ac_add_options --enable-dbus
|
|||||||
ac_add_options --enable-ffmpeg
|
ac_add_options --enable-ffmpeg
|
||||||
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir
|
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir
|
||||||
MOZ
|
MOZ
|
||||||
|
# ── POR QUÉ AQUÍ NO HAY PGO TODAVÍA ───────────────────────────────────────────────────────────
|
||||||
|
# PGO es la otra mitad de la ganancia (LTO solo rinde menos que LTO+PGO) y NO entra en esta pasada
|
||||||
|
# por dos muros que las distros no tienen, porque no persiguen lo que nosotros perseguimos:
|
||||||
|
# 1. El perfil se junta CORRIENDO el navegador. Alpine y Arch lo hacen bajo `xvfb-run`; nosotros
|
||||||
|
# NO tenemos X11 en el corpus (la distro es Wayland-only) ⇒ el camino es un sway headless.
|
||||||
|
# 2. El `profdata` NO es determinista (los contadores dependen del timing) ⇒ si se generara aquí,
|
||||||
|
# cada build sellaría bytes distintos. La salida es generarlo UNA vez, sellarlo como artefacto
|
||||||
|
# propio y consumirlo por hash desde `[deps]`.
|
||||||
|
# Es su propia unidad de trabajo (SDD 26 §3.ter). Cuando llegue, además trae el `jarlog`, que ordena
|
||||||
|
# el `omni.ja` para el arranque — y eso condiciona cómo `atuq` puede re-empacarlo.
|
||||||
|
#
|
||||||
|
# ── ThinLTO Y LA MEMORIA ──────────────────────────────────────────────────────────────────────
|
||||||
|
# El enlace ThinLTO abre un trabajo por hilo y cada uno carga bitcode: sin capar, el link es lo
|
||||||
|
# primero que muere por OOM en una máquina de 16 GiB. Se capa con la MISMA cuenta que `-j` y por la
|
||||||
|
# misma razón que ella no es un número fijo: un literal ataría el ArtifactHash a la RAM de quien
|
||||||
|
# escribió la receta (ver la nota de la fase compile).
|
||||||
|
# ⚠ Si algún día dos máquinas con distinto `nproc` sellan bytes distintos, el primer sospechoso es
|
||||||
|
# este flag — ThinLTO se diseñó determinista respecto al número de trabajos, pero es una promesa
|
||||||
|
# de upstream, no algo que hayamos medido acá.
|
||||||
|
gib=$(awk "/MemTotal/{printf \"%d\", \$2/1024/1024}" /proc/meminfo)
|
||||||
|
jl=$(( gib / 3 )); [ "$jl" -lt 1 ] && jl=1
|
||||||
|
n=$(nproc); [ "$jl" -gt "$n" ] && jl=$n
|
||||||
|
export LDFLAGS="${LDFLAGS:-} -Wl,--thinlto-jobs=$jl"
|
||||||
|
echo "ThinLTO con --thinlto-jobs=$jl (MemTotal ${gib} GiB, nproc $n)"
|
||||||
./mach configure
|
./mach configure
|
||||||
'''
|
'''
|
||||||
# `mach build` respeta -jN; la cuenta es la misma que en nodejs.toml y por el mismo motivo: un número
|
# `mach build` respeta -jN; la cuenta es la misma que en nodejs.toml y por el mismo motivo: un número
|
||||||
|
|||||||
@@ -213,6 +213,17 @@ else
|
|||||||
# El runtime libcrypto3/libssl3 (que curl/git necesitan) lo trae Alpine aparte, no es openssl-dev.
|
# El runtime libcrypto3/libssl3 (que curl/git necesitan) lo trae Alpine aparte, no es openssl-dev.
|
||||||
# `clang-dev clang-libs`: aportan libclang.so — `bindgen` (que usan varios *-sys: libbzip3-sys,
|
# `clang-dev clang-libs`: aportan libclang.so — `bindgen` (que usan varios *-sys: libbzip3-sys,
|
||||||
# etc.) lo carga en build para generar bindings de los headers C. No lo trae el base.
|
# etc.) lo carga en build para generar bindings de los headers C. No lo trae el base.
|
||||||
|
# `lld`: el linker de LLVM (`ld.lld`). Lo pide `compiler = "clang"` — hoy `recipes/firefox.toml`,
|
||||||
|
# que es la primera receta del corpus que lo usa. Firefox sondea el linker por la cadena que
|
||||||
|
# imprime (busca «LLD»/«GNU ld»/«GNU gold») y `--enable-lto=cross` necesita un linker con plugin
|
||||||
|
# LLVM; `llvm22-linker-tools` da el LLVMgold.so para GNU ld, pero el camino soportado por
|
||||||
|
# upstream —y el que usa el propio APKBUILD de Alpine con `--enable-linker=lld`— es lld.
|
||||||
|
# ⚠ DEUDA CONOCIDA: `lld` NO casa ningún prefijo de `TOOLCHAIN_PREFIXES` (hammer-core/src/lab.rs)
|
||||||
|
# ⇒ su versión NO entra en la huella del lab. Eso es lo que permite añadirlo HOY sin re-hashear
|
||||||
|
# los 837 artefactos sellados (medido: la huella no se movió), y a la vez es un agujero: dos labs
|
||||||
|
# con distinto lld pueden sellar bytes distintos en la misma dirección. Sólo expone a las recetas
|
||||||
|
# `compiler="clang"`, que hoy es una. Meter "lld" en la lista de prefijos es lo correcto y cuesta
|
||||||
|
# un re-hasheo del corpus entero: va en la próxima campaña, no de paso.
|
||||||
# `llvm22`: la SUITE binutils de LLVM (llvm-ar/llvm-objdump/llvm-profdata/llvm-nm/llvm-readobj).
|
# `llvm22`: la SUITE binutils de LLVM (llvm-ar/llvm-objdump/llvm-profdata/llvm-nm/llvm-readobj).
|
||||||
# `clang`/`clang-libs` NO la arrastran (sólo libLLVM.so + los binarios clang), y mozjs/spidermonkey
|
# `clang`/`clang-libs` NO la arrastran (sólo libLLVM.so + los binarios clang), y mozjs/spidermonkey
|
||||||
# con clang exige llvm-ar y llvm-objdump ⇒ sin esto configure aborta "Cannot find ar/llvm-objdump".
|
# con clang exige llvm-ar y llvm-objdump ⇒ sin esto configure aborta "Cannot find ar/llvm-objdump".
|
||||||
@@ -234,7 +245,7 @@ else
|
|||||||
# host-tool del kernel enlaza el openssl del corpus desde la capa overlay. Devolverlo al rootfs
|
# host-tool del kernel enlaza el openssl del corpus desde la capa overlay. Devolverlo al rootfs
|
||||||
# podría hacer que el kernel linkee el de Alpine y cambiar su artefacto. ⇒ python3 sigue sin
|
# podría hacer que el kernel linkee el de Alpine y cambiar su artefacto. ⇒ python3 sigue sin
|
||||||
# módulo `ssl`; ninguna receta lo necesita para construir, `pip` sí lo necesitaría.
|
# módulo `ssl`; ninguna receta lo necesita para construir, `pip` sí lo necesitaría.
|
||||||
NEEDED="make autoconf automake m4 patch coreutils libtool pkgconf bash binutils g++ zlib-dev rust cargo clang-dev clang-libs llvm22 linux-headers bubblewrap git curl kmod libffi-dev ncurses-dev readline-dev sqlite-dev bzip2-dev xz-dev expat-dev"
|
NEEDED="make autoconf automake m4 patch coreutils libtool pkgconf bash binutils g++ zlib-dev rust cargo clang-dev clang-libs lld llvm22 linux-headers bubblewrap git curl kmod libffi-dev ncurses-dev readline-dev sqlite-dev bzip2-dev xz-dev expat-dev"
|
||||||
missing=""
|
missing=""
|
||||||
for pkg in $NEEDED; do
|
for pkg in $NEEDED; do
|
||||||
# apk info -e devuelve el paquete si está instalado, vacío si no.
|
# apk info -e devuelve el paquete si está instalado, vacío si no.
|
||||||
|
|||||||
Reference in New Issue
Block a user