From 88dc1d5409a08a479947374bdbe2f5364e68bc59 Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Tue, 28 Jul 2026 07:56:20 +0000 Subject: [PATCH] =?UTF-8?q?[IMP]=20script=20qemu:=20support=20arm64/aarch6?= =?UTF-8?q?4=20(+=20archi=20native=20marqu=C3=A9e=20d'un=20*)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajoute l'architecture arm64 (aarch64) au déploiement, en plus d'amd64 (x86_64) et s390x. Disponibilité réelle vérifiée (juillet 2026) : - arm64 : Ubuntu, Debian, Fedora (Arch : pas d'image cloud aarch64 -> rejet). - s390x : Ubuntu seulement (inchangé). deploy_qemu.py : - host_arch() : arch native de l'hôte ; toute arch différente est ÉMULÉE (TCG, --virt-type qemu) — plus de liste FOREIGN_ARCHES figée. - virt_install : arm64 -> --arch aarch64 --machine virt --boot uefi (firmware AAVMF résolu par libvirt) ; s390x inchangé ; x86 UEFI/OVMF inchangé. - ensure_emulator(arch) généralisé : installe qemu-system-aarch64 + firmware UEFI AAVMF (arm64) ou qemu-system-s390x (s390x), selon le gestionnaire de paquets, avec vérif de présence (binaire + firmware pour arm64). - Validation --arch tôt via ARCH_DISTRO_SUPPORT (message clair si la distro ne publie pas l'arch). Les URLs d'images arm64 marchent déjà via les alias (fedora/arch aarch64 ; ubuntu/debian arm64). todo.py : menus d'architecture (VM unique + infra) proposent amd64/arm64/ s390x selon la distro ; l'architecture NATIVE de l'hôte est marquée d'un * (défaut) ; les autres sont signalées « émulé, lent ». Le catalogue infra est restreint aux distros publiant l'arch choisie (arm64 -> ubuntu/debian/fedora, s390x -> ubuntu). install_debian_dependency.sh : wkhtmltopdf (deb amd64 en dur) ignoré best-effort sur toute arch non-x86_64 (au lieu d'avorter l'install). Validé : dry-runs Ubuntu/Debian/Fedora arm64 (bonnes URLs + virt-install aarch64/virt/uefi/qemu), rejet Arch arm64, non-régression s390x, menus et filtrage simulés (natif *, arm64 par distro). Co-Authored-By: Claude Opus 4.8 (1M context) --- script/install/install_debian_dependency.sh | 9 +- script/qemu/deploy_qemu.py | 191 +++++++++++++------- script/todo/todo.py | 130 +++++++------ script/todo/todo_i18n.py | 23 +++ 4 files changed, 231 insertions(+), 122 deletions(-) diff --git a/script/install/install_debian_dependency.sh b/script/install/install_debian_dependency.sh index 0a5a7ee..81904a1 100755 --- a/script/install/install_debian_dependency.sh +++ b/script/install/install_debian_dependency.sh @@ -187,10 +187,11 @@ fi #-------------------------------------------------- # Install Wkhtmltopdf if needed #-------------------------------------------------- -if [ "$(uname -m)" = "s390x" ]; then - # wkhtmltopdf ne publie pas de build s390x (WKHTMLTOX_X64 est de l'amd64). - # On saute proprement plutôt que d'avorter tout l'install. - echo "wkhtmltopdf : pas de build s390x, ignoré (optionnel)." +if [ "$(uname -m)" != "x86_64" ]; then + # WKHTMLTOX_X64 pointe vers un .deb amd64 : sur toute autre architecture + # (s390x, arm64/aarch64…) gdebi échouerait. On saute proprement plutôt que + # d'avorter tout l'install (wkhtmltopdf est optionnel). + echo "wkhtmltopdf : pas de build pour $(uname -m), ignoré (optionnel)." elif [ ${EL_INSTALL_WKHTMLTOPDF} = "True" ]; then echo -e "\n---- Installing wkhtml ----" INSTALLED=$(dpkg -s wkhtmltox | grep installed) diff --git a/script/qemu/deploy_qemu.py b/script/qemu/deploy_qemu.py index 87ea817..18db5e2 100755 --- a/script/qemu/deploy_qemu.py +++ b/script/qemu/deploy_qemu.py @@ -110,15 +110,37 @@ ARCH_ALIASES: dict[str, dict[str, str]] = { "arch": {"amd64": "x86_64", "arm64": "aarch64"}, } -# Architectures « étrangères » à un hôte x86 : émulées en TCG (pas de KVM), -# donc LENTES, avec une machine et un amorçage spécifiques (voir virt_install). -FOREIGN_ARCHES: tuple[str, ...] = ("s390x",) +# Architectures non-x86 nécessitant une machine/un amorçage spécifiques (voir +# virt_install). Émulées en TCG (pas de KVM), donc LENTES, quand elles +# diffèrent de l'architecture de l'hôte. +NON_X86_ARCHES: tuple[str, ...] = ("arm64", "s390x") -# Distros publiant des images cloud s390x (IBM Z). Seul Ubuntu en publie : -# Debian et Fedora n'ont pas de qcow2 cloud s390x ; Arch ne cible que -# x86_64/aarch64. Vérifié en juillet 2026 (cloud-images.ubuntu.com : OK ; -# cloud.debian.org & fedora-secondary : 404). +# Distros publiant des images cloud par architecture (vérifié juillet 2026) : +# - s390x (IBM Z) : Ubuntu seulement (Debian/Fedora : 404 ; Arch : x86/arm). +# - arm64/aarch64 : Ubuntu, Debian, Fedora (Arch : pas d'image cloud officielle +# aarch64 sur geo.mirror.pkgbuild.com). S390X_DISTROS: tuple[str, ...] = ("ubuntu",) +ARM64_DISTROS: tuple[str, ...] = ("ubuntu", "debian", "fedora") +# arch générique -> distros la publiant (pour valider --arch tôt). +ARCH_DISTRO_SUPPORT: dict[str, tuple[str, ...]] = { + "s390x": S390X_DISTROS, + "arm64": ARM64_DISTROS, +} + + +def host_arch() -> str: + """Architecture de l'hôte en jeton générique (amd64/arm64/s390x).""" + try: + machine = os.uname().machine + except (AttributeError, OSError): + machine = "" + return { + "x86_64": "amd64", + "amd64": "amd64", + "aarch64": "arm64", + "arm64": "arm64", + "s390x": "s390x", + }.get(machine, "amd64") ARCH_CLOUD_BASE = "https://geo.mirror.pkgbuild.com/images/latest" @@ -399,18 +421,44 @@ DAEMON_PACKAGES: dict[str, list[str]] = { "brew": [], } -# Émulateur QEMU système s390x (IBM Z). Requis UNIQUEMENT pour --arch s390x sur -# un hôte non-s390x : virt-install a besoin du binaire qemu-system-s390x. NB : -# sur apt, qemu-system-misc ne contient PAS s390x (alpha/avr/… seulement) — -# c'est le paquet dédié qemu-system-s390x qui le fournit. -S390X_EMULATOR_PACKAGES: dict[str, list[str]] = { - "apt": ["qemu-system-s390x"], - "dnf": ["qemu-system-s390x"], - "pacman": ["qemu-emulators-full"], - "zypper": ["qemu-s390"], - "brew": [], +# Émulateurs QEMU système pour architectures non-x86, requis pour --arch +# sur un hôte d'architecture différente (émulation TCG). Par arch puis +# par gestionnaire de paquets. NB apt : qemu-system-misc ne contient PAS s390x +# (alpha/avr/… seulement) -> paquet dédié qemu-system-s390x ; qemu-system-arm +# fournit qemu-system-aarch64 ; l'arm64 exige aussi le firmware UEFI AAVMF. +EMULATOR_PACKAGES: dict[str, dict[str, list[str]]] = { + "s390x": { + "apt": ["qemu-system-s390x"], + "dnf": ["qemu-system-s390x"], + "pacman": ["qemu-emulators-full"], + "zypper": ["qemu-s390"], + "brew": [], + }, + "arm64": { + "apt": ["qemu-system-arm", "qemu-efi-aarch64"], + "dnf": ["qemu-system-aarch64", "edk2-aarch64"], + "pacman": ["qemu-emulators-full", "edk2-aarch64"], + "zypper": ["qemu-arm", "qemu-uefi-aarch64"], + "brew": [], + }, } +# Binaire émulateur par arch (détection de présence). +EMULATOR_BINARY: dict[str, str] = { + "s390x": "qemu-system-s390x", + "arm64": "qemu-system-aarch64", +} + +# Firmwares UEFI AAVMF possibles (arm64) : au moins un doit exister. +AARCH64_FIRMWARE_PATHS: tuple[str, ...] = ( + "/usr/share/AAVMF/AAVMF_CODE.fd", + "/usr/share/AAVMF/AAVMF_CODE.no-secboot.fd", + "/usr/share/edk2/aarch64/QEMU_EFI.fd", + "/usr/share/edk2/aarch64/QEMU_EFI-silent.fd", + "/usr/share/qemu-efi-aarch64/QEMU_EFI.fd", + "/usr/share/edk2-armvirt/aarch64/QEMU_EFI.fd", +) + # Gestionnaires de paquets, dans l'ordre de préférence : # (clé TOOL_PACKAGES, binaire à détecter, commande d'installation, sudo, refresh) PKG_MANAGERS: tuple[ @@ -619,31 +667,43 @@ def ensure_tools(runner: Runner, assume_yes: bool, no_install: bool) -> None: ensure_libvirt_service(runner) -def ensure_s390x_emulator( - runner: Runner, assume_yes: bool, no_install: bool +def emulator_ready(arch: str) -> bool: + """Vrai si l'émulateur (et, pour arm64, un firmware UEFI AAVMF) est là.""" + if shutil.which(EMULATOR_BINARY[arch]) is None: + return False + if arch == "arm64": + return any(os.path.exists(p) for p in AARCH64_FIRMWARE_PATHS) + return True + + +def ensure_emulator( + arch: str, runner: Runner, assume_yes: bool, no_install: bool ) -> None: - """Vérifie que qemu-system-s390x est présent (requis pour --arch s390x sur - un hôte x86) ; l'installe au besoin via le gestionnaire de paquets.""" - if shutil.which("qemu-system-s390x"): + """Vérifie l'émulateur QEMU système pour `arch` (et le firmware UEFI pour + arm64), requis quand on émule une architecture différente de l'hôte ; + l'installe au besoin via le gestionnaire de paquets.""" + binary = EMULATOR_BINARY[arch] + if emulator_ready(arch): return pm = detect_pkg_manager() if pm is None: sys.exit( - " Émulateur s390x introuvable (qemu-system-s390x) et gestionnaire " - "de paquets non reconnu.\n Installez-le manuellement." + f" Émulateur {arch} introuvable ({binary}) et gestionnaire de " + "paquets non reconnu.\n Installez-le manuellement." ) pm_key, install_cmd, use_sudo, refresh = pm - packages = S390X_EMULATOR_PACKAGES.get(pm_key, []) + packages = EMULATOR_PACKAGES.get(arch, {}).get(pm_key, []) if not packages: sys.exit( - " Émulateur s390x introuvable (qemu-system-s390x) : installez le " - "paquet QEMU système s390x de votre distribution." + f" Émulateur {arch} introuvable ({binary}) : installez le paquet " + "QEMU système correspondant de votre distribution " + "(+ firmware UEFI pour arm64)." ) full_cmd = install_cmd + packages printable = ("sudo " if use_sudo and runner.use_sudo else "") + " ".join( full_cmd ) - print(" Émulateur s390x manquant (qemu-system-s390x).") + print(f" Émulateur {arch} manquant ({binary}).") print(f" Commande d'installation : {printable}") if no_install: sys.exit( @@ -651,18 +711,18 @@ def ensure_s390x_emulator( " Installez manuellement : " + printable ) if not assume_yes and not prompt_yes_no( - " Installer l'émulateur s390x maintenant ?" + f" Installer l'émulateur {arch} maintenant ?" ): sys.exit(" Installation refusée.\n Commande manuelle : " + printable) if refresh: runner.run(refresh, privileged=use_sudo, check=False) runner.run(full_cmd, privileged=use_sudo) - if not shutil.which("qemu-system-s390x"): + if not emulator_ready(arch): sys.exit( - " qemu-system-s390x toujours absent après installation.\n" - f" Essayez manuellement : {printable}" + f" Émulateur {arch} ({binary}) ou firmware toujours absent après " + f"installation.\n Essayez manuellement : {printable}" ) - print(" Émulateur s390x installé avec succès.") + print(f" Émulateur {arch} installé avec succès.") # --------------------------------------------------------------------------- # @@ -1046,10 +1106,11 @@ def virt_install( osinfo: str, runner: Runner, ) -> None: - foreign = args.arch in FOREIGN_ARCHES + # Émulée (TCG, pas de KVM) si l'arch demandée diffère de celle de l'hôte. + emulated = args.arch != host_arch() # s390x n'a pas de port série ISA : la console est SCLP (ttysclp0), et non - # ttyS0. Ailleurs (x86), console série classique. - console_target = "sclp" if foreign else "serial" + # ttyS0. Ailleurs (x86/arm64), console série classique. + console_target = "sclp" if args.arch == "s390x" else "serial" cmd = [ "virt-install", "--name", @@ -1078,20 +1139,17 @@ def virt_install( "--console", f"pty,target_type={console_target}", ] - if foreign: - # s390x (IBM Z) sur hôte x86 : émulation TCG (--virt-type qemu, pas de - # KVM), machine s390-ccw-virtio, amorçage IPL/zipl depuis le disque - # (ni BIOS ni UEFI/OVMF -> aucun --boot). LENT (émulation logicielle). - cmd += [ - "--arch", - "s390x", - "--machine", - "s390-ccw-virtio", - "--virt-type", - "qemu", - ] + if args.arch == "s390x": + # s390x (IBM Z) : machine s390-ccw-virtio, amorçage IPL/zipl depuis le + # disque (ni BIOS ni UEFI/OVMF -> aucun --boot). + cmd += ["--arch", "s390x", "--machine", "s390-ccw-virtio"] + elif args.arch == "arm64": + # arm64/aarch64 : machine « virt » + UEFI (firmware AAVMF résolu par + # libvirt d'après --arch aarch64). Les images cloud arm64 n'ont pas de + # BIOS -> UEFI obligatoire. + cmd += ["--arch", "aarch64", "--machine", "virt", "--boot", "uefi"] elif not args.bios: - # Boot UEFI par défaut : Debian 13 (trixie) et les images cloud + # Boot UEFI par défaut (x86) : Debian 13 (trixie) et les images cloud # récentes n'embarquent plus le chargeur BIOS/GRUB-pc et partent en # boucle « Booting... » en SeaBIOS. UEFI (OVMF) fonctionne pour # Ubuntu/Debian/Fedora. --bios force l'ancien BIOS si OVMF est absent. @@ -1103,6 +1161,10 @@ def virt_install( "uefi,firmware.feature0.name=secure-boot," "firmware.feature0.enabled=no", ] + if emulated: + # Architecture différente de l'hôte -> émulation logicielle TCG + # (pas de KVM). LENT. + cmd += ["--virt-type", "qemu"] if not args.attach_console: cmd.append("--noautoconsole") runner.run(cmd, privileged=True) @@ -1183,8 +1245,9 @@ def build_parser() -> argparse.ArgumentParser: g_img.add_argument( "--arch", default="amd64", - help="Architecture de l'image (défaut : amd64). s390x (IBM Z) n'est " - "disponible que pour Ubuntu et est ÉMULÉ (lent) sur un hôte x86.", + help="Architecture de l'image (défaut : amd64). amd64/x86_64, " + "arm64/aarch64 (Ubuntu/Debian/Fedora) ou s390x (Ubuntu). Toute arch " + "différente de l'hôte est ÉMULÉE (TCG, lente).", ) g_img.add_argument( "--image-dir", @@ -1420,13 +1483,13 @@ def main() -> None: f"Version {args.version!r} inconnue pour {args.distro}. " f"Choix : {', '.join(versions)} (voir --list-images)." ) - # s390x n'est publié en image cloud que par Ubuntu (voir S390X_DISTROS). - if args.arch == "s390x" and args.distro not in S390X_DISTROS: + # Certaines architectures ne sont publiées que par une partie des distros + # (voir ARCH_DISTRO_SUPPORT) : on valide tôt plutôt qu'échouer au download. + supported = ARCH_DISTRO_SUPPORT.get(args.arch) + if supported is not None and args.distro not in supported: sys.exit( - f"Architecture s390x indisponible pour {args.distro!r} : seul " - f"Ubuntu publie des images cloud s390x ({', '.join(S390X_DISTROS)})." - "\n Debian/Fedora n'en publient pas ; Arch ne cible que " - "x86_64/aarch64." + f"Architecture {args.arch} indisponible pour {args.distro!r} : " + f"images cloud publiées seulement pour {', '.join(supported)}." ) code, default_osinfo, min_ram, min_disk = versions[args.version] if args.codename: @@ -1499,13 +1562,17 @@ def main() -> None: if not args.dry_run: ensure_tools(runner, args.assume_yes, args.no_install_deps) - if args.arch in FOREIGN_ARCHES: - ensure_s390x_emulator( - runner, args.assume_yes, args.no_install_deps + # Émulation requise si l'arch diffère de l'hôte : installe l'émulateur + # QEMU système adéquat (+ firmware UEFI pour arm64) et prévient de la + # lenteur. + if args.arch in EMULATOR_BINARY and args.arch != host_arch(): + ensure_emulator( + args.arch, runner, args.assume_yes, args.no_install_deps ) print( - " Note : s390x est ÉMULÉ (TCG) sur cet hôte — le boot et " - "l'installation seront nettement plus lents que x86." + f" Note : {args.arch} est ÉMULÉ (TCG) sur cet hôte " + f"({host_arch()}) — le boot et l'installation seront " + "nettement plus lents que l'architecture native." ) print(f"\n== 1/5 Image cloud ({args.distro} {args.version} / {code}) ==") diff --git a/script/todo/todo.py b/script/todo/todo.py index 6bad29e..36a6f11 100755 --- a/script/todo/todo.py +++ b/script/todo/todo.py @@ -854,31 +854,12 @@ class TODO: print(f"{t('Invalid selection, using')} {default}") return default - # Distros publiant des images cloud s390x (IBM Z). Seul Ubuntu en publie - # (cohérent avec S390X_DISTROS de deploy_qemu.py). + # Distros publiant des images cloud par architecture (cohérent avec + # S390X_DISTROS / ARM64_DISTROS de deploy_qemu.py). amd64 : toutes. _QEMU_S390X_DISTROS = ("ubuntu",) - - def _qemu_prompt_arch(self, distro): - """Demande l'architecture. s390x n'est proposé que pour les distros qui - publient des images s390x (Ubuntu) ; il est ÉMULÉ (lent) sur x86.""" - if distro not in self._QEMU_S390X_DISTROS: - return "amd64" - print(f"\n{t('Architecture:')}") - print(f" [1] amd64 *") - print(f" [2] s390x ({t('IBM Z — emulated, slow on x86')})") - sel = ( - input(f"{t('Choice (number or name, blank = amd64):')} ") - .strip() - .lower() - ) - if sel in ("2", "s390x"): - warn = t( - "s390x is emulated (TCG): boot and install are much " - "slower than x86." - ) - print(f"⚠ {warn}") - return "s390x" - return "amd64" + _QEMU_ARM64_DISTROS = ("ubuntu", "debian", "fedora") + # Alias distro pour l'affichage (jeton générique -> nom courant). + _QEMU_ARCH_ALIAS = {"amd64": "x86_64", "arm64": "aarch64"} @staticmethod def _native_arch(): @@ -896,39 +877,74 @@ class TODO: "s390x": "s390x", }.get(machine, "amd64") - def _qemu_prompt_infra_arch(self): - """Demande l'architecture du parc (défaut : native de l'hôte). s390x - est proposé mais ÉMULÉ (lent) et limité à Ubuntu (seule distro avec - des images cloud s390x).""" - native = self._native_arch() - opts = [native] - if native != "s390x": - opts.append("s390x") # émulé, disponible en plus du natif + def _qemu_arch_distros(self, arch): + """Distros supportant `arch` (None = toutes, cas amd64).""" + if arch == "s390x": + return self._QEMU_S390X_DISTROS + if arch == "arm64": + return self._QEMU_ARM64_DISTROS + return None + + def _qemu_ask_arch(self, opts, native): + """Affiche les architectures `opts` (natif marqué d'un *) et renvoie le + choix. Toute arch non native est ÉMULÉE (TCG, lente).""" print(f"\n{t('Architecture:')}") for i, a in enumerate(opts, 1): - tag = f" ({t('native')}) *" if a == native else "" - extra = "" - if a == "s390x": - extra = f" ({t('IBM Z — emulated, slow on x86; Ubuntu only')})" - print(f" [{i}] {a}{tag}{extra}") + alias = self._QEMU_ARCH_ALIAS.get(a) + label = f"{a} ({alias})" if alias else a + if a == native: + label += f" — {t('native')} *" + elif a == "s390x": + label += f" ({t('IBM Z — emulated, slow; Ubuntu only')})" + elif a == "arm64": + label += f" ({t('ARM 64-bit — emulated, slow')})" + else: + label += f" ({t('emulated, slow')})" + print(f" [{i}] {label}") sel = ( input(f"{t('Choice (number or name, blank = native):')} ") .strip() .lower() ) - if not sel: - return native - for i, a in enumerate(opts, 1): - if sel == str(i) or sel == a: - if a == "s390x": - warn = t( - "s390x is emulated (TCG): boot and install are much " - "slower than x86." - ) - print(f"⚠ {warn}") - return a - print(f"{t('Invalid selection, using')} {native}") - return native + chosen = native + if sel: + chosen = None + for i, a in enumerate(opts, 1): + if sel in (str(i), a, self._QEMU_ARCH_ALIAS.get(a)): + chosen = a + break + if chosen is None: + print(f"{t('Invalid selection, using')} {native}") + chosen = native + if chosen != native: + warn = t( + "This architecture is emulated (TCG): boot and install are" + " much slower than the native one." + ) + print(f"⚠ {warn}") + return chosen + + def _qemu_prompt_arch(self, distro): + """Architecture pour un déploiement de VM unique. Propose amd64, plus + arm64/s390x si la distro choisie publie ces images.""" + opts = ["amd64"] + if distro in self._QEMU_ARM64_DISTROS: + opts.append("arm64") + if distro in self._QEMU_S390X_DISTROS: + opts.append("s390x") + if len(opts) == 1: + return "amd64" # rien à demander + return self._qemu_ask_arch(opts, self._native_arch()) + + def _qemu_prompt_infra_arch(self): + """Architecture du parc (défaut : native de l'hôte, marquée d'un *). + Toute arch non native est émulée ; le catalogue est ensuite restreint + aux distros publiant cette arch.""" + native = self._native_arch() + opts = ["amd64", "arm64", "s390x"] + if native not in opts: # hôte exotique : garder le natif en tête + opts.insert(0, native) + return self._qemu_ask_arch(opts, native) def _qemu_list_images(self): """Affiche la liste des distros/versions et leurs specs.""" @@ -1913,16 +1929,18 @@ class TODO: return distros = list(mod.DISTROS) - # 0) Architecture du parc (défaut : native de l'hôte). s390x n'a des - # images cloud que pour Ubuntu -> on restreint le catalogue. + # 0) Architecture du parc (défaut : native de l'hôte). arm64 et s390x + # n'ont pas d'images pour toutes les distros -> on restreint le + # catalogue aux distros qui publient l'arch choisie. arch = self._qemu_prompt_infra_arch() - if arch == "s390x": - keep = [d for d in distros if d in self._QEMU_S390X_DISTROS] + allowed = self._qemu_arch_distros(arch) + if allowed is not None: + keep = [d for d in distros if d in allowed] dropped = [d for d in distros if d not in keep] if dropped: print( - f" ⚠ {t('s390x images only exist for:')} " - f"{', '.join(self._QEMU_S390X_DISTROS)} " + f" ⚠ {t('images for this arch only exist for:')} " + f"{', '.join(allowed)} " f"({t('ignored:')} {', '.join(dropped)})" ) distros = keep diff --git a/script/todo/todo_i18n.py b/script/todo/todo_i18n.py index 3d08e78..1bd71f8 100644 --- a/script/todo/todo_i18n.py +++ b/script/todo/todo_i18n.py @@ -1174,6 +1174,29 @@ TRANSLATIONS = { "fr": "IBM Z — émulé, lent sur x86 ; Ubuntu uniquement", "en": "IBM Z — emulated, slow on x86; Ubuntu only", }, + "IBM Z — emulated, slow; Ubuntu only": { + "fr": "IBM Z — émulé, lent ; Ubuntu uniquement", + "en": "IBM Z — emulated, slow; Ubuntu only", + }, + "ARM 64-bit — emulated, slow": { + "fr": "ARM 64 bits — émulé, lent", + "en": "ARM 64-bit — emulated, slow", + }, + "emulated, slow": { + "fr": "émulé, lent", + "en": "emulated, slow", + }, + "This architecture is emulated (TCG): boot and install are" + " much slower than the native one.": { + "fr": "Cette architecture est émulée (TCG) : le boot et l'installation" + " sont bien plus lents que l'architecture native.", + "en": "This architecture is emulated (TCG): boot and install are" + " much slower than the native one.", + }, + "images for this arch only exist for:": { + "fr": "images pour cette architecture disponibles seulement pour :", + "en": "images for this arch only exist for:", + }, "Choice (number or name, blank = native):": { "fr": "Choix (numéro ou nom, vide = native) :", "en": "Choice (number or name, blank = native):",