Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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::unix en est indissociable). Option A retenue : plus de pal air pur ; std réutilise le pal unix + 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 :

  1. Le PAL COMPOSE la couche 1, il ne re-syscall pas. std::sys::pal::air mappe 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.

  2. Hors-arbre jusqu’à la démo, puis upstream Tier-3. Le patchset std + les specs de cible vivent dans rt/ (workspace nightly, hors barrière stable — ADR-037/049) jusqu’à ce que std bootstrappe et tourne sur 2 arches. On enregistre alors {x86_64,aarch64}-unknown-linux-air comme cibles rustc Tier-3 (compile, sans garantie de test automatisé côté projet Rust), ce qui ouvre à terme rustup target add.

  3. 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 backend sys/pal/air + colle os/thread_local).

  4. 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 construit std + 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 : std natif sur Air (fs/net/thread/process/println!) sans glibc, sur une fondation Rust pure jusqu’à la couche 1 ; chemin d’upstream clair (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, destructeurs thread_local! (register_dtor), mutation d’env (set/unset), newtype os_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 backend pal/air.
  • Caveat de fermeture (aarch64) : cpufeatures (via air-crypto) lie libc (getauxval) ; le PAL ne dépend pas d’air-crypto (il lie couche-0 getrandom pour random), donc ce point reste un chantier de fermeture séparé, pas un bloquant du PAL.
  • Portée : le PAL est le socle du std d’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 (pal unix standard + shim libc en Rust pur) : donnerait « du Rust sans glibc », mais repasse par une couche en forme de libc et par le pal unix (avec ses hypothèses) — contraire à la doctrine « pal directement sur la couche 1 pure » (pal-rust-couche1-et-clang-air). Rejeté.
  • std sur notre libc C-ABI (pal unix pointé sur libair_c) : réintroduit une frontière FFI/unsafe que 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 le std Rust.
  • Rester no_std partout : renonce à l’ergonomie std (fs/net/thread/process) pour le userland Air. Contraire à l’objectif « full Rust natif ». Rejeté.
  • Attendre un support air dans LLVM/rustc en amont d’abord : inverserait l’ordre — on prouve la cible hors-arbre puis on upstream (ADR-049), pas l’inverse.