waterfox 6.7.1.1 (Gecko 153.1.0) — el primer fork, y la prueba de la tesis del reúso

Waterfox es un fork de Gecko con árbol propio, así que consume EXACTAMENTE la
misma plataforma que Firefox (gtk3, nodejs, clang18, cbindgen, variantes -shared)
y hereda los seis muros ya resueltos sin volver a pagarlos: sin --enable-linker,
compiler=gcc, RUST_TARGET, vaciado de checksums vendorizados, strip_debug y el
build hermético.

Medido con diff ignorando comentarios: las diferencias REALES con 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, una release por encima. Se reutilizan
igual porque el código que tocan (LFS64, time64, prctl, sandbox) se mueve poco
entre releases, pero es una apuesta EXPLÍCITA y no un hecho: si patch falla, falla
temprano —antes de compilar nada— y el arreglo es rebasar el que se queje.

ACÁ SÍ VA BRANDING OFICIAL, y no contradice a firefox.toml: allá va sin marca
porque el nombre y el logo de Firefox sobre un binario parcheado entran en la
política de marcas de Mozilla; acá browser/branding/official ES la marca del
propio Waterfox, que BrowserWorks distribuye en su árbol para que se construya
así.

Fuente por commit y no por el tarball_url de GitHub, que es /archive/-style y se
genera al vuelo. hammer clona con --filter=blob:none, así que el árbol Gecko no
trae historia.
This commit is contained in:
Sergio
2026-09-05 00:37:18 +00:00
parent db0767b3cc
commit a221300c30
+190
View File
@@ -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",
]