In questa sezione

Ogni pacchetto generato esegue il suo programma sul runtime di lungo, il port in Rust del runtime di Lean che i crate Rust compilano dai sorgenti. Per gli altri linguaggi è precompilato: chi usa un programma Lean da Go, Python, Swift o TypeScript dovrebbe avere bisogno della toolchain del proprio linguaggio e di un compilatore C, non di Rust. Questa pagina spiega come il runtime arriva a loro e perché è organizzato in questo modo.

Un runtime, molti pacchetti

Il backend di Lean genera C e lo collega alla libreria del runtime di Lean; il backend C di lungo fa lo stesso, con liblungo. Il runtime è la parte di un programma che non dipende dal programma (oggetti, numeri, stringhe, array, task, IO), quindi viene compilato una volta per piattaforma, rilasciato e condiviso: da ogni pacchetto generato in un processo e da ogni versione di programma generata con la stessa release di lungo.

La condivisione è anche un requisito. Il runtime ha uno stato a livello di processo: il gestore dei task, gli handle tenuti dall’host, i punti di ingresso dell’host, i flussi standard. Due copie in un processo lo dividerebbero. La libreria di supporto di ciascun linguaggio collega quindi il runtime una sola volta (il modulo Go lo collega nel binario, lungo-py carica la sua libreria condivisa nello spazio globale dei simboli, il pacchetto Swift collega l’XCFramework, il pacchetto C collega la libreria statica), e i pacchetti generati si limitano a riferirsi ai suoi simboli.

Che cosa contiene una release

Ogni release di lungo pubblica, con la stessa versione:

  • il runtime per ogni piattaforma, come archivi con l’header, le librerie statiche e condivise, un pacchetto CMake e un file pkg-config, e per le piattaforme Apple come XCFramework, serviti da release.machinefabric.com (lungo-runtime);
  • il comando lungo per macOS, Linux e Windows (lungo-cli), che incorpora il manifest del runtime della sua release (l’URL e il digest SHA-256 di ogni archivio del runtime), e i suoi pacchetti per Homebrew, apt e dnf;
  • le librerie di supporto: lungo-py su PyPI (con il runtime di ogni piattaforma nelle sue wheel), lungo-ts su npm, il modulo Go github.com/machinefabric/lungo-go (con il runtime di ogni piattaforma) e il pacchetto Swift machinefabric/lungo-swift (il cui target LungoRuntime è l’XCFramework, tramite URL e checksum);
  • i crate Rust.

Un pacchetto generato si riferisce esattamente a questa release: la sua versione fa parte di ciò che lo ha generato, perché il C generato chiama l’interfaccia interna del runtime. Una discrepanza viene rilevata dove è possibile: la versione dell’ABI C fallisce al collegamento, il marcatore di versione del modulo Go in compilazione, i pacchetti Python e TypeScript al caricamento, e la versione del pacchetto CMake è richiesta esattamente.

Di che cosa ci si deve fidare

Tutto ciò che un utente scarica viene controllato con digest che provengono dalla release stessa:

  • Il manifest della release di ogni prodotto (https://release.machinefabric.com/<product>/manifest) elenca ogni artefatto con il suo digest SHA-256, ed è firmato: un .sig accanto a esso porta una firma della chiave di release di MachineFabric sui byte esatti del manifest, con il certificato della chiave rilasciato dalle sue chiavi radice.
  • Il comando lungo incorpora i digest degli archivi del runtime della sua release, presi da quel manifest; il CMake di un pacchetto C generato controlla il suo archivio (URL_HASH), e lungo runtime fetch rifiuta una discrepanza (LNG0109).
  • I pacchetti del comando sono ricavati dagli archivi elencati nel manifest, dopo averli controllati con i loro digest; i repository apt e dnf sono firmati con una chiave del repository.
  • Il modulo Go e il pacchetto Swift sono assemblati dagli archivi del runtime pubblicati, controllati con i digest del manifest; i pacchetti di PyPI, npm e crates.io sono caricati dalla stessa release.

Il wasi-sdk che collega i programmi WebAssembly è fissato allo stesso modo: lungo scarica una release fissata e ne controlla il digest SHA-256 prima di usarla.

Ciò di cui resta da fidarsi sono i repository di lungo e il processo di release che compila a partire da essi, come per qualsiasi toolchain di compilazione, e Lean stesso, il cui compilatore ha prodotto il programma.

Senza una release

Quando non è disponibile una release, una distribuzione locale fornisce la stessa struttura, costruita da lungo-rs (cargo run -p lungo-dist -- local --out DIR), e lungo generate --runtime-dir DIR fa sì che i pacchetti generati si riferiscano a essa. Pacchetti del genere funzionano solo sulla macchina che ha costruito la distribuzione.