🔇 wireplumber: construido, corriendo… y NO era el bloqueo

b3:b8f3baf0, selló a la primera. Arranca desde cosmic-start ("wireplumber OK (pid
192) — hay gestor de sesión"), se conecta al grafo (dos clientes en wpctl status) y
wpctl pasa a mostrar una sección Video que antes no existía.

Y el Start de ScreenCast SIGUE sin Response a los 60s. Mismo resultado exacto.

LA HIPÓTESIS QUEDA MATADA POR MEDICIÓN. "Falta el gestor de sesión que mueva el nodo
de Paused a Streaming" era mía y era razonable; no era cierta. Queda escrita junto a
su refutación porque una hipótesis descartada CON EVIDENCIA vale más que una lista de
sospechosos: acota el próximo paso a lo que queda, que es el backend mismo.

El dato nuevo, que es por dónde seguir: con wireplumber corriendo, `wpctl status`
lista `Video → Streams` VACÍO durante el handshake. O sea que el nodo
`cosmic-screencast` que SÍ existe en `pw-cli ls Node` no llega a wireplumber como
stream gestionado. Próximo movimiento: RUST_LOG=trace sobre screencast_thread, no
otra dep.

── por qué receta propia y no la de GNOME ──────────────────────────────────────
La de incoming-gnome funciona pero NEEDea libglib/libgobject/libpipewire de la ISLA
DINÁMICA de GNOME: traerla metería una segunda glib y una segunda pipewire en la
imagen. De 19 deps, 14 dan hash idéntico; las que divergen divergen a propósito —
sobre todo `pipewire`, que acá apunta a la de COSMIC (338d1d8c), la que el escritorio
realmente ARRANCA. Un gestor de sesión contra otra pipewire que la que corre no
gestiona nada.

El cambio de fondo es glib → glib-shared. COSMIC usa la glib ESTÁTICA del corpus, que
le alcanza al portal porque es un ejecutable. Acá no: wireplumber produce un .so y 17
módulos, y libglib-2.0.a tiene 44.275 reubicaciones R_X86_64_32/32S ⇒ no es PIC. La
regla del frente GNOME (readelf -r ANTES de gastar el build) ahorró uno.

Y la salida no fue una campaña nueva sino una MEDICIÓN: incoming-kde/glib-shared
copiada a esta cola resuelve al MISMO hash (0584ce1f) y ya estaba sellada ⇒ cero
rebuild. Idem pcre2-shared, lua y libelogind. Las dos glib coexisten sin pisarse (.a
y .so son ficheros distintos) y el portal conserva sus 3 NEEDED.

escritorio-cosmic: 84 → 89 recetas, 0 faltantes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-05 10:54:54 -04:00
co-authored by Claude Opus 5
parent 97bcf0673e
commit 8d10bccf34
10 changed files with 402 additions and 5 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

