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
lungoper 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-pysu PyPI (con il runtime di ogni piattaforma nelle sue wheel),lungo-tssu npm, il modulo Gogithub.com/machinefabric/lungo-go(con il runtime di ogni piattaforma) e il pacchetto Swiftmachinefabric/lungo-swift(il cui targetLungoRuntimeè 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.sigaccanto 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
lungoincorpora 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), elungo runtime fetchrifiuta 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.