qemu: receta completa y BLOQUEADA — el muro es del corpus, no de qemu
Entra para cerrar «virtualización», que el censo marca 3 de 3 ausente con el
argumento entero en su comentario: «ni invitado ni anfitrión: no se puede probar
la propia ISO sin salir». Este proyecto genera imágenes y las prueba en QEMU
DESDE FUERA.
Queda commiteada SIN construir, con el rastro medido, porque lo que falta es una
decisión con presupuesto y no un ajuste de perillas.
Lo que SÍ quedó resuelto y sirve tal cual:
· --without-default-features: su meson.build son 5.072 líneas y nombra docenas
de deps (gnutls, libssh, capstone, libdw, epoxy…) que un grep ingenuo lista
como obligatorias — TODAS cuelgan de un if get_option(). Con esa perilla las
deps reales son glib, pixman, ncurses, zlib y libslirp, todas en el corpus
· libslirp como receta propia: desde qemu 7.2 la pila slirp dejó de venir
incluida, y sin ella `-netdev user` no existe
· instalar el wheel vendorizado de qemu.qmp descomprimiéndolo en site-packages
(su layout ES el de instalación, con .dist-info real) ⇒ mkvenv lo acepta
como paquete del sistema y no sale a la red
· quitar de [tooling] las tres entradas de cortesía (setuptools/wheel/pip),
cuyo propio comentario upstream dice «merely a sanity check»
EL MURO, medido: [tooling] también trae "qemu" = { path = "python/" }, así que
pip debe preparar el paquete propio de qemu con el gancho PEP 517, y eso revienta:
Preparing editable metadata (pyproject.toml) did not run successfully.
AttributeError: 'Distribution' object has no attribute 'entry_points'
…/site-packages/setuptools/config/setupcfg.py:285
py3-setuptools (y mi py3-pip) COPIAN el árbol del paquete a site-packages — no
son instalaciones: sin .dist-info, sin metadatos de entry_points, con el shim de
distutils a medias. Para IMPORTAR alcanza; para que setuptools actúe como backend
de build de otro paquete, no.
⇒ Haría falta que py3-setuptools fuera una instalación de verdad. Y eso cuesta:
tiene 31 consumidores en incoming-gnome, así que cambiar su contenido cambia su
hash y el de todos ellos — la cascada que la promoción había evitado. Pagarla es
decisión del operador.
⚠ Y lo que NO hay que hacer: fabricar un .dist-info a mano. Resolvería la
DETECCIÓN pero no este muro, porque acá setuptools tiene que ejecutar de verdad.
Sería un verde falso de los que este repo persigue.
Delta semántico
Ninguna definición cambió: el cambio es de texto, documentación o datos.
1 archivos · +278 −0
- recipes/qemu.toml +278 −0
diff --git a/recipes/qemu.toml b/recipes/qemu.toml
new file mode 100644
index 00000000..9dba7e01
--- /dev/null
+++ b/recipes/qemu.toml
@@ -0,0 +1,278 @@
+# ⛔ **BLOQUEADA — NO CONSTRUYE TODAVÍA. El muro es del CORPUS, no de qemu.**
+#
+# Esta receta queda commiteada con todo el rastro medido porque el diagnóstico vale y porque lo que
+# falta es una decisión con presupuesto, no un ajuste de perillas. Seis vueltas de `configure`, cada
+# una descartando una hipótesis con una medición:
+#
+# 1. «el venv necesita red» → NO: `python3` trae `venv` y `ensurepip` con su wheel de
+# pip, así que el venv se crea offline
+# 2. «falta setuptools» → lo promoví del corpus, y GRATIS (0 de 92 hashes). Falló igual
+# 3. «falta pip importable» → escribí `py3-pip`; medido DENTRO del sandbox,
+# `find_spec` da True para los dos. Falló igual
+# 4. «falta qemu.qmp» → ✅ correcto: descomprimir su wheel vendorizado lo satisfizo
+# 5. «quedan 3 entradas de cortesía» → ✅ correcto: `[tooling]` trae setuptools/wheel/pip con
+# sólo `accepted`, detectadas por `importlib.metadata`
+# 6. el muro de verdad ⇓
+#
+# ══ EL MURO: EL CORPUS NO TIENE PAQUETES DE PYTHON *INSTALADOS*, TIENE DIRECTORIOS COPIADOS ═════
+# `[tooling]` incluye `"qemu" = { path = "python/" }`: pip tiene que preparar el paquete propio de
+# qemu con el gancho PEP 517, y eso revienta así:
+#
+# Preparing editable metadata (pyproject.toml) did not run successfully.
+# AttributeError: 'Distribution' object has no attribute 'entry_points'
+# …/site-packages/setuptools/config/setupcfg.py:285
+#
+# `py3-setuptools` (y mi `py3-pip`) **copian el árbol del paquete** a `site-packages` — no son
+# instalaciones: no hay `.dist-info`, no hay metadatos de `entry_points`, y el shim de distutils
+# queda a medias. Para importar basta; para que setuptools actúe como **backend de build de otro
+# paquete**, no.
+#
+# ⇒ Lo que haría falta es que `py3-setuptools` sea una instalación de verdad (con su `.dist-info`).
+# **Y eso cuesta**: la receta vive en el corpus con **31 consumidores en `incoming-gnome`**, así que
+# cambiar su contenido cambia su hash y el de todos ellos. Es exactamente la cascada que la
+# promoción había evitado, y decidir pagarla es del operador.
+#
+# ⚠ Lo que NO hay que hacer: fabricar un `.dist-info` a mano para que `importlib.metadata` conteste.
+# Resolvería la detección (punto 5) y **no** este muro, porque acá setuptools tiene que ejecutar de
+# verdad. Sería un verde falso de los que este repo persigue.
+#
+# Todo lo demás de esta receta está medido y sirve tal cual el día que eso se destrabe: las perillas,
+# el porqué de `--without-default-features`, la instalación del wheel vendorizado y el parche de
+# `pythondeps.toml`.
+#
+# qemu 11.1.2 — la máquina virtual. Con esto la distro puede ARRANCAR SUS PROPIAS IMÁGENES.
+#
+# ══ POR QUÉ ENTRA, Y POR QUÉ IMPORTA MÁS ACÁ QUE EN OTRA DISTRO ════════════════════════════════
+# `censo-distro.py` marcaba «virtualización» **3 de 3 ausente**, y su comentario es el argumento
+# entero: «ni invitado ni anfitrión: **no se puede probar la propia ISO sin salir**».
+#
+# Este proyecto genera imágenes de disco y perfiles de escritorio, y las prueba en QEMU **desde
+# fuera** — hay memorias enteras sobre arrancar los escritorios en QEMU en otra máquina. O sea que
+# la distro dependía de un anfitrión ajeno para verificarse a sí misma. Con esta receta, el bucle
+# «construir imagen → arrancarla → mirarla» se cierra adentro.
+#
+# ══ ⚠ `--without-default-features` ES LA CLAVE DE QUE ESTO SEA UNA RECETA Y NO UNA CAMPAÑA ══════
+# El `meson.build` de qemu son **5.072 líneas** y nombra docenas de `dependency()`: gnutls, libssh,
+# libnfs, libiscsi, capstone, libcbor, libdw, libcurl, libgcrypt, epoxy, blkio, igvm, selinux,
+# pipewire… Ninguna de ellas es obligatoria: **todas cuelgan de un `if get_option(...)`**, y un grep
+# ingenuo las lista como si lo fueran (lo hice, y daba 20 deps falsas).
+#
+# La perilla que lo resuelve es de qemu y está para esto: `--without-default-features`
+# (`configure:244`) apaga TODO lo opcional, y después se enciende a mano sólo lo que esta distro
+# necesita. Con eso las deps reales son `glib`, `pixman`, `ncurses`, `zlib` y `libslirp` — todas en
+# el corpus.
+#
+# ══ LO QUE SE ENCIENDE, Y PARA QUÉ SIRVE CADA COSA ═════════════════════════════════════════════
+# --target-list=x86_64-softmmu un solo objetivo. Emular un MIPS o un ARM es otra decisión; esto
+# es para arrancar NUESTRAS imágenes, que son x86-64
+# --enable-slirp red sin privilegios (`-netdev user`). ⚠ Desde qemu 7.2 la pila
+# slirp **dejó de venir incluida**: sin `recipes/libslirp.toml` la
+# única red sería `tap`, que pide root y un puente. Ver esa receta
+# --enable-tools `qemu-img` y `qemu-nbd`: crear, convertir y montar las imágenes.
+# Sin esto hay emulador y nada con qué preparar un disco
+# --enable-curses ver la VM **en la terminal** (`-display curses`). En una caja sin
+# escritorio —que es donde se construye— esto es lo que de verdad
+# se usa
+# --enable-vnc la otra forma de mirarla, desde otra máquina
+# --enable-pixman lo piden curses y vnc para el framebuffer
+# --enable-kvm aceleración por hardware. ⚠ Es de COMPILACIÓN: en `gioser` no hay
+# `/dev/kvm` (es un vServer, está medido en la memoria del repo) y
+# qemu cae a TCG solo. Se enciende porque en metal —el objetivo
+# `metal-tigerlake`— sí lo hay, y apagarlo lo haría imposible allí
+# --disable-docs sphinx no está en el corpus
+#
+# ══ ⚠ EL VENV DE PYTHON: COMPROBADO ANTES, NO DESPUÉS ══════════════════════════════════════════
+# El `configure` de qemu crea un entorno virtual de Python (`mkvenv.py create pyvenv`,
+# `configure:940`) y «llama a `ensurepip` como respaldo cuando hace falta». En un sandbox sin red eso
+# es un fallo esperando. Medido antes de lanzar: nuestro `python3` trae `venv`, `ensurepip` **con el
+# wheel `pip-25.0.1` incluido** y `tomllib` — o sea que el venv se crea **offline**. Si algún día el
+# `python3` del corpus se construye sin `ensurepip`, esta receta se cae y la causa está acá escrita.
+#
+# ⚠⚠ **PERO COMPROBAR EL VENV NO ALCANZÓ, Y ÉSTE FUE EL MURO REAL.** El venv se crea bien y después
+# el configure hace, LITERALMENTE sin condición:
+#
+# # Unconditionally install our tooling group.
+# $mkvenv ensuregroup … pythondeps.toml tooling || exit 1 (configure:988)
+#
+# y el grupo `[tooling]` es `"qemu.qmp" = {…}`. qemu **vendoriza** ese wheel —`python/wheels/` trae
+# `qemu_qmp`, `meson` y `pycotap`— pero para instalarlo pip arranca su trío de bootstrap y murió así:
+#
+# ERROR: Could not find a version that satisfies the requirement setuptools>=44.1.1
+# (from versions: none)
+#
+# El `site-packages` de nuestro `python3` está **vacío** (sólo un README), y no hay red. **No hay
+# perilla**: `--without-default-features` no toca esto, y el grupo `tooling` es incondicional.
+#
+# ⇒ Entra `py3-setuptools`, **y promoverlo salió GRATIS** — medido, no supuesto: la receta ya existía
+# en `incoming-gnome`, 31 recetas de esa cola dependen de ella, y moverla al corpus cambió **0 de 92
+# hashes**. Razón: su única dep es `python3` (runtime), que resuelve al del corpus desde los dos
+# sitios, así que ni su hash ni los de sus consumidores se mueven. Estaba además ya sellada al mismo
+# hash, o sea cero reconstrucciones.
+#
+# **Que 31 consumidores dependan de algo NO implica cascada.** La cascada aparece cuando las deps
+# PROPIAS del promovido resuelven distinto — eso es lo que pasó al promover `glib-introspected`, que
+# depende de `glib` y en el corpus encuentra la estática. Acá no había nada que resolver distinto.
+name = "qemu"
+version = "11.1.2"
+license = "GPL-2.0-only"
+
+[source]
+tarball = "https://download.qemu.org/qemu-11.1.2.tar.xz"
+sha256 = "731b5681e4bb18be313231579b8efd0296c5b015fa36dc533874b639ba838016"
+
+[build]
+compiler = "zig-cc"
+target = "x86_64-linux-musl"
+# `dynamic` y no `static`: sus deps del corpus son todas `.a` hoy, así que el binario sale casi
+# autosuficiente de todos modos — pero forzar `-static` rompería el día que una de ellas sólo
+# publique `.so`, que es exactamente lo que le pasó a `gdb` con `gmp`/`mpfr`.
+link = "dynamic"
+flags = []
+
+[build.phases]
+configure = '''
+set -e
+[ -f ./configure ] || { echo "qemu: no hay ./configure" >&2; exit 1; }
+
+# ⚠⚠ **SE INSTALA EL WHEEL QUE QEMU YA TRAE, Y ESO EVITA QUE SU BUILD SALGA A LA RED.**
+#
+# Su `configure` hace, literalmente sin condición (`configure:988`):
+#
+# # Unconditionally install our tooling group.
+# $mkvenv ensuregroup … pythondeps.toml tooling || exit 1
+#
+# y el grupo `[tooling]` es `"qemu.qmp" = { accepted = ">=0.0.5", installed = "0.0.6" }`. El campo
+# `accepted` es la clave: significa **«versiones aceptadas si se usa un paquete del sistema»**. Si
+# `qemu.qmp` ya está instalado, mkvenv no instala NADA y no necesita red.
+#
+# Si NO está, intenta instalarlo en el venv — y para eso pip arranca su trío de bootstrap
+# (`setuptools`, `wheel`, `pip`) **como wheels locales**, que no existen, y muere:
+#
+# ERROR: Could not find a version that satisfies the requirement setuptools>=44.1.1
+#
+# ⚠ Y declarar `py3-setuptools` + `py3-pip` NO alcanzó, aunque parecía la cura: comprobado con un
+# diagnóstico dentro del sandbox, `find_spec` encuentra los dos (`pip: True setuptools: True`). Esos
+# dos sólo deciden si el venv lleva pip propio (`mkvenv.py:244-251`); no evitan la INSTALACIÓN de
+# qemu.qmp. Siguen declarados porque esa rama también hace falta, pero no eran el muro.
+#
+# ⇒ La salida exacta: **el wheel ya viene en el tarball** (`python/wheels/qemu_qmp-0.0.6-…whl`), y el
+# layout de un wheel puro ES el layout instalado — trae `qemu/qmp/` y su `.dist-info`. Así que se
+# descomprime en `site-packages` y queda un paquete del sistema legítimo, con su metadata de verdad
+# en vez de una fabricada a mano (que es lo que hubiera hecho falta copiando `python/qemu` a pelo:
+# `importlib.metadata` necesita el `.dist-info` para responder la versión).
+#
+# El `/` del sandbox es un `--tmp-overlay`, así que escribir en `site-packages` es legítimo y se
+# descarta con el build.
+# ⚠⚠ **Y HAY TRES ENTRADAS MÁS EN `[tooling]` QUE SON COMPROBACIONES DE CORTESÍA.** El grupo no es
+# sólo `qemu.qmp`:
+#
+# "setuptools" = { accepted = ">=44.1.1" }
+# "wheel" = { accepted = ">=0.34.2" }
+# # pip should be guaranteed by mkvenv, this is merely a sanity check for
+# # which version we are counting on being present.
+# "pip" = { accepted = ">=20.3.4" }
+#
+# Las tres tienen **sólo `accepted` y ningún `installed`**: o sea que únicamente se satisfacen con un
+# paquete del SISTEMA, y mkvenv detecta eso con `importlib.metadata.version()`, que necesita el
+# `.dist-info`. `py3-setuptools` y `py3-pip` instalan los paquetes **sin metadata** —son copias del
+# árbol, no instalaciones de wheel— así que mkvenv los ve ausentes, intenta instalarlos y muere sin
+# red. (Ese fue el muro después de resolver `qemu.qmp`: la lista de «installing» se quedó en esos
+# tres.)
+#
+# ⇒ Se quitan de `pythondeps.toml`, y el argumento es de upstream: su propio comentario dice que la
+# de `pip` es «**merely a sanity check** for which version we are counting on being present». Las
+# tres lo son — nada del build las IMPORTA: sirven para instalar, y con `qemu.qmp` ya presente no
+# queda nada que instalar.
+#
+# ⚠ Y se hace ACÁ y no en `py3-setuptools` a propósito: esa receta vive en el corpus con **31
+# consumidores en `incoming-gnome`**, y cambiar su contenido cambiaría su hash y el de todos ellos
+# — la cascada que la promoción había evitado. Añadirles `.dist-info` es su propia unidad de
+# trabajo, con su propio presupuesto.
+PD=pythondeps.toml
+for m in setuptools wheel pip; do
+ grep -qE "^\"$m\" *=" "$PD" || { echo "qemu: $PD ya no declara \"$m\" en [tooling] — upstream lo cambió; REVISAR si este parche sigue haciendo falta" >&2; exit 1; }
+done
+sed -i -E '/^"(setuptools|wheel|pip)" *=/d' "$PD"
+for m in setuptools wheel pip; do
+ grep -qE "^\"$m\" *=" "$PD" && { echo "qemu: no pude quitar \"$m\" de $PD" >&2; exit 1; }
+done
+grep -q '"qemu.qmp"' "$PD" || { echo "qemu: el sed se llevó qemu.qmp de $PD — eso NO debía pasar" >&2; exit 1; }
+echo "qemu: quitadas las 3 comprobaciones de cortesía de [tooling]; qemu.qmp intacto"
+
+W=$(ls python/wheels/qemu_qmp-*.whl 2>/dev/null | head -1)
+[ -n "$W" ] || { echo "qemu: no hay python/wheels/qemu_qmp-*.whl — upstream dejó de vendorizarlo y este build necesitaría red" >&2; ls python/wheels 2>/dev/null >&2; exit 1; }
+SP=$(python3 -c 'import sysconfig; print(sysconfig.get_path("purelib"))')
+python3 -m zipfile -e "$W" "$SP" || { echo "qemu: no pude descomprimir $W en $SP" >&2; exit 1; }
+# Comprobar lo que mkvenv va a preguntar: el módulo Y su versión por metadata.
+python3 - <<'PYEOF' || exit 1
+import importlib.util as u
+from importlib.metadata import version, PackageNotFoundError
+if not u.find_spec("qemu.qmp"):
+ raise SystemExit("qemu: qemu.qmp no es importable tras instalar el wheel")
+try:
+ v = version("qemu.qmp")
+except PackageNotFoundError:
+ raise SystemExit("qemu: qemu.qmp importable pero SIN metadata — mkvenv no podría leer su version y lo reinstalaria")
+print("qemu: qemu.qmp", v, "instalado como paquete del sistema (sin red)")
+PYEOF
+./configure --prefix=/usr --sysconfdir=/etc \
+ --without-default-features \
+ --target-list=x86_64-softmmu \
+ --enable-slirp --enable-tools --enable-pixman \
+ --enable-curses --enable-vnc --enable-kvm \
+ --disable-docs --disable-werror
+'''
+compile = 'make -j"$(nproc)"'
+# ⚠ EL GUARDIÁN LO EJECUTA, Y COMPRUEBA LA RED DONDE SE VE DE VERDAD.
+#
+# Que `qemu-system-x86_64` exista no dice nada: un emulador sin su tabla de máquinas o sin red es un
+# binario que arranca y no puede arrancar NADA. Y `--enable-slirp` por sí solo no garantiza que
+# slirp entrara: su `dependency()` podría haber fallado en silencio con otra combinación de
+# perillas.
+#
+# `-netdev help` lista los backends REGISTRADOS, y `user` aparece **sólo si slirp se enlazó**. Eso
+# es la prueba, no el flag de configure. Lo mismo `-machine help` para las máquinas y `qemu-img`
+# creando una imagen de verdad: tres comprobaciones de extremo a extremo que no necesitan ni KVM ni
+# `/dev` (el sandbox va con `--unshare-all`, así que arrancar una VM sí está fuera de alcance).
+install = '''
+set -e
+make install DESTDIR=/out
+Q=/out/usr/bin/qemu-system-x86_64
+[ -x "$Q" ] || { echo "qemu: no quedó qemu-system-x86_64 — NO sello" >&2; ls /out/usr/bin 2>/dev/null >&2; exit 1; }
+[ -x /out/usr/bin/qemu-img ] || { echo "qemu: falta qemu-img — habría emulador y nada con qué preparar un disco" >&2; exit 1; }
+
+# Ejecución y truncado SEPARADOS: el estado de una tubería es el del último comando.
+sal=$("$Q" --version 2>&1) || { echo "qemu: el emulador no arranca" >&2; printf '%s\n' "$sal" >&2; exit 1; }
+printf '%s\n' "$sal" | head -1 | grep -qE 'QEMU emulator version 11\.1\.2' || { echo "qemu: --version inesperado: $(printf '%s\n' "$sal" | head -1)" >&2; exit 1; }
+
+# LA RED: `user` sólo aparece si slirp se enlazó de verdad.
+nd=$("$Q" -netdev help 2>&1) || true
+printf '%s\n' "$nd" | grep -qw user || {
+ echo "qemu: '-netdev help' no lista 'user' — slirp NO entró, así que la única red sería tap (root + puente)" >&2
+ printf '%s\n' "$nd" | head -10 >&2
+ exit 1
+}
+# LAS MÁQUINAS: sin tabla de máquinas no se puede arrancar nada.
+mq=$("$Q" -machine help 2>&1) || true
+printf '%s\n' "$mq" | grep -qE '^q35|pc-q35|^pc ' || {
+ echo "qemu: '-machine help' no lista q35 ni pc — el emulador no tiene con qué arrancar una imagen" >&2
+ printf '%s\n' "$mq" | head -8 >&2
+ exit 1
+}
+# LAS HERRAMIENTAS, de extremo a extremo: crear una imagen y volver a leerla.
+t=$(mktemp -d)
+/out/usr/bin/qemu-img create -f qcow2 "$t/p.qcow2" 16M >/dev/null 2>&1 || { echo "qemu: qemu-img no pudo crear un qcow2" >&2; exit 1; }
+/out/usr/bin/qemu-img info "$t/p.qcow2" 2>&1 | grep -q 'qcow2' || { echo "qemu: qemu-img creó una imagen que no puede volver a leer" >&2; exit 1; }
+echo "qemu: $(printf '%s\n' "$sal" | head -1) · red user (slirp) + $(printf '%s\n' "$mq" | grep -c . ) máquinas + qemu-img"
+'''
+
+[deps]
+build = ["make", "meson", "samurai", "pkgconf", "python3", "glib", "pixman", "ncurses",
+ "zlib", "libslirp", "libffi", "pcre2", "libseccomp", "binutils", "bison", "flex",
+ # ⚠ Los DOS, y `py3-pip` por una razón que no es «instalar cosas»: `mkvenv.py:244-251` decide
+ # con `find_spec("setuptools") and find_spec("pip")`. Con setuptools pero SIN pip importable
+ # toma la rama del `ensurepip`, y en Python 3.12 **ensurepip ya no incluye setuptools** — así
+ # que ese camino va al índice y muere sin red. Con los dos presentes crea el venv
+ # `with_pip=False` y resuelve su wheel vendorizado con el pip del sistema. Ver
+ # `recipes/py3-pip.toml`.
+ "py3-setuptools", "py3-pip"]