+46 -5
View File
@@ -1090,6 +1090,46 @@ esperarlo. Es una hipótesis, no una medición — construir `wireplumber` la co
- Y uno de shell, al automatizar por QMP: **`| head -N` bufferiza** y deja la terminal en blanco hasta
que el programa termina. Parece que la sonda colgó cuando en realidad está esperando.
## 🔇 wireplumber: construido, corriendo… y NO era el bloqueo (2026-08-05)
`recipes/incoming-cosmic/wireplumber.toml` 0.5.15 → **`b3:b8f3baf0`**, selló a la primera. Arranca
desde `cosmic-start` (`wireplumber OK (pid 192) — hay gestor de sesión`), se conecta al grafo (dos
clientes en `wpctl status`) y `wpctl` pasa a mostrar una sección **Video** que antes no existía.
**Y el `Start` de ScreenCast sigue sin `Response` a los 60s. Exactamente el mismo resultado.**
La hipótesis de la sección anterior —«falta el gestor de sesión que mueva el nodo de `Paused` a
`Streaming`»— **queda MATADA por medición**. Era mía y era razonable; no era cierta. Se deja escrita
junto con su refutación porque una hipótesis descartada con evidencia vale más que una lista de
sospechosos: acota el próximo paso a lo que queda, que es el propio backend.
El dato nuevo, que es por dónde seguir: con wireplumber corriendo, `wpctl status` lista
`Video → Streams` **vacío** durante el handshake. O sea que el nodo `cosmic-screencast` que sí existe
en `pw-cli ls Node` **no llega a wireplumber como stream gestionado**. El próximo movimiento es el log
del backend con `RUST_LOG=trace` alrededor de `screencast_thread`, no otra dep.
### Por qué es una receta propia y no la de GNOME
La de `incoming-gnome` está sellada y funciona, pero su binario NEEDea `libglib-2.0.so.0`,
`libgobject-2.0.so.0` y `libpipewire-0.3.so.0` **de la isla dinámica de GNOME**: traerla tal cual
metería una segunda glib y una segunda pipewire en la imagen. De las 19 deps, **14 dan hash idéntico**
y las que divergen divergen a propósito — sobre todo `pipewire`, que acá apunta a la de COSMIC
(`338d1d8c`), la que el escritorio realmente arranca. Un gestor de sesión contra otra pipewire que la
que corre no gestiona nada.
**El cambio de fondo es `glib` → `glib-shared`.** COSMIC usa la glib ESTÁTICA del corpus, que le
alcanza a `xdg-desktop-portal` porque es un ejecutable. Acá no: wireplumber produce
`libwireplumber-0.5.so` y 17 módulos, y `libglib-2.0.a` del corpus tiene **44.275 reubicaciones
`R_X86_64_32/32S`** ⇒ no es PIC y no entra en un `.so`. (Regla del frente GNOME: `readelf -r` ANTES de
gastar el build — acá ahorró uno.)
La salida no fue una campaña nueva sino una **medición**: `incoming-kde/glib-shared.toml` copiada a
esta cola resuelve al **mismo hash** (`0584ce1f`) y **ya estaba sellada** ⇒ cero rebuild. Idem
`pcre2-shared` (`f254abaa`), `lua` (`e6c35f98`) y `libelogind` (`f1a690b2`). Las dos glib **coexisten
sin pisarse** en el rootfs: `.a` y `.so` son ficheros distintos, y el portal conserva sus 3 NEEDED.
Cierre: `escritorio-cosmic` pasa de 84 a **89 recetas**, 0 faltantes.
### El `-L/usr/lib` que pkg-config no da
`pkg-config` **omite los `-L` de directorios que considera estándar del sistema**, asumiendo que el
@@ -1105,11 +1145,12 @@ existe, y eso cuesta igual que un bug.
## Lo que falta, en orden
1. ~~Arrancar el demonio de pipewire~~ ✅ y ~~el cliente persistente~~ ✅ (`portal-probe`, `b3:af49d32d`).
**Lo que queda es `wireplumber`**: el stream de ScreenCast se crea y llega a `Paused`, con nodo
`cosmic-screencast` visible en pipewire, pero nadie lo pasa a `Streaming` y el backend no emite el
`Response`. La hipótesis es que falta el gestor de sesión — construirlo la confirma o la mata.
Falta también correr `portal-probe filechooser`, que ya puede capturar la URI.
1. ~~Demonio de pipewire~~ ✅, ~~cliente persistente~~ ✅ (`portal-probe`, `b3:af49d32d`),
~~`wireplumber`~~ ✅ (`b3:b8f3baf0`) — **y wireplumber NO era el bloqueo**: el `Start` sigue sin
`Response`. Lo que queda es el **backend mismo**: con `RUST_LOG=trace` alrededor de
`screencast_thread`, mirando por qué el nodo que sí existe en `pw-cli ls Node` no aparece como
`Video → Streams` en `wpctl`. Falta también correr `portal-probe filechooser`, que ya puede
capturar la URI.
2. **Decidir `gvfs`** (ver la corrección de arriba: las piezas ya están selladas, lo que falta es la
decisión sobre la segunda glib). Destrabaría los montajes remotos de cosmic-files y su applet.
3. **Enchufar la tienda a `.swm`**: servir `org.freedesktop.PackageKit` y encender la feature
+5
View File
@@ -137,6 +137,11 @@ paquetes = [
# porque nadie la declara como dep y sin ella el perfil no incluiría con qué verificarse a sí
# mismo — un handshake de portal sólo se puede ejercer DESDE la sesión, con bus y compositor vivos.
"portal-probe",
# El GESTOR DE SESIÓN de pipewire. Se lista como raíz porque ningún `[deps]` lo alcanza: es un
# CLIENTE del demonio, no una librería de nadie. Trae consigo la glib COMPARTIDA (`glib-shared`),
# que no es la estática que usa el resto de la cola — wireplumber produce `.so` y la estática del
# corpus no es PIC. Construido y corriendo; NO desbloqueó ScreenCast (ver el runbook).
"wireplumber",
# Datos, no binarios: el tema de iconos (y el hicolor del que hereda), las tablas de xkb y una
# tipografía. Ninguno es dep de build de nadie y sin ellos el escritorio arranca roto — sin puntero,
# sin teclado o con tofu.
+32
View File
@@ -0,0 +1,32 @@
# glib-shared 2.88.1 — variante DINÁMICA (libglib-2.0.so.0 + libgobject/libgio/libgmodule/libgthread)
# para el escritorio KDE. El canónico (recipes/glib.toml) es `-Ddefault_library=static --prefer-static`
# (sólo .a) ⇒ no enlaza dentro de un .so. Es la **deuda Capa 0 "glib shared-PIC"** que el ADR 0011 arrastra
# desde plasma-workspace (se esquivó parcheando NetworkManagerQt a opcional).
#
# glib es foundational para el resto del escritorio: libnm (NetworkManager→plasma-nm), polkit (auth),
# xdg-desktop-portal, gstreamer. Esta variante lo destraba.
#
# Deps: libffi ya es PIC (--with-pic en el canónico, enlazable en .so) ⇒ no necesita variante.
# pcre2-shared SÍ (el pcre2 canónico no tiene --with-pic). zlib-shared por el libz.so versionado.
# Se conservan los switches del canónico (tests/nls/libmount/selinux/introspection off) para no arrastrar
# deps nuevas; sólo cambia el modo de librería.
name = "glib-shared"
version = "2.88.1"
[source]
tarball = "https://download.gnome.org/sources/glib/2.88/glib-2.88.1.tar.xz"
sha256 = "51ab804c56f6eab3e5045c774d1290ac5e4c923d4f9a3d8e33123bee45c1840e"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "dynamic"
flags = []
[build.phases]
configure = "PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release -Ddefault_library=shared -Dtests=false -Dnls=disabled -Dlibmount=disabled -Dselinux=disabled -Dman-pages=disabled -Dintrospection=disabled -Dglib_debug=disabled -Dglib_assert=false -Dglib_checks=false"
compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
[deps]
build = ["meson", "samurai", "python3", "pkgconf", "libffi", "pcre2-shared", "zlib-shared"]
+69
View File
@@ -0,0 +1,69 @@
# libelogind — la C-ABI `sd-login` que le faltaba a la distro, implementada en arje-compat.
#
# QUÉ RESUELVE: mutter (y polkit, gcr, at-spi2-core) exigen un proveedor de logind por pkg-config —
# `libsystemd` o `libelogind`— para llamar la API C sd-login. Esa API NO es un cliente D-Bus: lee
# `/run/systemd/{sessions,users,seats}`. Los otros tres tienen perilla para esquivarla y se
# construyeron por su camino degradado; **mutter no tiene**, porque `-Dudev=false` exige
# `-Dlogind=false` (mutter/meson.build:257) y sin udev+logind no hay backend nativo KMS: no hay
# compositor de verdad, sólo anidado.
#
# POR QUÉ NO ES elogind NI UN STUB: `arje-logind-compat` ya escribe ese estado en /run/systemd (ver
# `arje_compat::login_state`). Lo único que faltaba era una librería que lo LEYERA y lo ofreciera en
# C. `arje-sdlogin-compat` hace exactamente eso — no inventa datos ni levanta un daemon paralelo.
# Empaquetar elogind sería traer un logind entero a competirle al que arje ya tiene.
#
# Corrige de paso lo que afirma el comentario de recipes/arje-logind-compat.toml («no hace falta la
# C-ABI sd-login… los escritorios consultan login1 en RUNTIME por D-Bus»): es cierto para los
# clientes D-Bus y FALSO para mutter, que la enlaza.
#
# HUB-ONLY, como toda receta de fuente tawasuyu: la gitea escucha en :2345 y el worker efímero es
# secretless ⇒ recibe Connection refused en :22. Se muele en el hub.
name = "libelogind"
version = "0.0.1"
[source]
# El `commit` es el identificador inmutable; la URL es sólo locator y NO entra al ArtifactHash.
# Rama `selfhost/arje-zero-attest-lockfile`, igual que arje-logind-compat, porque es la única que
# versiona el `Cargo.lock` de la raíz: sin él, el vendoreo `--locked` del fetch no es reproducible
# (el monorepo lo gitignora en main).
repo = "gitea@git.tawasuyu.net:tawasuyu/tawasuyu.git"
commit = "749edfe41766e098d3eb18561c6a396610c5cd8e"
# El monorepo COMMITEA su propio `vendor/` (`[patch.crates-io] smithay = { path = "vendor/smithay" }`,
# la copia parcheada que mirada necesita para el tearing) y el `cargo vendor` de hammer escribe ahí
# por defecto, pisándolo: el build muere con `failed to read /src/vendor/smithay/.cargo-checksum.json`
# al resolver la dep git de taffy. Se vendorea a un subdir aparte, igual que arje-logind-compat.
# Apareció recién ahora porque el `vendor/` entró a esta rama con el merge de main, no antes.
# Ver [[hammer-cargo-vendor-clobbers-project-vendor]].
cargo_vendor_dir = ".hammer-cargo-vendor"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
# dynamic, no static: el producto ES una librería compartida (cdylib). Con `link = "static"` el lab
# exporta -static y no hay .so que valga.
link = "dynamic"
flags = ["-p", "arje-sdlogin-compat"]
[build.phases]
# Sólo se sobrescribe `install`: el `compile` por defecto del lab (cargo build --release, offline y
# vendoreado) es el correcto. El default de Cargo copia EJECUTABLES a /usr/bin, y acá no hay ninguno:
# hay una .so, una cabecera y un .pc.
#
# El SONAME (libelogind.so.0) lo fija el build.rs del crate, no esta receta, para que un `cargo build`
# a mano también produzca algo enlazable. Por eso el fichero se instala directamente con ese nombre y
# el `libelogind.so` es el symlink de desarrollo que busca el linker.
#
# La cabecera va a /usr/include/elogind/systemd/ y el .pc trae `-I${includedir}/elogind`: así el
# `#include <systemd/sd-login.h>` de mutter resuelve sin que mutter sepa que somos nosotros. Es el
# mismo arreglo de elogind upstream.
install = '''
set -e
mkdir -p /out/usr/lib/pkgconfig /out/usr/include/elogind/systemd
cp target/release/libelogind.so /out/usr/lib/libelogind.so.0
ln -s libelogind.so.0 /out/usr/lib/libelogind.so
cp 03_ukupacha/arje/arje-sdlogin-compat/include/systemd/sd-login.h /out/usr/include/elogind/systemd/
# sd-daemon.h va aparte porque en systemd también son dos cabeceras y quien la usa la pide por su
# nombre: gdm hace `#include <systemd/sd-daemon.h>` en common/gdm-log.c para `sd_booted()`.
cp 03_ukupacha/arje/arje-sdlogin-compat/include/systemd/sd-daemon.h /out/usr/include/elogind/systemd/
cp 03_ukupacha/arje/arje-sdlogin-compat/pkgconfig/libelogind.pc /out/usr/lib/pkgconfig/
'''
+95
View File
@@ -0,0 +1,95 @@
# lua 5.4.8 — el intérprete y **la librería compartida**, que es lo que hace falta acá.
#
# POR QUÉ ENTRA: `wireplumber` —el gestor de sesión de PipeWire, sin el cual PipeWire acepta clientes
# pero no enumera ni enruta dispositivos— tiene su política escrita EN LUA y embebe un intérprete
# (`lib/wplua`). Su `subprojects/lua.wrap` DESCARGA Lua 5.5 de lua.org, cosa imposible en el sandbox
# hermético (`--wrap-mode=nodownload`), así que va con `-Dsystem-lua=true` y el sistema tiene que
# tener Lua. Su meson acepta 5.5, 5.4 o 5.3 (meson.build:91-95); se elige **5.4**, la serie estable
# larga que usan las distros, en vez de la 5.5 del wrap.
#
# ══ LO QUE ESTA RECETA TIENE QUE INVENTAR, porque upstream no lo da ═════════════════════════════
# El Makefile de Lua sólo produce `liblua.a` y los binarios. **No hay regla de `.so` ni fichero
# pkg-config**: los agrega cada distro. Acá se agregan las dos cosas, y a mano, porque no hay dónde
# copiarlas de:
#
# 1. `-fPIC` en `MYCFLAGS`. Sin esto la `.a` no es reubicable y `libwplua` —que es un objeto
# compartido— no linkea: es la regla del corpus sobre `.a` no-PIC dentro de un `.so`
# («relocation R_X86_64_32 … recompile with -fPIC»), la misma que obligó a las variantes
# `-shared` de zlib, sqlite, libxml2, libuuid y dbus.
# 2. La `.so` se enlaza a mano desde la `.a` con `--whole-archive`, porque una librería estática sólo
# aporta los objetos que alguien referencia y acá hay que llevárselos TODOS. SONAME
# `liblua-5.4.so.0`, que es el que graba quien enlace.
# 3. El `.pc` se escribe acá. El nombre importa: wireplumber prueba `lua-5.4`, `lua5.4` y `lua54` en
# ese orden, así que el fichero se llama `lua5.4.pc` y ADEMÁS se deja `lua-5.4.pc` y `lua.pc` como
# enlaces — es más barato satisfacer las tres convenciones que adivinar cuál buscará el próximo
# consumidor.
#
# `-DLUA_USE_LINUX` es lo que activa `dlopen` y el resto de POSIX; sin él Lua se compila en modo ANSI
# genérico y `require` de módulos C no funciona. **SIN readline a propósito**: sólo lo usa el REPL
# interactivo, y el ncurses del catálogo es static-only y arrastra `-static` al link (el mismo
# problema que hizo saltar `pw-top` en la receta de pipewire).
#
# `SYSLIBS` pierde el `-Wl,-E` de upstream: exportar todos los símbolos del EJECUTABLE sirve para que
# módulos C cargados por `require` vean la API de Lua, y acá el que exporta es la `.so`.
name = "lua"
version = "5.4.8"
[source]
tarball = "https://www.lua.org/ftp/lua-5.4.8.tar.gz"
sha256 = "4f18ddae154e793e46eeab727c59ef1c0c0c2b744e7b94219710d76f530629ae"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "dynamic"
[build.phases]
configure = "true"
compile = '''
set -e
# CC se pasa explícito: el Makefile de Lua lo fija a `gcc -std=gnu99` en la línea 9 y ganaría sobre el
# del entorno.
make -C src all CC="hammer-zig-cc -std=gnu99" \
SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-ldl" MYCFLAGS="-fPIC"
# La .so que upstream no construye. --whole-archive porque de una estática el linker sólo se lleva lo
# referenciado, y acá hay que llevárselo todo.
hammer-zig-cc -shared -o src/liblua-5.4.so.0.0.0 \
-Wl,-soname,liblua-5.4.so.0 \
-Wl,--whole-archive src/liblua.a -Wl,--no-whole-archive -lm
'''
install = '''
set -e
mkdir -p /out/usr/bin /out/usr/lib/pkgconfig /out/usr/include /out/usr/share/man/man1
install -m755 src/lua /out/usr/bin/lua5.4
install -m755 src/luac /out/usr/bin/luac5.4
ln -s lua5.4 /out/usr/bin/lua
ln -s luac5.4 /out/usr/bin/luac
install -m644 src/lua.h src/luaconf.h src/lualib.h src/lauxlib.h src/lua.hpp /out/usr/include/
install -m644 src/liblua.a /out/usr/lib/liblua-5.4.a
install -m755 src/liblua-5.4.so.0.0.0 /out/usr/lib/
ln -s liblua-5.4.so.0.0.0 /out/usr/lib/liblua-5.4.so.0
ln -s liblua-5.4.so.0 /out/usr/lib/liblua-5.4.so
ln -s liblua-5.4.so /out/usr/lib/liblua.so
cat > /out/usr/lib/pkgconfig/lua5.4.pc <<'PC'
prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
INTERPRETER=${exec_prefix}/bin/lua5.4
COMPILER=${exec_prefix}/bin/luac5.4
Name: Lua
Description: Lua language engine
Version: 5.4.8
Requires:
Libs: -L${libdir} -llua-5.4 -lm
Cflags: -I${includedir}
PC
# Las tres convenciones de nombre que se usan por ahí; wireplumber prueba lua-5.4, lua5.4 y lua54.
ln -s lua5.4.pc /out/usr/lib/pkgconfig/lua-5.4.pc
ln -s lua5.4.pc /out/usr/lib/pkgconfig/lua54.pc
ln -s lua5.4.pc /out/usr/lib/pkgconfig/lua.pc
'''
[deps]
build = ["make", "pkgconf"]
+36
View File
@@ -0,0 +1,36 @@
# pcre2-shared 10.47 — variante DINÁMICA (libpcre2-8.so.0, PIC) para el escritorio KDE.
# El canónico (recipes/pcre2.toml) es --disable-shared SIN --with-pic ⇒ su .a no enlaza dentro de un .so.
# Lo exige glib-shared (libglib-2.0.so linkea pcre2 para GRegex). Deuda Capa 0 (static↔dinámico).
#
# compiler=gcc igual que el canónico: su comentario advierte que zig-cc MISCOMPILA libs C (patrón file/jq);
# el gcc del rootfs es musl, y el .so resultante es ABI-compatible con los consumidores zig.
# --disable-symvers como el canónico (musl no maneja symbol versioning de la forma que asume pcre2).
name = "pcre2-shared"
version = "10.47"
[source]
tarball = "https://github.com/PhilipHazel/pcre2/releases/download/pcre2-10.47/pcre2-10.47.tar.bz2"
sha256 = "47fe8c99461250d42f89e6e8fdaeba9da057855d06eb7fc08d9ca03fd08d7bc7"
[build]
compiler = "gcc"
target = "x86_64-linux-musl"
link = "dynamic"
flags = []
[build.phases]
compile = '''
./configure \
--build=$CBUILD --host=$CHOST \
--prefix=/usr \
--enable-shared --disable-static \
--enable-pcre2-16 --enable-pcre2-32 \
--enable-jit \
--enable-pcre2grep-libz \
--disable-symvers
make -j"$(nproc)"
'''
install = "make DESTDIR=/out install && find /out -name '*.la' -delete"
[deps]
build = ["zlib-shared"]
+86
View File
@@ -0,0 +1,86 @@
# wireplumber 0.5.15 — EL GESTOR DE SESIÓN de PipeWire, en la variante de COSMIC.
#
# ── POR QUÉ EXISTE ESTA COPIA Y NO SE REUSA LA DE GNOME ─────────────────────────────────────────
# `recipes/incoming-gnome/wireplumber.toml` está sellada y funciona, pero su binario NEEDea
# `libglib-2.0.so.0`, `libgobject-2.0.so.0` y `libpipewire-0.3.so.0` **de la isla dinámica de GNOME**.
# Traerlo tal cual a la imagen de COSMIC significaría meter una segunda glib y una segunda pipewire —
# justo el choque de 370 ficheros solapados que la campaña midió y evitó.
#
# La regla del runbook es que copiar entre colas sale gratis **sólo si toda la clausura resuelve
# igual**. Acá NO resuelve igual, y eso es lo que se quiere: de las 19 deps, 14 dan hash idéntico y
# las que divergen divergen A PROPÓSITO —`pipewire` apunta a la de COSMIC (`338d1d8c`), que es la que
# el escritorio realmente ARRANCA. Un gestor de sesión contra otra pipewire que la que corre no
# gestiona nada.
#
# ── EL CAMBIO DE FONDO: `glib` → `glib-shared` ──────────────────────────────────────────────────
# COSMIC usa la `glib` ESTÁTICA del corpus (le sirve a `xdg-desktop-portal`, que es un ejecutable).
# Acá no alcanza: wireplumber produce `libwireplumber-0.5.so` y sus módulos, y la estática del corpus
# tiene **44.275 reubicaciones `R_X86_64_32/32S`** en `libglib-2.0.a` ⇒ no es PIC y no se puede
# enlazar dentro de un `.so`. (Regla del frente GNOME: `readelf -r` ANTES de gastar un build.)
#
# La salida no fue una campaña nueva sino una MEDICIÓN: `incoming-kde/glib-shared.toml` copiada acá
# resuelve al **mismo hash** (`0584ce1f`) y **ya está sellada** ⇒ cero rebuild. Idem `pcre2-shared`
# (`f254abaa`), `lua` (`e6c35f98`) y `libelogind` (`f1a690b2`), traídas por la misma razón: no existen
# en el catálogo padre y sus hashes coinciden con los de su cola de origen.
#
# ── LO QUE APORTA, Y POR QUÉ HACE FALTA ACÁ ─────────────────────────────────────────────────────
# `pipewire` se construye con `-Dsession-managers=[]`: arranca, acepta clientes y sirve —el portal ya
# figura como cliente suyo— pero **no hay política** de qué es entrada, qué es salida, ni quién mueve
# un nodo de `Paused` a `Streaming`. Y ahí está parado ScreenCast: el backend crea el nodo
# (`cosmic-screencast`, `Video/Source`, visible en `pw-cli ls Node`), su log dice
# `state-changed 'Connecting' -> 'Paused'`… y no emite el `Response`. La hipótesis a confirmar o
# matar con esta receta es que falta exactamente esto.
#
# La política está escrita EN LUA: embebe un intérprete (`lib/wplua`) y sus reglas viven en
# `src/scripts/*.lua`. Por eso la dep interesante no es PipeWire sino **`lua`**.
#
# `-Dsystem-lua=true` es obligatorio: por defecto usa su `subprojects/lua.wrap`, que **DESCARGA Lua
# 5.5 de lua.org**, y el sandbox va con `--wrap-mode=nodownload`. Con la perilla prendida busca por
# pkg-config `lua-5.5`/`lua5.5`/`lua55`, después las 5.4 y después las 5.3 (meson.build:91-95):
# nuestra `lua5.4.pc` entra por la segunda tanda.
#
# `-Delogind=enabled` — la C-ABI de logind otra vez, y acá la sirve `arje-sdlogin-compat`, el mismo
# shim que en el resto del fractal. wireplumber la usa para saber si la sesión está activa antes de
# tomar los dispositivos, que es justo el problema que ese shim resuelve.
#
# Apagados: `-Dsystemd=disabled` y sus units (PID1 es arje-zero y el arranque lo hace `cosmic-start`);
# `-Ddoc=disabled` (falta sphinx/doxygen); `-Dtests=false -Ddbus-tests=false`; `-Dintrospection=disabled`
# porque nadie carga `Wp-0.5` por typelib.
name = "wireplumber"
version = "0.5.15"
[source]
tarball = "https://gitlab.freedesktop.org/pipewire/wireplumber/-/archive/0.5.15/wireplumber-0.5.15.tar.gz"
sha256 = "baa121bc918df5fa0e0e70755bb1c99ffab0ab107225ecf99aa470e2c6ba5e7b"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "dynamic"
[build.phases]
# Sin `rm -rf output`: con el árbol de fuentes compartido (ADR 0012) borrar el dir de build es
# sabotear a quien esté compilando en paralelo. Lección heredada de la receta de GNOME.
configure = '''
set -e
PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output \
--prefix=/usr --buildtype=release --wrap-mode=nodownload \
-Ddefault_library=shared \
-Dsystem-lua=true -Dsystem-lua-version=auto \
-Delogind=enabled -Dsystemd=disabled \
-Dsystemd-system-service=false -Dsystemd-user-service=false \
-Dintrospection=disabled -Ddoc=disabled \
-Dtests=false -Ddbus-tests=false \
-Dc_args=-Wno-error=date-time
'''
compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
[deps]
# Difiere de la de GNOME en cuatro nombres, y los cuatro a propósito: `glib-shared` en vez de `glib`
# (la estática no es PIC), `pcre2-shared` en vez de `pcre2` (coherencia con lo que el `.pc` de
# glib-shared declara), y `pipewire`/`pulseaudio` que resuelven a los de ESTA cola — los que el
# escritorio arranca.
build = ["meson", "samurai", "python3", "pkgconf", "gettext-tiny", "lua", "pipewire",
"glib-shared", "dbus-shared", "libelogind", "alsa-lib", "libsndfile", "pulseaudio",
"expat", "pcre2-shared", "libffi", "libudev-zero", "zlib-shared"]
+28
View File
@@ -170,6 +170,34 @@ else
say "!! sin /usr/bin/pipewire — ScreenCast no va a poder crear stream"
fi
# ── EL GESTOR DE SESIÓN: wireplumber ────────────────────────────────────────────────────────────
# pipewire se construye con `-Dsession-managers=[]`, o sea que arranca y sirve pero NO TIENE
# POLÍTICA: nada decide qué es entrada, qué es salida, ni quién mueve un nodo de `Paused` a
# `Streaming`. wireplumber es esa política, escrita en Lua.
#
# Por qué está acá y no antes: **necesita el socket de pipewire ya abierto**. Se lanza después a
# propósito, no por orden estético — un gestor de sesión sin demonio que gestionar sale con error.
#
# Acá NO se puede esperar un socket, porque wireplumber no abre ninguno: es un CLIENTE de pipewire,
# no un servidor. Lo que dice que hizo su trabajo es que aparezca como cliente en el grafo
# (`pw-cli ls Client`), y eso es una medición del sistema, no una condición de arranque. Así que se
# espera un instante y se reporta si el proceso sigue vivo — con el log a mano, que es lo que sirve
# cuando falla.
if [ -x /usr/bin/wireplumber ] && [ -S "$XDG_RUNTIME_DIR/pipewire-0" ]; then
/usr/bin/wireplumber >/tmp/wireplumber.log 2>&1 &
WP_PID=$!
sleep 2
if alive $WP_PID; then
say "wireplumber OK (pid $WP_PID) — hay gestor de sesión"
else
say "!! wireplumber MURIÓ:"; dump /tmp/wireplumber.log
fi
elif [ -x /usr/bin/wireplumber ]; then
say "!! wireplumber presente pero sin socket de pipewire — no se lanza"
else
say "-- sin wireplumber (pipewire sirve, pero sin política de sesión)"
fi
# ── FONDO: color liso, porque la imagen por defecto NO SE PUEDE EMPAQUETAR ────────────────────
# El default de cosmic-bg apunta a `/usr/share/backgrounds/cosmic/orion_nebula_nasa_heic0601a.jpg`,
# que vive en el repo `cosmic-wallpapers`… en **git-lfs**: el tarball de GitHub pesa 20 KB y trae
+5
View File
@@ -84,6 +84,11 @@ else
# con el bus y el compositor vivos— y sale estática, sin un NEEDED, justamente para que nunca
# falle por algo del sistema que está midiendo.
recipes/incoming-cosmic/portal-probe.toml
# El GESTOR DE SESIÓN de pipewire. Ningún `[deps]` lo alcanza —es un cliente del demonio, no una
# librería de nadie— así que es raíz a mano como todo lo que se lanza por PATH. Trae consigo la
# glib COMPARTIDA (`glib-shared`), que no es la estática que usa el resto de la cola: wireplumber
# produce `.so` y la estática del corpus no es PIC.
recipes/incoming-cosmic/wireplumber.toml
recipes/incoming-cosmic/cosmic-app-library.toml
recipes/incoming-cosmic/cosmic-workspaces-epoch.toml
# Ni binario ni librería: DATOS. El tema de iconos de COSMIC — sin él el escritorio no se ve