kde/Plasma: hito H-QML PASADO — hidratación FHS del cierre runtime + reproducer QML
- repo-selfcontain.py: work/repo-kde auto-contenido (alias qt-corto→qt6-* + cierre base desde dist/repo), re-firmado 884 pkgs, repo verify trusted. - hydrate-fhs.sh: hidrata el cierre runtime instalando cada pkg del cierre en el mismo prefix (install --prefix sólo baja el pkg pedido); 32 pkgs → work/kde-rootfs, 455 .so (libQt6Core/Gui/Qml/Quick + QPA offscreen + mesa/xcb/wayland/openssl). - h-qml-run.sh + h-qml-test.cpp: QQmlApplicationEngine carga QtQuick Window+Text, compila zig-cc/musl contra el FHS, corre offscreen rc=0 (engine instancia el árbol QML). - ADR 0011: sección resultado H-QML + deudas (target_bin espurio en libs, cache-miss por re-resolución de deps → qtbase más completo con SSL, fuentes). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
# h-qml-run.sh — VALIDA el hito H-QML (ADR 0011, Capa 1) contra el FHS hidratado desde el repo firmado.
|
||||
# Compila scripts/kde/h-qml-test.cpp (QQmlApplicationEngine + QtQuick Window/Text) con zig-cc/musl
|
||||
# contra work/kde-rootfs y lo corre con QT_QPA_PLATFORM=offscreen vía el loader musl del .dev-fs.
|
||||
# Pensado para correr EN EL WORKER (host glibc + rootfs musl). Prerequisito: hydrate-fhs.sh ya hidrató
|
||||
# el cierre runtime de qt6-qtdeclarative en work/kde-rootfs.
|
||||
#
|
||||
# Éxito = "H-QML: QML instanciado" + "event loop terminó rc=0".
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
|
||||
R="${RFS:-$ROOT/work/kde-rootfs}"
|
||||
ZIG="${ZIG:-$ROOT/.dev-fs/tools/zig-x86_64-linux-0.13.0/zig}"
|
||||
LOADER="${LOADER:-$ROOT/.dev-fs/alpine/lib/ld-musl-x86_64.so.1}"
|
||||
A="$ROOT/.dev-fs/alpine"
|
||||
BIN="${BIN:-/tmp/h-qml}"
|
||||
I="$R/usr/include/qt6"
|
||||
|
||||
echo "==> compilando h-qml-test.cpp (zig-cc/musl) contra $R"
|
||||
"$ZIG" c++ -std=c++17 -target x86_64-linux-musl -mcpu=baseline -fPIC \
|
||||
scripts/kde/h-qml-test.cpp -o "$BIN" \
|
||||
-I"$I" -I"$I/QtCore" -I"$I/QtGui" -I"$I/QtQml" \
|
||||
-L"$R/usr/lib" -lQt6Qml -lQt6Gui -lQt6Core
|
||||
|
||||
echo "==> corriendo H-QML (offscreen)"
|
||||
LIBS="$R/usr/lib:$R/usr/lib/qt6:$A/usr/lib:$A/lib"
|
||||
QT_QPA_PLATFORM=offscreen QT_QUICK_BACKEND=software \
|
||||
QT_PLUGIN_PATH="$R/usr/lib/qt6/plugins" \
|
||||
QML_IMPORT_PATH="$R/usr/lib/qt6/qml" QML2_IMPORT_PATH="$R/usr/lib/qt6/qml" \
|
||||
"$LOADER" --library-path "$LIBS" "$BIN"
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
# hydrate-fhs.sh — hidrata un FHS runtime KDE desde el repo firmado, instalando el CIERRE completo.
|
||||
#
|
||||
# `hammer install <pkg> --prefix P` sólo hidrata los archivos de <pkg>, NO de su cierre. Para un
|
||||
# rootfs runtime usable (que capture todas las `.so`), hay que instalar cada paquete del cierre en el
|
||||
# MISMO prefix (igual que product-userland-from-repo.sh). El store del worker está caliente ⇒ cache-hit.
|
||||
#
|
||||
# Las recetas de LIBS KDE declaran `target_bin=/usr/bin/<pkg>` que no existe (son libs, no binarios):
|
||||
# `install` hidrata los ficheros y LUEGO falla la aserción con exit 1. Lo toleramos: contamos éxito si
|
||||
# el paquete dejó ficheros en el prefix.
|
||||
#
|
||||
# Uso: TARGET=qt6-qtdeclarative ./hydrate-fhs.sh (default)
|
||||
set -uo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
|
||||
REPO="${REPO:-work/repo-kde}"; TRUST="${TRUST:-dist/keys}"; STORE="${STORE:-./store}"
|
||||
RFS="${RFS:-work/kde-rootfs}"; TARGET="${TARGET:-qt6-qtdeclarative}"
|
||||
HAMMER="${HAMMER:-./target/release/hammer}"
|
||||
DB="$RFS/var/lib/hammer/installed.json"
|
||||
|
||||
# cierre transitivo del TARGET, leído del índice (deps + aliases ya resuelven). Excluimos herramientas
|
||||
# puramente de build (no aportan runtime) para acelerar; si algo falta lo delata ldd.
|
||||
CLOSURE=$(python3 - "$REPO/index.json" "$TARGET" <<'PY'
|
||||
import json,sys
|
||||
idx=json.load(open(sys.argv[1])); tgt=sys.argv[2]
|
||||
by={p['name']:p for p in idx['packages']}
|
||||
BUILD_ONLY={'cmake','samurai','meson','ninja','bison','flex','gperf','util-macros','xorgproto',
|
||||
'xcb-proto','wayland-protocols','pkgconf','mako','markupsafe','packaging','python3','extra-cmake-modules',
|
||||
'qttools','qt6-qttools'}
|
||||
# alias qt-corto -> qt6-*
|
||||
def canon(n):
|
||||
return n if n in by else ('qt6-'+n if 'qt6-'+n in by else n)
|
||||
seen=set(); order=[]
|
||||
def visit(n):
|
||||
n=canon(n)
|
||||
if n in seen or n not in by: return
|
||||
seen.add(n)
|
||||
for d in by[n].get('deps',[]): visit(d)
|
||||
order.append(n)
|
||||
visit(tgt)
|
||||
for n in order:
|
||||
if n not in BUILD_ONLY: print(n)
|
||||
PY
|
||||
)
|
||||
|
||||
mkdir -p "$(dirname "$DB")"
|
||||
echo "==> hidratando cierre runtime de $TARGET → $RFS ($(echo "$CLOSURE"|wc -w) pkgs)"
|
||||
ok=0; fail=0
|
||||
for pkg in $CLOSURE; do
|
||||
before=$(find "$RFS" -type f 2>/dev/null | wc -l)
|
||||
NO_PROXY=localhost NIX_STORE="${NIX_STORE:-$HOME/.nixstore}" \
|
||||
"$HAMMER" --store "$STORE" install "$pkg" --repo "$REPO" --prefix "$RFS" \
|
||||
--trust "$TRUST" --require-signed --db "$DB" >"$RFS/.h-$pkg.log" 2>&1
|
||||
rc=$?
|
||||
after=$(find "$RFS" -type f 2>/dev/null | wc -l)
|
||||
if [ "$after" -gt "$before" ] || grep -q "hidratados" "$RFS/.h-$pkg.log"; then
|
||||
printf " ✓ %-22s (+%s ficheros%s)\n" "$pkg" "$((after-before))" \
|
||||
"$([ $rc -ne 0 ] && echo ', target_bin tolerado')"
|
||||
ok=$((ok+1))
|
||||
else
|
||||
printf " ✗ %-22s rc=%s (ver %s)\n" "$pkg" "$rc" "$RFS/.h-$pkg.log"; fail=$((fail+1))
|
||||
fi
|
||||
done
|
||||
echo "==> $ok hidratados, $fail fallaron; .so totales: $(find "$RFS" -name '*.so*'|wc -l)"
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""repo-selfcontain.py — vuelve el repo KDE AUTO-CONTENIDO para hidratar por `install`.
|
||||
|
||||
`install` lee los `depends` del recipe embebido en cada `.swm` y resuelve cada nombre como
|
||||
CLAVE del índice. El repo KDE cosechado (work/repo-kde) no cierra:
|
||||
1. deps a nombres de receta-archivo qt-cortos (`qtbase`) cuando el paquete es `qt6-qtbase`.
|
||||
2. faltan libs base del cierre (libffi/libpng/gperf/mako/markupsafe/packaging y su cierre).
|
||||
|
||||
Este script, SIN re-buildear nada:
|
||||
- trae de dist/repo (repo base firmado, cierre completo) todo paquete cuyo nombre no esté ya
|
||||
en el repo KDE (colisión → gana la versión KDE), copiando su `.swm`.
|
||||
- agrega entradas ALIAS qt-corto→qt6-* (mismo `.swm`, otra clave de índice).
|
||||
El índice resultante se re-firma aparte con `hammer repo sign`.
|
||||
"""
|
||||
import json, shutil, sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
KDE = ROOT / "work/repo-kde"
|
||||
BASE = ROOT / "dist/repo"
|
||||
|
||||
kde_idx = json.loads((KDE / "index.json").read_text())
|
||||
base_idx = json.loads((BASE / "index.json").read_text())
|
||||
|
||||
kde_pkgs = kde_idx["packages"]
|
||||
kde_names = {p["name"] for p in kde_pkgs}
|
||||
base_by_name = {p["name"]: p for p in base_idx["packages"]}
|
||||
|
||||
added_base, copied, aliases = [], 0, []
|
||||
|
||||
# 1) traer del repo base todo lo que el KDE no tenga (colisión → gana KDE)
|
||||
for name, entry in base_by_name.items():
|
||||
if name in kde_names:
|
||||
continue
|
||||
src = BASE / entry["file"]
|
||||
if not src.exists():
|
||||
continue
|
||||
dst = KDE / entry["file"]
|
||||
if not dst.exists():
|
||||
shutil.copy2(src, dst); copied += 1
|
||||
kde_pkgs.append(entry)
|
||||
kde_names.add(name)
|
||||
added_base.append(name)
|
||||
|
||||
# 2) aliases qt-corto → qt6-* (misma .swm, clave de índice distinta)
|
||||
by_name = {p["name"]: p for p in kde_pkgs}
|
||||
for p in list(kde_pkgs):
|
||||
n = p["name"]
|
||||
if n.startswith("qt6-qt"):
|
||||
short = n[len("qt6-"):] # qt6-qtbase -> qtbase
|
||||
if short not in kde_names:
|
||||
alias = dict(p); alias["name"] = short
|
||||
kde_pkgs.append(alias); kde_names.add(short); aliases.append(short)
|
||||
|
||||
kde_idx["packages"] = kde_pkgs
|
||||
(KDE / "index.json").write_text(json.dumps(kde_idx, indent=None))
|
||||
|
||||
print(f"base traídos: {len(added_base)} ({copied} .swm copiados)")
|
||||
print(f"aliases qt: {len(aliases)} -> {' '.join(sorted(aliases))}")
|
||||
print(f"total índice: {len(kde_pkgs)} entradas")
|
||||
|
||||
# 3) chequeo de cierre: cada dep declarado en el índice ahora resuelve
|
||||
missing = set()
|
||||
for p in kde_pkgs:
|
||||
for d in p.get("deps", []):
|
||||
if d not in kde_names:
|
||||
missing.add(d)
|
||||
print(f"deps del índice sin resolver: {len(missing)} {sorted(missing) if missing else ''}")
|
||||
Reference in New Issue
Block a user