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-076 — std Rust natif sur la libc d’Air : cible env = "musl" + vendor = "air" (chantier B, option A)

Statut : Accepté (2026-07-08, décision BDFL directe). Amende ADR-050 (choix env = "air"env = "musl") et amende ADR-075 (« pal pur, zéro libc » → « std sur la libc d’Air »). Met en œuvre le chantier B de la roadmap PAL (docs/notes/roadmap-pal-cloture-fr.md).

Catégorie : Décision de toolchain (toit std). N’altère aucune API couche 0/1 scellée.

Contexte

Objectif du chantier B : produire la toolchain Rust *-linux-air avec std natif, pour que nos exécutables et tests soient full Rust, sans tirer la glibc.

En amorçant le portage, un mur d’architecture est apparu : std — pour une cible target_family = "unix" + target_os = "linux" (ce qu’Air est, ADR-004/050) — compile son API publique std::os::unix / std::os::linux, indissociable de libc (extern crate libc, types libc::*, helpers sys::cvt, sys::linux). Un « pal sur couche 1 pure, sans libc » (l’ambition d’ADR-075) ne suffit pas : la structure de std exige une libc.

Par ailleurs, target_env = "air" (ADR-050 D1, « 3ᵉ saveur de libc ») n’est reconnu par aucun crate de l’écosystème (libc, std) : la crate libc échoue à compiler pour env = "air" (elle ne sélectionne aucun module d’environnement). Or Air est ABI-musl — son llvm-target est déjà *-linux-musl (ADR-050 D-1.3).

Décision — option A

std utilise son pal unix, et les symboles libc sont fournis par la libc pure-Rust d’Air (air-libc, libair_c) au lieu de la glibc. Concrètement :

  1. La cible porte env = "musl" (au lieu de "air") dans son spec JSON. Alors libc, std et tout crate cfg(musl) / cfg(unix) compilent pour Air sans le moindre patch (ils voient une cible musl, ce qu’Air est). C’est le modèle éprouvé d’eyra/mustang (cibles à base musl).

  2. L’identité d’Air passe par vendor = "air". Le code Air qui doit savoir « je bâtis la cible Air réelle » (couche 1 : errno #[thread_local], destructeurs thread_local, yield_now/set_thread_name, feature nightly thread_local, sélections per-cible) utilise désormais cfg(target_vendor = "air") au lieu de cfg(target_env = "air"). Déclaré valide dans [workspace.lints.rust] (check-cfg). Renommage mécanique, sémantiquement invariant (faux sur l’hôte gnu, vrai sur la cible Air).

  3. Le lien résout les symboles libc vers libair_c (statique), pas la glibc : -nostdlib + CRT Air + -lair_c. -lunwind = stub (la cible est panic = abort, l’unwinder n’est jamais invoqué).

« Sans glibc » ≠ « sans libc ». L’objectif est zéro glibc, avec notre libc (pure Rust, couche 1 → C-ABI). La campagne air-libc-* (déjà en production, cf. la libc scopée OpenSSH) devient aussi le socle de std : les deux grands chantiers (libc et toolchain) convergent.

Conséquences

  • build-std=std compile ENTIÈREMENT pour Air, sans un seul patch de libc/std (prouvé le 2026-07-08 : libc config musl + std + std_detect + un hello-std compilent ; ne reste que le lien, qui réclame -lc/-lunwind). L’option A est validée.
  • Validation on-target préservée : selftest rt x86-air = 42 ET aarch64-air = 42 après le renommage cfg (couche 1 intacte via vendor = "air"). Barrière verte.
  • Cible de production du chantier B : compléter air-libc pour couvrir la surface std::sys::unix (superset des 55 manques révélés par la sonde OpenSSH), configurer le lien (libair static + CRT + -lunwind stub), et faire TOURNER hello-std on-target 2 arches. C’est désormais le cœur du chantier (le portage std est acquis ; reste la complétion de libair).
  • Ce qui est abandonné vs ADR-075 : le pal air custom (on réutilise le pal unix de std). Le patchset rust-src d’ADR-075 devient quasi vide (l’env = "musl" fait tout compiler).
  • Réversibilité : le renommage cfg et le champ env du spec sont localisés ; aucun impact sur les couches scellées.

Alternatives rejetées

  • (B) Cible non-unix (os custom) : std ne compilerait pas os::unix (pal pur possible), mais coût écosystème massif (tout crate cfg(unix) exclut Air) et perte de la logique unix de std. Rejeté.
  • (C) Patcher std/libc lourdement pour découpler os::unix d’Air, en gardant env = "air" : gros patch fragile (38+ cfg musl dans libc), dette de rebase à chaque nightly. Rejeté au profit de env = "musl" (zéro patch).
  • Garder env = "air" : rejeté — non reconnu par l’écosystème, force le portage à se battre contre libc/std.