ADR-075 — Fourniture du PAL : std::sys::pal::air via rust-src patché + build-std, puis upstream Tier-3
Statut : Accepté (2026-07-07, décision BDFL directe). Mise en œuvre des phases 3-4 du
programme *-linux-air (ADR-049 /
ADR-050 / ADR-052).
S’appuie sur l’allocateur (ADR-056) et l’audit
face-PAL (docs/notes/audit-face-pal-cloture-fr.md). Détaillé côté exécution par la note
docs/notes/roadmap-pal-cloture-fr.md.
⚠️ AMENDÉ par ADR-076 (2026-07-08). Le portage a montré que
std(cible unix/linux) EXIGE une libc (os::unixen est indissociable). Option A retenue : plus de palairpur ;stdréutilise le palunix+ la libc d’Air (libair) fournit les symboles (zéro glibc). Cette ADR reste valable pour le principe « rust-src reproductible », mais le pal custom est abandonné.
Catégorie : Décision d’outillage / toit au-dessus des couches scellées. N’altère aucune API couche 0/1 scellée (le PAL consomme la couche 1 ; les manques se comblent en additif, ADR-051).
Contexte
Le PAL (Platform Abstraction Layer) = le backend std::sys qu’une toolchain
*-linux-air doit fournir pour que le std Rust compile et tourne nativement sur Air,
sans tirer la glibc dans nos binaires et nos tests.
Le bring-up sous std est fait et prouvé 2 arches : _start/self-reloc static-PIE,
TLS/errno/TCB, spawn clone3, allocateur réel air-alloc (ADR-052/056). L’audit
face-PAL conclut à zéro gap fondateur : chaque primitive std::sys a sa brique
couche 1 (fs AirFile, net AirTcp/Udp/Unix, process, thread, time, env, args, stdio,
path, alloc, TLS), et les 10 crates que le PAL compose sont #![no_std].
Reste la question de mise en œuvre : comment fournir concrètement le backend std::sys
pour air ? Rust n’offre pas de mécanisme stable de « pal enfichable » : -Z build-std
reconstruit std depuis les sources rustc ; ajouter un backend air implique donc de
modifier ces sources.
Décision
On fournit le PAL en maintenant un rust-src patché — un fork minimal du sous-arbre
library/std de rustc qui ajoute un backend std::sys::pal::air — construit via
-Z build-std=std sur le nightly épinglé. Quatre principes :
-
Le PAL COMPOSE la couche 1, il ne re-syscall pas.
std::sys::pal::airmappe chaque primitive sur la brique couche 1 correspondante (air_runtime,air_alloc,air_thread,air_filesystem::AirFile,air_socket,air_process,air_env,air_stdio,air_base_core). Il ne réimplémente rien et n’appelle jamais la couche 0 en direct (ADR-052 : seule la couche 1 consomme la couche 0). Aucune libc, aucune FFI. -
Hors-arbre jusqu’à la démo, puis upstream Tier-3. Le patchset
std+ les specs de cible vivent dansrt/(workspace nightly, hors barrière stable — ADR-037/049) jusqu’à ce questdbootstrappe et tourne sur 2 arches. On enregistre alors{x86_64,aarch64}-unknown-linux-aircomme cibles rustc Tier-3 (compile, sans garantie de test automatisé côté projet Rust), ce qui ouvre à termerustup target add. -
Nightly épinglé, rebase discipliné. Le patch suit le nightly daté (ADR-025 pour la repro de la vérification ;
rt/reste hors des garanties repro du produit jusqu’à l’upstream). Un bump de nightly = re-rebase du patch PAL — coût de maintenance assumé et localisé (le patch est petit : un backendsys/pal/air+ colleos/thread_local). -
Gate CI nightly en phase 4. Le carve-out actuel de
rt/(hors barrière/couverture) est refermé par une lane CI nightly dédiée qui construitstd+ le « hello std » sur 2 arches. La logique de runtime déjà redomiciliée en couche 1 (ADR-052) reste, elle, sous les 100 % + barrière 2-arches obligatoires.
Conséquences
- Positif :
stdnatif sur Air (fs/net/thread/process/println!) sans glibc, sur une fondation Rust pure jusqu’à la couche 1 ; chemin d’upstreamclair (Tier-3) ; le PAL n’altère aucune API scellée. - Briques additives couche 1 à livrer (audit face-PAL, sous 100 %, descellement additif
ADR-051) :
Condvar,Once, destructeursthread_local!(register_dtor), mutation d’env (set/unset), newtypeos_str. Aucune n’est fondatrice (toutes constructibles sur des primitives déjà publiques). - Coût de maintenance : un fork
rust-srcà rebaser à chaque bump de nightly — délibéré, circonscrit au backendpal/air. - Caveat de fermeture (aarch64) :
cpufeatures(viaair-crypto) lielibc(getauxval) ; le PAL ne dépend pas d’air-crypto(il lie couche-0getrandompourrandom), donc ce point reste un chantier de fermeture séparé, pas un bloquant du PAL. - Portée : le PAL est le socle du
stdd’Air (Rust natif). La libc C-ABI (pour compiler du C contre Air) reste une piste distincte (ADR-046/047), non requise ici.
Alternatives rejetées
- Eyra /
c-scape(palunixstandard + shim libc en Rust pur) : donnerait « du Rust sans glibc », mais repasse par une couche en forme de libc et par le palunix(avec ses hypothèses) — contraire à la doctrine « pal directement sur la couche 1 pure » (pal-rust-couche1-et-clang-air). Rejeté. stdsur notre libc C-ABI (palunixpointé surlibair_c) : réintroduit une frontière FFI/unsafeque le pal Rust-pur élimine, et crée une circularité (la libc s’appuie en partie sur la couche 1). Rejeté pour le pal ; la libc C-ABI sert les programmes C, pas lestdRust.- Rester
no_stdpartout : renonce à l’ergonomiestd(fs/net/thread/process) pour le userland Air. Contraire à l’objectif « full Rust natif ». Rejeté. - Attendre un support
airdans LLVM/rustc en amont d’abord : inverserait l’ordre — on prouve la cible hors-arbre puis on upstream (ADR-049), pas l’inverse.