Las seis recetas que el audit daba por colgantes declaran ahora
`runtime = ["gcc-libs"]`. `deps.runtime` NO entra en el ArtifactHash —medido:
firefox sigue en b3:8116bdec, atuq en b3:f2960991, waterfox en b3:88b5a762—
así que esto NO reconstruye nada. Lo que cambia es la CLAUSURA, que es lo que se
hidrata en la imagen.
EVIDENCIA DE QUE ARREGLA EL FALLO REAL, no de que compila: `atuq` bajo sway
headless, sin GPU, renderizando about:buildconfig con sus tablas y la barra de
contenedores de la v0.5. Antes moría con decenas de «Error relocating:
_ZNKSt5ctypeIcE13_M_widen_initEv: symbol not found».
docs/evidencia/atuq-arranca-con-gcc-libs-2026-09-06.png
Y el audit se corrige, porque SUB-REPORTABA en dos formas:
· Miraba sólo ejecutables y `head -12` por artefacto. El siguiente NEEDED que
faltaba estaba en una LIBRERÍA (libmozsandbox.so pedía libnspr4.so), así que
daba «6 recetas» cuando el artefacto de firefox declara 30 sonames. Ahora
recorre TODOS los ELF.
· No contaba lo que el propio artefacto TRAE. Firefox bundlea su nspr/nss y
las encuentra por el LD_LIBRARY_PATH que fija su lanzador; contarlas como
colgantes era un falso positivo.
Con las dos correcciones y gcc-libs en el store, el corpus baja de 25 artefactos
colgantes a TRES, y son otra cosa:
sqlite-shared libreadline.so.8
python3 libreadline.so.8
naabu libdl.so.2 libpthread.so.0 libc.so.6
Los dos primeros piden una receta que falta (readline). El tercero pide sonames
de GLIBC, que en una distro musl es un síntoma distinto y merece su propia
mirada. Quedan anotados, no arreglados.
291 lines
18 KiB
TOML
291 lines
18 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.
|
|
# ══ ⚠ DOS COSAS MEDIDAS EN EL ARTEFACTO, SIN RESOLVER — SON DECISIÓN, NO BUG ══════════════════
|
|
# Del `application.ini` del artefacto `b3:e65c0221` (2026-09-06), leído del sellado, no de la doc:
|
|
#
|
|
# Vendor=BrowserWorks Name=Firefox RemotingName=firefox-default
|
|
# Profile=Waterfox ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
|
|
#
|
|
# 1) EL BRANDING «OFICIAL» DE ESTE COMMIT ES EL DE MOZILLA, NO EL DE WATERFOX. El comentario de
|
|
# más abajo dice que `browser/branding/official` es «la marca del propio Waterfox»; en ESTE
|
|
# commit no lo es. Comprobado en el árbol: `branding/official/configure.sh` pone
|
|
# `MOZ_APP_DISPLAYNAME=Firefox`, y `brand.ftl` da `-brand-short-name = Firefox` y
|
|
# `-brand-full-name = Mozilla Firefox`. El `ID` es además el ID canónico de Firefox. O sea que
|
|
# hoy esto sella un binario parcheado que se presenta como «Mozilla Firefox» — justo lo que
|
|
# `firefox.toml` evita a propósito yendo SIN marca (la historia de Iceweasel). La salida
|
|
# probable es `unofficial`, pero es una decisión de política de marcas, no una perilla técnica,
|
|
# y por eso se deja escrita en vez de cambiada.
|
|
#
|
|
# 2) COLISIONA DE RUTA CON `firefox`. El artefacto instala en `usr/lib/firefox/` y `usr/bin/firefox`
|
|
# —las MISMAS rutas que la receta `firefox`— porque el árbol no fija `MOZ_APP_NAME`. Hoy no
|
|
# rompe nada porque ninguna imagen incluye las dos, pero el día que una lo haga, las dos capas
|
|
# overlay se pelean el mismo fichero y gana una en silencio. El arreglo es `MOZ_APP_NAME` en el
|
|
# mozconfig, que es un rebuild y puede arrastrar branding: su propia unidad de trabajo.
|
|
#
|
|
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 MOZ_BUILD_DATE="$(date -u -d "@${SOURCE_DATE_EPOCH:-1}" +%Y%m%d%H%M%S)" # ver el guardián del install
|
|
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 MOZ_BUILD_DATE="$(date -u -d "@${SOURCE_DATE_EPOCH:-1}" +%Y%m%d%H%M%S)" # ver el guardián del install
|
|
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 MOZ_BUILD_DATE="$(date -u -d "@${SOURCE_DATE_EPOCH:-1}" +%Y%m%d%H%M%S)" # ver el guardián del install
|
|
export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=system
|
|
DESTDIR=/out ./mach install
|
|
|
|
# ── GUARDIÁN: QUE EL BuildID NO SEA UNA FECHA ────────────────────────────────────────────────
|
|
# Copiado de `firefox.toml`, y no por simetría: SIN ESTO YA SELLÓ MAL. El artefacto
|
|
# `b3:e65c0221` del 2026-09-06 salió con `BuildID=20260906062042` —la hora del build— o sea que
|
|
# NO REPRODUCE. Y selló en VERDE: el ArtifactHash es input-addressed y no se mueve por esto, así
|
|
# que `build-state.json` lo contaba como bueno. Es exactamente el modo de fallo que el comentario
|
|
# de firefox describe, ocurriendo en la receta de al lado por no haber copiado las cuatro líneas.
|
|
esperado="$(date -u -d "@${SOURCE_DATE_EPOCH:-1}" +%Y%m%d%H%M%S)"
|
|
real="$(sed -n 's/^BuildID=//p' /out/usr/lib/firefox/application.ini)"
|
|
if [ "$real" != "$esperado" ]; then
|
|
echo "guardián: BuildID=$real y esperaba $esperado — el artefacto NO reproduce." >&2
|
|
echo " Revisá que MOZ_BUILD_DATE se exporte en TODAS las fases." >&2
|
|
exit 1
|
|
fi
|
|
echo "guardián: BuildID = $real (determinista, de SOURCE_DATE_EPOCH)"
|
|
'''
|
|
|
|
[deps]
|
|
# ⚠ DEP DE EJECUCIÓN, NO DE BUILD — Y NO ES DECORACIÓN (2026-09-06).
|
|
# Este artefacto declara `NEEDED libstdc++.so.6` / `libgcc_s.so.1`, y hasta hoy NADIE en el corpus
|
|
# las proveía: sólo existían en `.dev-fs/alpine`, o sea en el LAB. El binario sellaba, REPRODUCÍA
|
|
# bit a bit, pasaba todos los guardianes… y no arrancaba fuera del lab. Se descubrió corriendo
|
|
# `atuq` bajo un sway headless, no leyendo el grafo.
|
|
# `runtime` NO entra en el ArtifactHash (igual que `license`), así que declararlo NO re-hashea:
|
|
# lo que cambia es la CLAUSURA, que es lo que se hidrata en la imagen. Lo vigila
|
|
# `scripts/audit-needed.sh`.
|
|
runtime = ["gcc-libs"]
|
|
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",
|
|
]
|