`-DKCOREADDONS_USE_QML=OFF` estaba desde que se escribió la receta, con el argumento razonable de
que un framework tier-1 no debería arrastrar QML. El precio no se vio hasta hacer CLIC en el
lanzador dentro de QEMU: `kickoff` importa `org.kde.coreaddons` y ese módulo lo instala esta receta
y ninguna otra ⇒ **el menú de aplicaciones no abría**. La librería C++ salía completa, sus 70
consumidores enlazaban bien y el perfil reportaba 100%.
Es la forma más pura del «sellado ≠ arranca»: no falta una librería, falta una porción OPCIONAL de
una librería que sí está. Ninguna métrica de clausura puede verlo — mide recetas, no features.
`qtdeclarative` ya estaba en `[deps].build`, así que prenderlo no agrega una dep: deja de tirar lo
que ya se podía construir.
VERIFICADO CON UN SOLO BUILD (56 s), a propósito, en vez de pagar la cascada para averiguarlo:
· panel → menú abre (usuario, buscador, Favoritos/Todas, Aplicaciones/Lugares/Sesión)
· buscar «konsole» + Enter → la terminal arranca y corre:
uname -a → Linux (none) 6.16.12 #1 SMP PREEMPT_DYNAMIC … x86_64
konsole --version → konsole 25.04.3
Es la cadena completa del escritorio por primera vez: panel → menú → búsqueda → app → shell.
COSTO, medido antes de tocar y confirmado después: `yupana radio kcoreaddons` predijo 71, y el grafo
regenerado da exactamente **71 en deuda** (`escritorio-kde 192/263`). Queda como deuda DECLARADA
para una campaña de granja; la imagen de hoy corre con un kcoreaddons más nuevo que aquel contra el
que enlazaron sus consumidores, lo que es legítimo porque cruza un SONAME (misma ABI, sólo se suma
un módulo QML) — la misma regla que decidió la promoción de pipewire.
De yapa: `export SHELL=/bin/sh` en plasma-start-qemu.sh. El aviso rojo de konsole («Could not find
'', starting '/bin/sh' instead») era real y no venía de /etc/passwd —que dice /bin/sh— sino de que
konsole lee $SHELL y este getty no es un login shell.
Y el barrido que encuentra esto sin hacer clic queda escrito en el runbook: cruzar los `import` de
los `.qml` instalados contra los módulos con `qmldir`. Además de éste destapó `org.kde.kscreenlocker`
y `org.kde.newstuff.core`, sin diagnosticar.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGXe6mShYYw6V8ea1dQ13u
220 lines
12 KiB
Bash
220 lines
12 KiB
Bash
#!/bin/sh
|
|
# plasma-start-qemu.sh — arranca Plasma en una VM QEMU con render por SOFTWARE (kms_swrast/llvmpipe)
|
|
# sobre el DRM de virtio-gpu (/dev/dri/card0). Derivado de plasma-start-metal.sh pero SIN hardware iris:
|
|
# en QEMU no hay GPU real, así que kwin presenta por el DRM de virtio con EGL/GBM de software.
|
|
#
|
|
# Se instala como /usr/bin/plasma-start en la imagen QEMU y lo AUTO-LANZA /etc/profile (console-getty
|
|
# autologin). Trae los arreglos de la campaña KDE 2026-07: QT_QUICK_BACKEND=software (plasmashell no crea
|
|
# contexto GL sin él), QT_QPA_FONTDIR (mata los tofu; qtbase se construyó sin fontconfig), kdeglobals +
|
|
# QT_QPA_PLATFORMTHEME=kde (iconos + estilo Breeze), kactivitymanagerd (plasmashell aborta sin él).
|
|
#
|
|
# Logs: /tmp/{kwin,kamd,plasmashell}.log + tee a /dev/console. Salir: matar kwin.
|
|
set -u
|
|
# getty ejecuta este script DIRECTO (no vía login shell) ⇒ PATH viene vacío: mkdir/tr/cat/dbus-daemon
|
|
# no se hallan y kwin nunca levanta. Seteamos PATH explícito (busybox + userland KDE) ANTES de todo.
|
|
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
|
# tee a la consola gráfica (tty0) Y al serial (ttyS0) — el host captura ttyS0 con -serial file:
|
|
say() { echo "== plasma-qemu :: $*" | tee -a /dev/console /dev/ttyS0 2>/dev/null; }
|
|
dump() { echo "---- $1 ----" > /dev/ttyS0 2>/dev/null; cat "$1" > /dev/ttyS0 2>/dev/null; }
|
|
|
|
export LD_LIBRARY_PATH=/usr/lib64:/usr/lib/qt6:/usr/lib:/lib
|
|
export QT_PLUGIN_PATH=/usr/lib64/qt6/plugins:/usr/lib/qt6/plugins
|
|
export QML2_IMPORT_PATH=/usr/lib64/qt6/qml:/usr/lib/qt6/qml
|
|
export QML_IMPORT_PATH=$QML2_IMPORT_PATH
|
|
export XDG_DATA_DIRS=/usr/share
|
|
export XDG_RUNTIME_DIR=/run/user/0
|
|
export XDG_CONFIG_HOME=/root/.config
|
|
# konsole toma el intérprete de $SHELL, NO de /etc/passwd, y este getty no es un login shell ⇒ sin
|
|
# esto la terminal abre con «Warning: Could not find '', starting '/bin/sh' instead. Please check
|
|
# your profile settings.» en rojo. El shell caía bien de casualidad; el aviso era real.
|
|
export SHELL=/bin/sh
|
|
export XDG_CACHE_HOME=/root/.cache
|
|
export HOME=/root
|
|
|
|
# --- render por software sobre virtio-gpu ---
|
|
export LIBGL_ALWAYS_SOFTWARE=1
|
|
export GALLIUM_DRIVER=llvmpipe
|
|
# GBM_ALWAYS_SOFTWARE=1 — EL FIX del segfault (MURO 2, verificado en fuente mesa 24.0.9). virtio-gpu-pci
|
|
# SIN 3D expone un nodo KMS-only (no render-capable). Con MESA_LOADER_DRIVER_OVERRIDE solo, gbm carga
|
|
# kms_swrast pero deja gbm_dri->software=FALSE (dri_screen_create tiene éxito ⇒ nunca cae al fallback
|
|
# dri_screen_create_sw, el único que setea software=true). Entonces dri2_initialize_drm entra al bloque
|
|
# `if(!software)` y llama gbm_dri->mesa->queryCompatibleRenderOnlyDeviceFd() — NULL en el driver software
|
|
# ⇒ SIGSEGV. GBM_ALWAYS_SOFTWARE=1 fuerza dri_screen_create_sw ⇒ software=true ⇒ se salta ese bloque.
|
|
export GBM_ALWAYS_SOFTWARE=1
|
|
# kms_swrast (NO swrast): kwin abre card0 como dispositivo KMS y crea un gbm device sobre él ⇒ necesita
|
|
# el driver de software para KMS (dumb buffers). Con 'swrast' a secas gbm_create_device falla ("Failed
|
|
# to create gbm device"). kms_swrast_dri.so está en /usr/lib/dri.
|
|
export MESA_LOADER_DRIVER_OVERRIDE=kms_swrast
|
|
export LIBGL_DRIVERS_PATH=/usr/lib/dri
|
|
export QT_QUICK_BACKEND=software
|
|
# LP_NUM_THREADS=1: llvmpipe SINCRÓNICO (sin pool de threads del rasterizador) — el JIT multi-thread de
|
|
# llvmpipe segfaultea al componer la 1ra superficie en esta VM. KWIN_DRM_NO_AMS=1: desactiva atomic
|
|
# modesetting (algunos virtio-gpu lo rompen). Ambos son fixes conocidos de kwin/llvmpipe en VMs.
|
|
export LP_NUM_THREADS=1
|
|
# KWIN_DRM_NO_AMS (legacy modeset) fue una corazonada del segfault (que resultó ser GBM_ALWAYS_SOFTWARE).
|
|
# Dejamos atomic (virtio soporta atomic nativo; legacy es el frágil).
|
|
# export KWIN_DRM_NO_AMS=1
|
|
#
|
|
# EL FIX DEL NEGRO: virtio-gpu ADVIERTE soportar drmModeAddFB2WithModifiers pero RECHAZA el modifier
|
|
# explícito (aún LINEAR=0) con EINVAL ⇒ "Failed to create a framebuffer" ⇒ sin output layer ⇒ NEGRO.
|
|
# El modeset inicial usa un buffer dumb (sin modifiers) y SÍ pinta (por eso se ve el wallpaper un instante),
|
|
# pero los buffers del compositor van por AddFB2WithModifiers y fallan ⇒ vuelve a negro. KWIN_DRM_USE_MODIFIERS=0
|
|
# fuerza a kwin a usar drmModeAddFB2 plano (modifier implícito) que virtio-gpu sí acepta.
|
|
export KWIN_DRM_USE_MODIFIERS=0
|
|
# KWIN_COMPOSE=Q — compositor QPainter (raster de Qt directo al buffer, SIN escena llvmpipe). El
|
|
# compositor GL por defecto usa el rasterizador de llvmpipe, cuyo hilo SEGFAULTEA en lp_rast_clear_color
|
|
# → util_fill_rect al limpiar el color buffer (backtrace del core.llvmpipe-0): kwin pinta unos frames y
|
|
# muere → "vuelve a negro". QPainter no arma escenas llvmpipe ⇒ esquiva ese crash. (El segfault viejo con
|
|
# =Q era el de gbm-init, ya resuelto por GBM_ALWAYS_SOFTWARE.) llvmpipe sigue disponible para gbm/EGL.
|
|
export KWIN_COMPOSE=Q
|
|
export QT_QPA_PLATFORM=wayland
|
|
export QT_QPA_PLATFORMTHEME=kde
|
|
export QT_QPA_FONTDIR=/usr/share/fonts/dejavu
|
|
# cursor: kwin busca el tema "default" y no lo halla ("Failed to load cursor theme") ⇒ cursor invisible.
|
|
# Apuntamos al breeze_cursors del rootfs (115 cursores) por env + kcminputrc (kwin lee [Mouse] cursorTheme).
|
|
export XCURSOR_THEME=breeze_cursors
|
|
export XCURSOR_PATH=/usr/share/icons:/usr/share/pixmaps
|
|
export XCURSOR_SIZE=24
|
|
# El tema ya carga (sin "Failed to load cursor theme") pero el cursor SIGUE invisible: kwin usa el plano
|
|
# de cursor por HARDWARE del DRM, y en virtio-gpu con render software ese plano no se presenta (aparece y
|
|
# desaparece). KWIN_FORCE_SW_CURSOR=1 ⇒ kwin dibuja el cursor DENTRO del framebuffer principal (software)
|
|
# ⇒ visible y estable en VMs sin GPU real.
|
|
export KWIN_FORCE_SW_CURSOR=1
|
|
|
|
# --- DIAGNÓSTICO del segfault-al-1er-composite (MURO 2) ---
|
|
# Sin gdb en la imagen: subimos el logging categorizado de kwin (kwin_core/drm/scene/opengl) + mesa/egl
|
|
# para ver EN QUÉ FASE muere (bind EGL, alloc GBM, JIT llvmpipe, o el paint real). DIAG=0 para apagarlo.
|
|
if [ "${DIAG:-1}" = 1 ]; then
|
|
export QT_LOGGING_RULES="kwin_*=true;qt.qpa.*=true"
|
|
export EGL_LOG_LEVEL=debug
|
|
export LIBGL_DEBUG=verbose
|
|
export MESA_DEBUG=1
|
|
export GALLIUM_HUD= # no HUD, sólo para dejar constancia
|
|
export KWIN_DRM_DEBUG=1
|
|
fi
|
|
|
|
mkdir -p "$XDG_RUNTIME_DIR" "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" /run/dbus /root
|
|
chmod 700 "$XDG_RUNTIME_DIR"
|
|
[ -s /etc/machine-id ] || cat /proc/sys/kernel/random/uuid 2>/dev/null | tr -d - > /etc/machine-id
|
|
|
|
# kdeglobals: iconos + estilo Breeze (sin esto Qt cae a hicolor vacío = escritorio pelado)
|
|
cat > "$XDG_CONFIG_HOME/kdeglobals" <<EOF
|
|
[Icons]
|
|
Theme=breeze
|
|
|
|
[General]
|
|
ColorScheme=BreezeLight
|
|
widgetStyle=Breeze
|
|
|
|
[KDE]
|
|
widgetStyle=Breeze
|
|
EOF
|
|
|
|
# kcminputrc: el tema de cursor que kwin lee al arrancar (además del env XCURSOR_THEME)
|
|
cat > "$XDG_CONFIG_HOME/kcminputrc" <<EOF
|
|
[Mouse]
|
|
cursorTheme=breeze_cursors
|
|
cursorSize=24
|
|
EOF
|
|
|
|
say "GPU DRM: $(ls /dev/dri/ 2>/dev/null | tr '\n' ' ')"
|
|
[ -e /dev/dri/card0 ] || say "!! no hay /dev/dri/card0 — ¿virtio-gpu no cargó? (dmesg | grep -i drm)"
|
|
|
|
# D-Bus de SISTEMA: sin él, kf.solid/udisks2 spamea "Not connected to D-Bus server" y powerdevil + los
|
|
# applets de dispositivos/energía no inician. Escucha en el path estándar /run/dbus/system_bus_socket
|
|
# (los clientes lo hallan por DBUS_SYSTEM_BUS_ADDRESS por defecto ⇒ no exportamos nada). Corre como root
|
|
# y hace setuid a messagebus (uid 81, sembrado en el passwd de la imagen). No hay udisksd/upowerd reales
|
|
# en el rootfs ⇒ no habrá discos/batería, pero el bus existe y solid deja de errorear en cada poll.
|
|
mkdir -p /run/dbus /var/lib/dbus
|
|
cp -f /etc/machine-id /var/lib/dbus/machine-id 2>/dev/null || true
|
|
if [ ! -S /run/dbus/system_bus_socket ]; then
|
|
if dbus-daemon --system --fork 2>/tmp/dbus-system.log; then
|
|
say "system bus ON (/run/dbus/system_bus_socket)"
|
|
else
|
|
say "!! system bus NO arrancó:"; dump /tmp/dbus-system.log
|
|
fi
|
|
fi
|
|
|
|
# D-Bus de sesión
|
|
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
|
|
DBUS_SESSION_BUS_ADDRESS=$(dbus-daemon --session --fork --print-address 2>/dev/null)
|
|
export DBUS_SESSION_BUS_ADDRESS
|
|
fi
|
|
say "dbus: ${DBUS_SESSION_BUS_ADDRESS:-NO ARRANCO}"
|
|
|
|
# --- CORE DUMP del segfault (MURO 2): sin gdb en la imagen, sacamos un core y lo leemos con el gdb del
|
|
# host apuntando al rootfs fundido. Localiza el frame culpable (libLLVM/llvmpipe vs kwin vs mesa). ---
|
|
if [ "${DIAG:-1}" = 1 ]; then
|
|
ulimit -c unlimited 2>/dev/null || true
|
|
# /core en la RAÍZ ext4 (NO /tmp: es tmpfs=RAM y se pierde al matar QEMU). Tras el crash hacemos sync
|
|
# explícito ⇒ el core persiste en la imagen aunque después mate QEMU con SIGKILL.
|
|
echo '/core.%e.%p' > /proc/sys/kernel/core_pattern 2>/dev/null || true
|
|
say "core dumps ON (pattern=$(cat /proc/sys/kernel/core_pattern 2>/dev/null), ulimit -c=$(ulimit -c))"
|
|
fi
|
|
|
|
# SÓLO el card de virtio-gpu: el efifb/simpledrm sobrevive como 2º DRM ("Unknown-1", read-only) y kwin
|
|
# intenta manejar ambos outputs ⇒ conflicto de presentación ⇒ pinta y vuelve a NEGRO. Detectamos el card
|
|
# cuyo driver es virtio_gpu (robusto al numerado card0/card1 que cambia entre boots) y se lo pasamos a kwin.
|
|
VIRTIO_CARD=
|
|
for c in /dev/dri/card*; do
|
|
n=$(basename "$c")
|
|
drv=$(readlink -f "/sys/class/drm/$n/device/driver" 2>/dev/null)
|
|
case "$drv" in *virtio*) VIRTIO_CARD="$c"; break;; esac
|
|
done
|
|
if [ -n "$VIRTIO_CARD" ]; then
|
|
export KWIN_DRM_DEVICES="$VIRTIO_CARD"
|
|
say "KWIN_DRM_DEVICES=$VIRTIO_CARD (ignorando efifb/simpledrm)"
|
|
else
|
|
say "!! no hallé card virtio_gpu; kwin verá todos los DRM (posible doble output)"
|
|
fi
|
|
|
|
# Compositor sobre el DRM de virtio (software EGL/GBM vía kms_swrast). SIN --virtual: presenta al display.
|
|
say "lanzando kwin_wayland (DRM virtio, software GL)..."
|
|
/usr/bin/kwin_wayland --drm >/tmp/kwin.log 2>&1 &
|
|
KWIN=$!
|
|
# stream EN VIVO del kwin.log al serial (busybox sed NO soporta -u ⇒ nada de sed/pipes: tail -f directo).
|
|
( echo "==== kwin.log (stream vivo) ===="; tail -f /tmp/kwin.log ) > /dev/ttyS0 2>/dev/null &
|
|
TAILPID=$!
|
|
i=0
|
|
while [ $i -lt 60 ]; do
|
|
[ -S "$XDG_RUNTIME_DIR/wayland-0" ] && break
|
|
kill -0 $KWIN 2>/dev/null || { say "!! kwin murio:"; dump /tmp/kwin.log; exec /bin/sh; }
|
|
i=$((i+1)); sleep 0.5
|
|
done
|
|
if [ -S "$XDG_RUNTIME_DIR/wayland-0" ]; then
|
|
say "compositor OK (wayland-0)"
|
|
else
|
|
say "!! kwin no expuso wayland-0:"; dump /tmp/kwin.log; exec /bin/sh
|
|
fi
|
|
export WAYLAND_DISPLAY=wayland-0
|
|
|
|
# kactivitymanagerd: plasmashell ABORTA sin el
|
|
KAMD=$(ls /usr/lib*/libexec/kactivitymanagerd 2>/dev/null | head -1)
|
|
[ -n "$KAMD" ] && { "$KAMD" >/tmp/kamd.log 2>&1 & sleep 2; say "kactivitymanagerd lanzado"; }
|
|
|
|
say "lanzando plasmashell..."
|
|
/usr/bin/plasmashell >/tmp/plasmashell.log 2>&1 &
|
|
sleep 8
|
|
say "procesos: $(ps axo comm 2>/dev/null | grep -E 'kwin|plasma' | sort -u | tr '\n' ' ')"
|
|
say "escritorio arriba (o mira /tmp/plasmashell.log). Ctrl-C mata la sesion."
|
|
dump /tmp/plasmashell.log
|
|
# monitor de estado: cada 15s dice si kwin/plasmashell siguen vivos ⇒ si vuelve a negro, sabremos si
|
|
# fue plasmashell que murió (containment) o kwin/output. (busybox pgrep -c cuenta procesos.)
|
|
( n=0; while sleep 15; do
|
|
n=$((n+1))
|
|
say "STATUS +$((n*15))s: kwin=$(pgrep kwin_wayland 2>/dev/null | wc -l) plasmashell=$(pgrep plasmashell 2>/dev/null | wc -l)"
|
|
done ) &
|
|
wait $KWIN
|
|
RC=$?
|
|
# kwin salió ⇒ volcá su log para saber por qué (backend QPainter, DRM, modeset…)
|
|
say "kwin salió (código $RC) — volcando kwin.log:"
|
|
dump /tmp/kwin.log
|
|
# copiar los logs a la ext4 raíz y SYNC ⇒ core + logs persisten en la imagen para leer desde el host
|
|
# con debugfs/gdb (el SIGKILL de QEMU no sincroniza; sin este sync se pierde todo lo de esta sesión).
|
|
cp /tmp/kwin.log /kwin.log 2>/dev/null || true
|
|
cp /tmp/plasmashell.log /plasmashell.log 2>/dev/null || true
|
|
say "cores en /: $(ls -la /core.* 2>/dev/null | tr '\n' ' ' || echo NINGUNO)"
|
|
sync; sync
|
|
say "== disco SYNCED (core+logs en la raíz). serial CONGELADO. matá QEMU desde el host. =="
|
|
sleep 3600
|