lungo genera codice da un programma Lean come protoc fa dai file .proto: un comando, una
directory di output per linguaggio e plugin per altri linguaggi.
lungo [OPTIONS] <COMMAND>
lungo generate --c_out=gen/c --go_out=gen/go --python_out=gen/py --rust_out=gen/rust
Installazione
Con Homebrew, apt, dnf, Cargo o un download diretto per macOS, Linux e Windows: vedi
installare lungo. Compilato da lungo-rs, lungo è una build di sviluppo (vedi
il runtime).
Configurazione
La configurazione è lungo.toml nella directory corrente, un altro file indicato con
--config, oppure il progetto Lake indicato con --project insieme alle impostazioni
predefinite (vedi configurazione). Indicare sia un file sia --project è
un errore.
| Opzione | Significato |
|---|---|
--config <FILE> |
Un file di configurazione. Predefinito: ./lungo.toml quando esiste. |
--project <DIR> |
La directory del progetto Lake, al posto di un file di configurazione. |
--root <MODULE> |
Un modulo radice. Ripetibile. Si aggiunge a root-modules. |
--export <DECL> |
Una dichiarazione da esportare. Ripetibile. |
--export-module <MODULE> |
Un modulo le cui dichiarazioni vanno esportate. Ripetibile. |
--assurance-module <MODULE> |
Un modulo da cui leggere record di garanzia senza compilarlo nel programma. Ripetibile. Si aggiunge ad assurance-modules. |
--name <NAME> |
Il nome del programma. |
Queste opzioni sono globali: possono precedere o seguire il comando.
generate
lungo generate [--<language>_out=DIR]... [--<language>_opt=KEY=VALUE[,KEY=VALUE]...]... [--runtime-dir DIR] [--wasi-sdk DIR] [--verify | --link]
| Linguaggio | Output |
|---|---|
rust |
Il modulo Rust che genera build.rs, in DIR/<name>/ (vedi codice generato). |
c |
Un progetto CMake di una libreria C con l’API C del programma. |
go |
Un pacchetto Go (cgo). |
python |
Un progetto Python (scikit-build-core). |
swift |
Un pacchetto Swift, con l’API C per Objective-C. |
ts |
Un pacchetto npm (modulo ES, dichiarazioni di tipo, program.wasm). |
| qualsiasi altro nome | L’output del plugin lungo-gen-<name> trovato nel PATH (vedi plugin). |
Pacchetti generati descrive il pacchetto di ciascun linguaggio. Le
DIR sulla riga di comando sono relative alla directory corrente; le directory out della
configurazione al file di configurazione. Senza alcun --<language>_out, generate scrive gli
output indicati dalla configurazione (ogni tabella di linguaggio con out, e [rust] con
out-dir); se non ce n’è nessuno, fallisce (LNG0107).
--<language>_opt aggiunge opzioni alle options del linguaggio e le sostituisce; rust non
ha opzioni sulla riga di comando (le sue impostazioni sono tipizzate: vedi
configurazione).
Ogni directory di output appartiene a lungo: viene sostituita per intero, e una directory che
lungo non ha creato (una senza il suo build-info.json) non viene mai sostituita
(LNG0107). Un output i cui input (il progetto Lean, la toolchain, lungo,
il generatore e le sue opzioni, le politiche di fiducia e di garanzia) sono invariati, e che contiene ancora esattamente i file che ha
generato (nessuno modificato, rimosso o aggiunto da allora), viene riutilizzato: generate
stampa up to date: <language> <DIR> invece di generated <language> into <DIR>. Il progetto
viene analizzato una volta per tutti gli output (una volta in più per ts, il cui target è
WebAssembly a 32 bit).
Il codice generato spesso viene messo sotto commit, così gli utenti di un pacchetto non hanno
bisogno né di Lean né di lungo. --verify controlla che sia aggiornato: genera ogni output
senza scrivere, confronta con esso i sorgenti generati di ciascuna directory, stampa
verified: <language> <DIR> per ciascuna che corrisponde, e fallisce con
LNG0110 indicando ogni file modificato, mancante o in più. Non vengono
confrontati né build-info.json né i prodotti di piattaforma.
Un prodotto di piattaforma è un file che un output collega per la macchina che lo scrive: il
program.wasm del binding TypeScript, il programma collegato con il runtime WebAssembly.
Funziona su ogni piattaforma, ma i suoi byte dipendono dalla macchina che ha compilato il
runtime che collega, quindi due macchine collegano moduli diversi dagli stessi sorgenti. È un
prodotto della build: generato insieme ai sorgenti, mai messo sotto commit (va ignorato dal
controllo di versione; npm lo include dai files del pacchetto). --link scrive solo i
prodotti di piattaforma, per questa macchina, negli output i cui sorgenti sono aggiornati —
linked: <language> <DIR> for this machine — lasciando i sorgenti come sono; dove non lo
sono non collega nulla e fallisce con LNG0110. Un checkout esegue
--link prima di testare il binding TypeScript.
| Opzione | Significato |
|---|---|
--runtime-dir <DIR> |
Una distribuzione locale di lungo da usare al posto di quella di questa release (vedi il runtime). |
--wasi-sdk <DIR> |
Il wasi-sdk che collega il WebAssembly del binding TypeScript. Predefinito: WASI_SDK_PATH, altrimenti la release fissata del wasi-sdk, scaricata nella cache e controllata con il suo digest SHA-256. |
--verify |
Confronta i sorgenti generati invece di scrivere (sopra). |
--link |
Collega i prodotti di piattaforma di questa macchina negli output i cui sorgenti sono aggiornati (sopra). |
assurance
lungo assurance [DECLARATION] [--format human|json] [--claim-kind RELATION]... [--facility NAME]...
[--assumption NAME]... [--trust-issue ISSUE]... [--policy] [--compose FILE]...
Riporta, export per export, ciò che il codice Lean del programma afferma e dimostra di esso, ciò
che le sue dimostrazioni non coprono (la sua fiducia) e ciò che i suoi claim assumono dell’host,
tenendo separate le tre cose. Compila e analizza il progetto come check, e rifiuta un
programma i cui record di garanzia non sono validi (LNG0701–LNG0710): un rapporto su di essi
sarebbe fuorviante.
Il rapporto leggibile comincia con il programma e la sua provenienza (versione e commit di Lean,
versione di lungo, schema di garanzia), poi un blocco per export, con le sezioni
== Claims ==, == Trust ==, == Assumptions == e == Facilities ==; una sezione vuota
riporta (none). Lo stato di un claim è scritto tra parentesi quadre, [proved] o
[incomplete] (poggia su sorry), con la sua relazione, le specifiche di cui parla e le
assunzioni su cui poggia. Un’assunzione è scritta [assumed] con ciò che afferma — la sua
definizione quando è una definizione, altrimenti il suo tipo — e la sua facility:
[assumed] Polyglot.ScalesMonotonically : ∀ (a b : Nat), a ≤ b → Polyglot.hostScale a ≤ Polyglot.hostScale b (of Polyglot.Scaler)
Un export asincrono è marcato (async). --format json stampa lo
stesso come oggetto JSON: schema_version, program, provenance, exports (come in
assurance.json), i claims che li riguardano, policy (le
violazioni, con --policy) e composition (le discrepanze).
| Opzione | Significato |
|---|---|
DECLARATION |
Riporta soltanto questo export (un errore se non lo è). |
--format <FORMAT> |
human (predefinito) o json. |
--claim-kind <RELATION> |
Soltanto gli export con un claim di questa relazione, come lungo.decides. Ripetibile. |
--facility <NAME> |
Soltanto gli export che richiedono questa facility, per nome Lean o identificatore. Ripetibile. |
--assumption <NAME> |
Soltanto gli export i cui claim assumono questo, per nome Lean. Ripetibile. |
--trust-issue <ISSUE> |
Soltanto gli export con questo problema: sorry, axioms (oltre a propext, Classical.choice, Quot.sound), unsafe, partial, facility (richiede una facility dell’host), no-claim, incomplete (un claim che lo riguarda poggia su sorry), assumption (un claim che lo riguarda è condizionato a un’assunzione). Ripetibile. |
--policy |
Controlla le politiche di fiducia e di garanzia; stampa policy: satisfied, oppure le violazioni. |
--compose <FILE> |
L’assurance.json di un altro pacchetto da confrontare. Ripetibile. |
I filtri di tipo diverso devono corrispondere tutti; i valori di uno stesso tipo corrispondono se almeno uno corrisponde.
--compose controlla che pacchetti generati separatamente descrivano allo stesso modo ogni
record che condividono (una specifica, un claim, una facility o un’assunzione, per nome Lean):
dallo stesso pacchetto, con lo stesso fingerprint. Un record descritto diversamente — una specifica, o
una definizione del workspace che usa, cambiata in un pacchetto e non rigenerata nell’altro — viene
riportato come
LNG0708 con il pacchetto e il fingerprint di ciascun documento. Con una
configurazione (un lungo.toml, --config o --project), il documento del progetto stesso è
uno di quelli confrontati; senza, i file dati vengono confrontati tra loro, e ne servono almeno
due. Un file che non è un documento di garanzia leggibile da lungo è
LNG0711.
| Stato di uscita | Significato |
|---|---|
0 |
Il rapporto è stato stampato; le politiche valgono e i documenti concordano (quando controllati). |
1 |
Un errore (error[LNGxxxx]: …). |
2 |
Una violazione di politica (--policy). |
3 |
Una discrepanza di composizione (--compose). |
Il runtime
Ogni linguaggio esegue il programma sullo stesso runtime, precompilato per ogni
piattaforma e pubblicato con ogni release di lungo: i pacchetti generati si
riferiscono agli archivi del runtime della release tramite URL e digest SHA-256 (il CMake del
pacchetto C lo scarica e lo controlla; le librerie di supporto di Go, Python, Swift e TypeScript
lo contengono). Una release di lungo conosce la release del suo runtime dal manifest
incorporato.
Una build di sviluppo di lungo (compilata dai sorgenti) non conosce alcuna release.
Generare un pacchetto diverso da Rust richiede allora una distribuzione locale: una
directory organizzata come una release (runtime/, wasm/, go/, python/, lungo-swift/,
ts/), costruita da lungo-rs con cargo run -p lungo-dist -- local --out DIR e indicata con
--runtime-dir DIR. Con --python PATH contiene anche la wheel di lungo-py per questa macchina
in wheels/, perché pip la trovi (--find-links DIR/wheels) quando compila un pacchetto
Python generato. Senza di essa il comando fallisce con LNG0108. I
pacchetti generati si riferiscono allora a quella directory, quindi si compilano solo su quella
macchina.
lungo runtime fetch [--target TRIPLE]
lungo runtime path [--target TRIPLE]
lungo runtime verify [--target TRIPLE]
| Comando | Significato |
|---|---|
runtime fetch |
Scarica l’archivio del runtime per il target nella cache e lo estrae, dopo averne controllato il digest SHA-256; stampa la sua directory. Un archivio in cache già controllato viene riutilizzato. Il target predefinito è quello per cui è stato compilato lungo stesso: su Windows il comando rilasciato è compilato per l’ABI GNU, quindi x86_64-pc-windows-gnu; indica --target x86_64-pc-windows-msvc per il runtime MSVC. |
runtime path |
Stampa la directory del runtime in cache per il target, oppure fallisce se non è stato scaricato. |
runtime verify |
Scarica di nuovo l’archivio e lo controlla. |
Un download il cui digest differisce da quello della release viene scartato e segnalato come
LNG0109. Il pacchetto del runtime contiene include/lungo.h, le
librerie statiche e condivise in lib/, lib/cmake/lungo/lungoConfig.cmake e
lib/pkgconfig/lungo.pc.
Aggiornamento
lungo self update
Sostituisce questo lungo con l’ultima release del canale su cui è stato pubblicato, e stampa
lungo <vecchia> -> <nuova>, oppure lungo <versione> is the latest release quando non c’è nulla
di più recente. Legge il manifest delle release del registro in cui questo lungo è stato
pubblicato (quello indicato in installare lungo) e installa una
release solo quando valgono tutte queste condizioni:
- la firma del manifest risale alle chiavi incorporate in questo
lungo: un certificato per la chiave di release, firmato da due di quelle chiavi, valido in questo momento, e il manifest firmato da quella chiave di release; - l’archivio ha la dimensione e il digest SHA-256 elencati nel manifest;
- il comando contenuto nell’archivio si avvia e dichiara la versione con cui è stato pubblicato.
Ogni altro caso è LNG0112, e il comando installato resta com’è. Il nuovo
comando prende il posto del vecchio in un solo passo, là dove si trova il vecchio, quindi da quel
momento il lungo nel tuo PATH è la nuova release. Su Windows il comando in esecuzione non può
essere rimosso: resta accanto a quello nuovo come lungo.exe.old, e l’aggiornamento successivo lo
rimuove.
Due tipi di lungo non si aggiornano in questo modo, e dicono che cosa li aggiorna
(LNG0111):
| Installato con | Si aggiorna con |
|---|---|
| Homebrew | brew upgrade machinefabric/tap/lungo |
| apt | sudo apt update && sudo apt install --only-upgrade lungo |
| dnf | sudo dnf upgrade lungo |
| Cargo, o compilato da lungo-rs | cargo install lungo-cli, oppure compila i sorgenti più recenti |
Il lungo di un gestore di pacchetti si riconosce dal file installed-by che il suo pacchetto
mette accanto al comando. Un lungo installato dove non puoi scrivere — /usr/local/bin, con
sudo install — si aggiorna con gli stessi diritti: sudo lungo self update.
Altri comandi
| Comando | Output |
|---|---|
check |
Compila il progetto e lo traduce (Rust e C) senza scrivere output; stampa la toolchain, il numero di moduli, le dichiarazioni compilate, gli extern e gli export, la garanzia del programma (specifiche, claim dimostrati e incompleti, facility, assunzioni, e quanti export hanno claim dimostrati), e gli eventuali avvisi. |
inspect <DECL> |
Per una dichiarazione: tipo Lean, modulo, sorgente (relativo alla configurazione); per un export, i suoi claim, la fiducia, le assunzioni e le facility come li riporta assurance, poi la sua fiducia per intero; per un teorema che è l’evidenza di un claim, il claim (stato, relazione, soggetti, enunciato, specifiche, assunzioni, assiomi dell’evidenza, fingerprint); per una specifica, il suo tipo di specifica, il fingerprint, ciò che afferma (la sua definizione quando è una definizione, altrimenti il suo tipo) e i claim che la citano; per un’assunzione, la sua facility e ciò che afferma (allo stesso modo); per una facility, che cos’è; poi la firma compilata, gli ausiliari del compilatore, la voce extern. |
ir <DECL> |
La Bridge IR della dichiarazione e degli ausiliari che il compilatore ne ha derivato. |
rust <DECL> |
Il Rust generato per la dichiarazione: il codice del livello del compilatore e, se esportata, la sua funzione di facciata. |
externs |
externs.json: ogni extern raggiunto dal programma e la sua implementazione Rust. |
mappings |
names.json: ogni mappatura di nomi da Lean a Rust. |
prepare |
Compila (o verifica) il worker per la toolchain del progetto; stampa la versione di Lean, il commit, l’identità del worker e la sua posizione. |
setup |
Installa con elan la toolchain fissata, materializza le dipendenze bloccate in lake-manifest.json e prepara il worker. |
Gli errori vengono stampati come error[LNGxxxx]: … (vedi errori) e il comando
esce con stato 1 (assurance ha altri due stati: vedi sopra).
Esempio
$ lungo generate --go_out=gen/formal --python_out=gen/py
generated go into gen/formal
generated python into gen/py
$ lungo inspect Formal.step
Formal.step : Formal.Sess → Formal.Op → Bool × Formal.Sess
module: Formal.Session
source: lean/Formal/Session.lean
exported: yes
== Claims ==
[proved] lungo.preserves Formal.step_implements (of Formal.Spec)
== Trust ==
(none)
== Assumptions ==
(none)
== Facilities ==
(none)
== Trust, in full ==
axioms: (none)
depends on sorry: false
unsafe dependencies: (none)
partial dependencies: (none)
extern dependencies: lean_nat_add
compiled: (obj, u8) -> obj in module Formal.Session
compiler auxiliaries: Formal.step._boxed