Con las deps -shared el enlace de libxul.so YA PASA (el choque de cairo se
acabó) y el build avanza hasta el empaquetado, donde muere así:
error: browser/installer/package-manifest.in:239: Missing file(s):
bin/browser/chrome/icons/default/default22.png
:240: default24.png
:245: default256.png
No falta arte y no es culpa nuestra: es una inconsistencia INTERNA del árbol de
Waterfox 6.7.1.1. Bajo `#ifdef MOZ_GTK` el manifiesto pide ocho tamaños (16, 22,
24, 32, 48, 64, 128, 256) y la rama gtk de branding-common.mozbuild lista sólo
cinco. Los tres ficheros existen en los CUATRO brandings del árbol
(official/aurora/nightly/unofficial); lo que falta es la línea que los instala.
Es una rotura sólo de Linux, que es la razón plausible de que upstream no la
note: la rama de Windows del mismo fichero está completa.
El hunk está GENERADO con `diff -u` sobre el fichero real, no escrito a mano: la
primera versión aplicaba «with fuzz 2» y la segunda «with fuzz 1». Un parche con
fuzz es uno que puede agarrar donde no debe, y verificar que aplica limpio cuesta
un `patch --dry-run`.
Va en recipes/waterfox-patches/ y no en firefox-patches/ porque es de waterfox:
firefox no lo necesita.
242 lines
15 KiB
TOML
242 lines
15 KiB
TOML
# 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.
|
|
|
|
# ══ APARCADA 2026-09-05 — Y NO POR LOS PARCHES ═════════════════════════════════════════════════
|
|
# Primer intento en el worker: murió en CUATRO SEGUNDOS, no en las cuatro horas que temíamos, y por
|
|
# algo que este comentario no preveía:
|
|
#
|
|
# FATAL ERROR PROCESSING MOZBUILD FILE /src/waterfox/browser/moz.build
|
|
# The underlying problem is we referenced a path that does not exist. That path is:
|
|
# /src/waterfox/browser/locales/moz.build
|
|
#
|
|
# O sea: los once parches de musl **sí agarraron** —la apuesta de reusar los de 154 sobre un árbol
|
|
# 153.1.0 no es lo que falló— y lo que falta es un TROZO DEL ÁRBOL. `browser/locales` no está en el
|
|
# clon. Sospechoso número uno: el `--filter=blob:none` + cómo BrowserWorks compone su repo (locales
|
|
# como submódulo o generado), no la receta.
|
|
#
|
|
# Se aparca a propósito: la prioridad pasó a `firefox` con la cadena de optimización y a `atuq`
|
|
# (SDD 26). Cuando se retome, el primer paso es mirar si `browser/locales` existe en el commit
|
|
# pineado — un minuto de `git ls-tree`, no un build.
|
|
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",
|
|
# PROPIO de waterfox, no heredado de firefox: su `branding-common.mozbuild` instala cinco iconos
|
|
# y su `package-manifest.in` exige ocho. Los tres que faltan (22, 24, 256) están en el árbol; lo
|
|
# que falta es la línea que los instala. Rotura sólo de Linux — ver la cabecera del parche.
|
|
"waterfox-patches/branding-icons-gtk.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" && exit 0
|
|
|
|
# ── EL ENLACE FALLA Y `mach` SE TRAGA EL MENSAJE DEL LINKER ───────────────────────────────────
|
|
# Medido dos veces (2026-09-06, 03:20 y 04:08): el build llega al minuto ~36 y muere enlazando
|
|
# `libxul.so` con
|
|
#
|
|
# E collect2: error: ld returned 1 exit status
|
|
#
|
|
# y NADA delante. Entre la línea que anuncia el enlace y el `collect2` no hay ni un renglón en el
|
|
# log, ni `undefined reference`, ni `cannot find -l`, ni `DSO missing`. No es OOM (13 G libres, swap
|
|
# sin tocar) ni disco (37%). El filtro de salida de `mach` clasifica y descarta, y lo que descarta es
|
|
# justo el diagnóstico.
|
|
#
|
|
# Así que si `mach` falla se REHACE el mismo objetivo llamando a gmake directo, sin el filtro de por
|
|
# medio, y se deja hablar al linker. No cambia lo que se construye: es el mismo target sobre el mismo
|
|
# objdir, sólo que sin nadie tapándole la boca. Si el enlace ahora pasa (porque el fallo fuera del
|
|
# propio `mach`), igual salimos con error: esta rama existe para diagnosticar, no para aprobar.
|
|
echo "=== mach falló; rehago el enlace SIN su filtro para ver qué dice ld ==="
|
|
gmake -C objdir/toolkit/library/build V=1 2>&1 | tail -60
|
|
echo "=== fin del reintento ==="
|
|
exit 1
|
|
'''
|
|
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",
|
|
# ⚠ LAS VARIANTES `-shared`, Y NO ES SIMETRÍA CON FIREFOX: ES EL FALLO QUE MATABA EL ENLACE.
|
|
# Con las estáticas, `libcairo.a` entra al enlace de `libxul.so` por el `-lcairo` que arrastra el
|
|
# `.pc` de gtk3, y sus objetos CHOCAN con el cairo BUNDLEADO del propio árbol de Gecko:
|
|
#
|
|
# ld: /usr/lib/libcairo.a(cairo-ft-font.c.o): multiple definition of `_cairo_ft_to_cairo_error';
|
|
# gfx/cairo/cairo/src/cairo-ft-font.o: first defined here
|
|
#
|
|
# …y así decenas de símbolos. Con la variante compartida, `-lcairo` resuelve a `libcairo.so` y los
|
|
# símbolos bundleados se quedan donde tienen que quedarse. Las cuatro van juntas por lo que ya
|
|
# dice `firefox.toml`: declarar las ESTÁTICAS junto a un `gtk3` que trae las compartidas son dos
|
|
# artefactos peleando por el mismo `.pc`. Van las dos listas al mismo sitio o ninguna.
|
|
"gtk3", "atk", "gdk-pixbuf-shared", "pango-shared", "cairo-shared", "libepoxy",
|
|
"glib-shared", "pcre2-shared", "libffi-shared", "zlib-shared",
|
|
"harfbuzz-shared", "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",
|
|
]
|