diff --git a/recipes/waterfox.toml b/recipes/waterfox.toml new file mode 100644 index 00000000..8053a4ff --- /dev/null +++ b/recipes/waterfox.toml @@ -0,0 +1,190 @@ +# Waterfox 6.7.1.1 (Gecko 153.1.0) — el PRIMER FORK, y la prueba de la tesis del reúso. +# +# ══ QUÉ HEREDA, QUE ES CASI TODO ═══════════════════════════════════════════════════════════════ +# Waterfox es un fork de Gecko con árbol completo propio, así que consume EXACTAMENTE la misma +# plataforma que Firefox —gtk3, nodejs, clang18, cbindgen, y las variantes `-shared` del corpus— y +# los MISMOS seis muros ya resueltos. Ninguno se vuelve a pagar: +# 1. sin `--enable-linker` el sondeo de Mozilla no reconoce a zig (y con gcc ya no aplica). +# 2. `compiler = "gcc"` `flags.configure` EXIGE un `NEEDED …libc++`; zig enlaza libc++ +# estática para musl. Es negativa de upstream, no una perilla. +# 3. `RUST_TARGET` contrato del parche `fix-rust-target` de Alpine, no un bug. +# 4. checksums vendorizados cargo verifica cada fichero; los parches de musl los rompen. +# 5. `strip_debug` sin él el artefacto se va a varios GB. +# 6. hermético `--disable-bootstrap` + `MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE`. +# **Las diferencias reales con `recipes/firefox.toml` son TRES: la fuente, el branding y la versión.** +# Si aparece una cuarta, conviene preguntarse si no debería estar en las dos. +# +# ══ LA BASE ES 153.1.0 Y LOS PARCHES SON DE 154 ════════════════════════════════════════════════ +# `config/milestone.txt` de este tag dice 153.1.0: una release POR DEBAJO de la de Firefox. Los once +# parches de musl se reutilizan igual porque el código que tocan (LFS64, time64, prctl, el sandbox) +# se mueve poco entre releases — pero es una apuesta explícita, no un hecho: si `patch` falla, falla +# TEMPRANO, antes de compilar nada, y el arreglo es rebasar el parche que se queje. +# +# ══ ACÁ SÍ VA BRANDING OFICIAL, Y NO ES INCOHERENCIA ═══════════════════════════════════════════ +# `recipes/firefox.toml` va con branding SIN MARCA a propósito, porque poner el nombre y el logo de +# Firefox sobre un binario parcheado entra en la política de marcas de Mozilla (la historia de +# Iceweasel). Acá es al revés: `browser/branding/official` es **la marca del propio Waterfox**, que +# BrowserWorks distribuye en su árbol para que se construya así. Usar su branding es lo que quieren; +# lo que no se puede es usar el de Mozilla. + +name = "waterfox" +version = "6.7.1.1" +license = "MPL-2.0" + +[source] +# Por COMMIT y no por el `tarball_url` de GitHub: ése es un `/archive/`-style que la forja genera al +# vuelo y cuyo sha256 cambia (ADR 0006). El tag `6.7.1.1` es LIGERO —una sola ref en `ls-remote`, sin +# `^{}`— ⇒ este sha ES el commit. hammer clona con `--filter=blob:none`, así que un árbol Gecko +# entero no trae la historia: sólo los blobs de este commit. +repo = "https://github.com/BrowserWorks/Waterfox.git" +commit = "fd6662f3abfe6161e88b1b9cb4c70a963bdb345a" +# Los once de musl del APKBUILD de Alpine (community/firefox). NO se traen los suyos de ppc64le, +# loongarch ni Android: no aplican a x86_64 y cada parche que no hace falta es una forma más de que +# un rebase falle sin motivo. +patches = [ + "firefox-patches/lfs64.patch", + "firefox-patches/time64.patch", + "firefox-patches/musl-no-linux-prctl.patch", + "firefox-patches/fix-fortify-system-wrappers.patch", + "firefox-patches/fix-rust-target.patch", + "firefox-patches/sandbox-sched_setscheduler.patch", + "firefox-patches/abseil-cpp.patch", + "firefox-patches/glean-stub.patch", + "firefox-patches/rust-lto-thin.patch", + "firefox-patches/wasip1.patch", + "firefox-patches/widevine.patch", +] + +[build] +# ══ `gcc` Y NO `zig-cc` — TRES MUROS DE UNA VEZ ════════════════════════════════════════════════ +# El resto del corpus va con zig-cc y esta receta es una EXCEPCIÓN consciente, del mismo tipo que la +# que el repo ya mantiene para el kernel y cmake (ADR 0011). Se llegó acá por eliminación, no por +# 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 +# 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. +# 3. **«Firefox does not support linking statically with libstdc++»** — y éste no es un flag: +# `flags.configure:79` compila un C++ mínimo, lo pasa por `llvm-objdump --private-headers` y +# exige encontrar un `NEEDED …libc++`. zig enlaza libc++ ESTÁTICA para musl, así que ese NEEDED +# 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`, +# un `ar` de verdad y un linker que se anuncia como «GNU ld». +# +# ⚠ EL PRECIO, ESCRITO: **el lab NO entra en `hash_inputs`**, así que un Firefox construido con el +# gcc del lab queda más expuesto a la deriva del rootfs que uno con zig-cc — dos labs con gcc +# distinto pueden sellar bytes distintos sin que el store lo note. Es la misma deuda que ya cargan el +# kernel y las otras recetas `compiler=gcc`, y la razón por la que conviene no ampliar esta lista sin +# haber agotado antes el camino de zig. +compiler = "gcc" +target = "x86_64-linux-musl" +link = "dynamic" +flags = [] +# ══ `strip_debug`: SIN ESTO EL ARTEFACTO SERÍA INMANEJABLE ═════════════════════════════════════ +# Medido en el `nodejs` que acaba de sellar sin strip: su binario pesa **984 MB, de los cuales +# `.debug_info` son 497 MB y `.debug_line` otros 43** — más de la mitad del artefacto es información +# de depuración. Firefox es varias veces V8, así que sin strip su artefacto entraría en varios GB, y +# el store no es sólo disco: se sincroniza hub↔worker y se respalda. +# +# Es además el hallazgo del SDD 23: el 79% del contenido binario del store era `.debug_*`, y quitarlo +# hace que artefactos que no reproducían PASEN a reproducir, porque lo que difería eran las rutas del +# árbol de build embebidas en esas secciones. +# +# Entra en `hash_inputs` A PROPÓSITO (cambia el contenido del artefacto), y usa `zig objcopy`, que +# siempre está en el sandbox ⇒ no agrega una dep de build. +strip_debug = true + +[build.phases] +configure = ''' +export MOZBUILD_STATE_PATH="$PWD/.mozbuild" +export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=system +export MOZ_NOSPAM=1 +# ── RUST_TARGET: lo EXIGE el parche de Alpine, no Firefox ───────────────────────────────────── +# `fix-rust-target.patch` REEMPLAZA la autodetección del triple de Rust por un +# `os.environ['RUST_TARGET']` pelado. Sin la variable, configure muere con +# `KeyError: 'RUST_TARGET'` — que se lee como un bug de Firefox y es en realidad el contrato del +# parche: el APKBUILD de Alpine lo exporta como `$CTARGET` y acá hay que hacer lo propio. +# El valor NO se adivina: sale de `ls .dev-fs/alpine/usr/lib/rustlib/` en el lab, que es +# `x86_64-alpine-linux-musl` — el rustc del sandbox es el de Alpine, no el del host (el del host es +# `x86_64-unknown-linux-gnu` y usarlo produciría un cross-compile silencioso). +export RUST_TARGET=x86_64-alpine-linux-musl + +# ── LOS PARCHES ROMPEN EL CHECKSUM DE LOS CRATES VENDORIZADOS ───────────────────────────────── +# `error: the listed checksum of third_party/rust/zeitstempel/src/unix.rs has changed`. Los crates +# de Rust vienen VENDORIZADOS en el tarball y cargo verifica el sha de CADA fichero contra +# `.cargo-checksum.json`; en cuanto un parche de musl toca uno, el build muere. Cargo no ofrece +# ninguna forma de recalcularlo, así que la salida —la misma del APKBUILD de Alpine— es vaciar la +# lista de ficheros del manifiesto, dejando el checksum del paquete. +# +# Son los CINCO crates que tocan los parches, no uno: el error los va destapando de a uno y buscarlos +# por prueba y error costaría cinco vueltas de configure. +for c in audio_thread_priority cc zeitstempel wgpu-hal alsa; do + f="third_party/rust/$c/.cargo-checksum.json" + [ -f "$f" ] || { echo "FALTA $f — ¿upstream movió el crate?" >&2; exit 1; } + sed -i 's/\("files":{\)[^}]*/\1/' "$f" +done +cat > .mozconfig <<'MOZ' +ac_add_options --prefix=/usr +ac_add_options --enable-application=browser +ac_add_options --enable-default-toolkit=cairo-gtk3-wayland +ac_add_options --enable-release +ac_add_options --enable-optimize +ac_add_options --enable-hardening +ac_add_options --enable-official-branding +ac_add_options --with-libclang-path=/usr/lib +ac_add_options --disable-bootstrap +ac_add_options --disable-jemalloc +ac_add_options --disable-crashreporter +ac_add_options --disable-updater +ac_add_options --disable-tests +ac_add_options --disable-debug +ac_add_options --disable-debug-symbols +ac_add_options --disable-strip +ac_add_options --disable-install-strip +ac_add_options --disable-cargo-incremental +ac_add_options --without-wasm-sandboxed-libraries +ac_add_options --enable-alsa +ac_add_options --enable-pulseaudio +ac_add_options --enable-dbus +ac_add_options --enable-ffmpeg +mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir +MOZ +./mach configure +''' +# `mach build` respeta -jN; la cuenta es la misma que en nodejs.toml y por el mismo motivo: un número +# fijo ataría el ArtifactHash a la RAM de quien escribió la receta. +# ⚠ OJO con el techo: dentro del sandbox `/proc/meminfo` NO muestra la memoria del contenedor sino la +# del host (medido en el LXC: 186 GiB en vez de 16), así que en un contenedor esta cuenta se degrada +# a `nproc`. Es un tope, no una garantía. +compile = ''' +export RUST_TARGET=x86_64-alpine-linux-musl # ver la nota en la fase configure +export MOZBUILD_STATE_PATH="$PWD/.mozbuild" +export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=system +export MOZ_NOSPAM=1 +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 "mach build -j$j (MemTotal ${gib} GiB, nproc $n)" +./mach build -j"$j" +''' +install = ''' +export RUST_TARGET=x86_64-alpine-linux-musl # ver la nota en la fase configure +export MOZBUILD_STATE_PATH="$PWD/.mozbuild" +export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=system +DESTDIR=/out ./mach install +''' + +[deps] +build = [ + "python3", "pkgconf", "nasm", "make", "cmake", + # la plataforma Gecko, compartida con Waterfox y Zen + "nodejs", "cbindgen", "clang18", "llvm18", + "gtk3", "atk", "gdk-pixbuf", "pango", "cairo", "libepoxy", + "glib-shared", "pcre2-shared", "libffi-shared", "zlib-shared", + "harfbuzz", "fribidi", "freetype-shared", "fontconfig-shared", "pixman", + "libpng-shared", "libjpeg-turbo-shared", + "wayland", "wayland-protocols", "libxkbcommon", "mesa", "libdrm", + "dbus", "pipewire", "pulseaudio", "alsa-lib", + "libxml2-shared", "linux-headers", +]