lungo si configura in due posti che descrivono le stesse impostazioni:
lungo.toml, letto dal comandolungo, per ogni linguaggio di output;- un
lungo_build::Builderin unbuild.rsdi Cargo, per l’output Rust (compile_lean(project)equivale aconfigure().compile_lean(project)).
Ogni impostazione ha un valore predefinito. Le chiavi sconosciute sono errori
(LNG0107).
# lungo.toml
project = "lean"
[lean]
root-modules = ["Formal.Session"]
assurance-modules = ["Formal.Laws"]
[assurance]
require-claims = ["Formal.Session"]
[rust]
out-dir = "src/generated"
type-attributes = [
{ path = "Formal", attribute = "#[derive(serde::Serialize, serde::Deserialize)]" },
]
rust-externs = { host_log = "crate::host::log" }
[go]
out = "gen/formal"
options = { package = "formal" }
[plugins.kotlin]
out = "gen/kotlin"
// build.rs
fn main() -> lungo_build::Result<()> {
lungo_build::configure()
.root_module("Formal.Session")
.assurance_module("Formal.Laws")
.require_claims("Formal.Session")
.type_attribute("Formal", "#[derive(serde::Serialize, serde::Deserialize)]")
.rust_extern("host_log", "crate::host::log")
.compile_lean("lean")
}
Il file
| Chiave | Significato |
|---|---|
project |
La directory del progetto Lake. Obbligatoria. |
[lean] |
Le impostazioni condivise da tutti i linguaggi: che cosa viene compilato ed esportato, i moduli letti per i loro record di garanzia, la politica di fiducia, il nome del programma, il worker, la toolchain. |
[assurance] |
La politica di garanzia: gli export che devono avere un claim dimostrato, e le assunzioni su cui nulla può poggiare. |
[rust] |
Le impostazioni del generatore Rust. |
[c], [go], [python], [swift], [ts] |
La directory di output di un generatore integrato, le sue opzioni e i suoi tipi extern. |
[plugins.<name>] |
La directory di output e le opzioni di un plugin. <name> è composto da lettere minuscole, cifre e -, e non è il nome di un generatore integrato. |
I percorsi nel file (project, out, out-dir, toolchain-dir) sono relativi alla
directory del file. lungo tiene i file di lavoro in .lungo/ accanto al file; aggiungila a
.gitignore.
Programma
Si impostano in [lean], oppure con i metodi del Builder:
| Builder | Chiave TOML | Tipo | Predefinito | Significato |
|---|---|---|---|---|
root_module(m) |
root-modules |
lista di nomi di modulo | le radici dei target predefiniti | Moduli del progetto il cui codice viene compilato, con tutto ciò che importano. Ciascuno deve appartenere al pacchetto radice del progetto. |
export(d) |
exports |
lista di nomi di dichiarazione | [] |
Dichiarazioni che ricevono funzioni pubbliche. |
export_module(m) |
export-modules |
lista di nomi di modulo | [] |
Moduli (con i loro sottomoduli) le cui definizioni pubbliche ricevono funzioni pubbliche. |
assurance_module(m) |
assurance-modules |
lista di nomi di modulo | [] |
Moduli caricati soltanto per i record di garanzia che dichiarano, come leggi dimostrate a parte rispetto al codice di cui parlano. Vengono importati nell’ambiente che lungo legge ma mai compilati nel programma, quindi non cambiano nulla di ciò che il programma fa. Ciascuno deve appartenere a un pacchetto del workspace Lake e non essere un modulo radice. |
name(n) |
name |
stringa | il nome del pacchetto Lake | Il nome del programma: del modulo generato, del pacchetto e del prefisso dei simboli. Lettere, cifre, _ e -, senza iniziare con una cifra o con -. |
Quali extern implementa l’host non è un’impostazione: li dichiara il codice Lean del programma,
come operazioni di facility (@[lungo_facility] e @[lungo_operation]; vedi come chiamare
codice dell’host da Lean). Ogni pacchetto generato
chiede all’host ogni operazione di ogni facility dichiarata dai moduli collegati del programma.
La chiave extern di un’operazione è il simbolo del suo @[extern "symbol"], oppure il nome
della dichiarazione per le altre forme di extern.
Senza root_module, le radici sono ciò che compila lake build: i moduli radice di ogni
target predefinito del pacchetto radice (defaultTargets in lakefile.toml,
@[default_target] in lakefile.lean), che sono librerie Lean (le loro roots) o eseguibili
Lean (il loro root). Un pacchetto senza target predefiniti richiede root_module
(LNG0301).
Senza export ed export_module, vengono esportati i moduli radice e i loro sottomoduli. Da un
modulo esportato si esportano le definizioni, tranne quelle private, interne (componenti con
prefisso _), le istanze e i loro metodi, quelle generate dal compilatore (ricorsori,
matcher, noConfusion, proiezioni, costruttori, ausiliari strutturali), i tipi di nodo
sintattico (syntax, notation, macro) e le definizioni meta.
Politica di fiducia
Si impostano in [lean]:
| Builder | Chiave TOML | Predefinito | Rifiuta un export che… |
|---|---|---|---|
deny_sorry(b) |
deny-sorry |
true |
dipende da sorry |
deny_axioms(b) |
deny-axioms |
false |
dipende da un assioma diverso da propext, Classical.choice, Quot.sound |
deny_unsafe(b) |
deny-unsafe |
false |
ha una definizione unsafe nella sua chiusura eseguibile (fuori dalla toolchain di Lean) |
deny_sorry e deny_axioms si applicano anche all’evidenza di ogni claim (il teorema che
nomina): un claim dimostrato con sorry, o con un assioma che la politica nega, viene rifiutato
come lo sarebbe un export. Con deny-sorry = false, un tale claim viene riportato con stato
incomplete, e non conta come claim dimostrato per require-claims.
Le violazioni fanno fallire la build con LNG0601.
Politica di garanzia
Si impostano in [assurance], oppure con i metodi del Builder. lungo controlla prima i record di garanzia del
programma (la loro forma, le dichiarazioni che nominano, la forma di ogni claim); un problema in
uno di essi fa fallire la build qualunque sia la politica, con un codice proprio
(LNG0701–LNG0710). Poi:
| Builder | Chiave TOML | Predefinito | Significato |
|---|---|---|---|
require_claims(path) |
require-claims |
[] |
Ogni export selezionato dal percorso deve essere soggetto di almeno un claim dimostrato (LNG0602 altrimenti). . seleziona ogni export; ogni altro percorso seleziona l’export che nomina e ogni export al suo interno come namespace (Formal seleziona Formal.apply, Formal.Se non seleziona nulla). |
forbid_assumption(name) |
forbid-assumptions |
[] |
Nessun claim dimostrato può assumere l’assunzione name; se name è una facility, nessun claim può assumere una delle sue assunzioni e nessun export può chiamare una delle sue operazioni (LNG0603 altrimenti). |
Un percorso che non seleziona alcun export, o un nome che non è né un’assunzione né una facility
del programma, è un errore (LNG0107): non potrebbe avere alcun effetto.
La politica fa parte di ciò da cui un output viene generato: renderla più stringente fa sì che
lungo generate controlli di nuovo un output invece di considerarlo aggiornato.
Worker
Si impostano in [lean]:
| Builder | Chiave TOML | Predefinito | Significato |
|---|---|---|---|
worker_timeout(d) |
worker-timeout |
nessuno | Secondi di tempo reale dopo i quali i processi del worker vengono terminati (LNG0304). |
worker_cpu_limit(d) |
worker-cpu-limit |
nessuno | Secondi di processore che il worker può usare (LNG0305). |
worker_memory_limit(bytes) |
worker-memory-limit |
nessuno | Memoria che il worker può usare. Applicato su Linux e Windows; un errore (LNG0104) altrove. |
hermetic(b) |
hermetic |
false |
Esegue il worker con soltanto PATH, HOME, USERPROFILE, SystemRoot, SYSTEMROOT, TEMP, TMP, TMPDIR, LANG, LC_ALL, ELAN_HOME, LOCALAPPDATA, APPDATA dell’ambiente, più l’ambiente di Lake per il progetto. |
hermetic_worker_cache(b) |
hermetic-worker-cache |
false |
Tiene il worker compilato accanto all’output della build invece che nella cache condivisa. |
lean_option(name, value) |
lean-options |
{} |
Opzioni di Lean in vigore mentre il worker carica il progetto ed esegue metaprogrammi Lean. |
max_errors(n) |
max-errors |
0 |
Riporta al massimo n errori del worker; 0 li riporta tutti. |
Toolchain
Si impostano in [lean]:
| Builder | Chiave TOML | Predefinito | Significato |
|---|---|---|---|
toolchain_policy(p) |
install-toolchain |
Strict / false |
Install (true) installa con elan una toolchain fissata mancante. Strict (false) fallisce con LNG0103. |
toolchain_dir(dir) |
toolchain-dir |
l’installazione di elan | Usa la toolchain installata in dir. |
Rust
Si impostano in [rust], oppure con i metodi del Builder:
| Builder | Chiave TOML | Predefinito | Significato |
|---|---|---|---|
mode(m) |
mode |
pure-rust |
pure-rust genera Rust sul runtime di lungo. lean-oracle esegue il backend nativo di Lean dietro la stessa API (vedi piattaforme). |
rust_extern(key, path) |
rust-externs |
{} |
La funzione Rust che implementa ciascuna operazione delle facility del programma: chiave extern → percorso Rust. Ogni operazione dichiarata dal programma ne ha una (LNG0401 altrimenti). Una chiave che è un extern ma non un’operazione viene rifiutata (LNG0706), e una chiave che nessun extern usa è inutilizzata (LNG0405). |
out_dir(d) |
out-dir |
$OUT_DIR/lungo |
La directory che riceve <name>/. In build.rs è relativa al pacchetto Cargo, e include_lean! trova solo quella predefinita (usa include! per un’altra). Per lungo generate, l’output Rust (--rust_out la sostituisce). |
facade_namespace(n) |
facade-namespace |
il primo componente del primo modulo radice | Il namespace Lean posto alla radice del modulo generato. I nomi al di fuori vengono posti sotto _root_. |
embed_sources(b) |
embed-sources |
false |
Incorpora i sorgenti Lean locali, disponibili tramite __meta::source. |
emit_rerun_if_changed(b) |
emit-rerun-if-changed |
se la build gira sotto Cargo | Stampa cargo::rerun-if-changed per ogni input, e cargo::rerun-if-env-changed per le variabili d’ambiente. |
Uno script di build può compilare più progetti Lean; ciascuno genera il proprio modulo, e due
che genererebbero lo stesso modulo sono un errore (LNG0107). Dai a uno
dei due un altro name.
Modellare il codice generato
Queste impostazioni selezionano elementi generati tramite un percorso. Il percorso .
seleziona ogni elemento; qualsiasi altro percorso seleziona il nome Lean che compone e ogni nome
al suo interno inteso come namespace: Formal seleziona Formal.Sess e
Formal.Sess.isOpen, ma Formal.Se non seleziona nessuno dei due. I campi si indicano come in
names.json: <Structure>.<field>, <Constructor>.<binder>
oppure <Constructor>#<index>. Un percorso diverso da . che non seleziona nulla è un errore
(LNG0107): non può avere alcun effetto.
| Builder | Chiave TOML | Predefinito | Significato |
|---|---|---|---|
type_attribute(path, attr) |
type-attributes |
[] |
Aggiunge l’attributo Rust attr a ogni struct ed enum generato selezionato da path. |
struct_attribute(path, attr) |
struct-attributes |
[] |
Lo stesso, solo per le struct. |
enum_attribute(path, attr) |
enum-attributes |
[] |
Lo stesso, solo per gli enum. |
field_attribute(path, attr) |
field-attributes |
[] |
Aggiunge attr a ogni campo di un tipo generato selezionato da path. |
skip_debug(paths) |
skip-debug |
[] |
Genera i tipi selezionati senza #[derive(Debug)], perché l’applicazione implementi Debug. |
disable_comments(paths) |
disable-comments |
[] |
Genera i tipi e le funzioni selezionati senza commenti di documentazione. |
extern_type(lean, path) |
extern-types |
{} |
Usa il tipo Rust esistente in path per il tipo Lean lean invece di generarne uno. |
In TOML, le impostazioni degli attributi sono liste di tabelle { path, attribute },
skip-debug e disable-comments liste di percorsi, ed extern-types una tabella da tipo Lean
a percorso Rust.
Gli attributi si scrivono come nel sorgente Rust, #[…], e vengono posti dopo le derivazioni
generate da lungo (Clone, Debug, e PartialEq, Eq, Hash dove ogni campo le ha), quindi
possono essere #[derive(…)] di altri trait o attributi di quelle derivazioni, come
#[serde(…)]. La feature serde del crate lungo implementa serde per i
tipi della facciata.
Un tipo extern implementa lungo::LeanType per il backend in uso, ha i parametri del tipo Lean
e rappresenta i suoi valori come fa il tipo Lean; in pratica è il tipo che un’altra build di
lungo ha generato per lo stesso tipo Lean. Non viene generato, e i tipi che lo contengono
derivano solo Clone e Debug. Implementa anche lungo::LeanLayout con l’impronta del
layout del tipo Lean, che il modulo generato controlla quando viene compilato (vedi
tipi extern); un tipo generato da lungo la implementa già. Vedi
Come condividere tipi tra progetti Lean.
Opzioni dei generatori
La tabella di un linguaggio contiene la sua directory di output, out, e le sue opzioni,
options, una tabella di stringhe. --<language>_opt=KEY=VALUE dalla riga di comando le
integra (e le sostituisce). Un generatore rifiuta le opzioni che non conosce.
| Linguaggio | Opzione | Predefinito | Significato |
|---|---|---|---|
c |
embed |
assente | true: una directory del progetto CMake dell’host invece di un progetto a sé (incorporato). |
go |
package |
l’identificatore C del programma, in minuscolo | Il nome del pacchetto Go. |
python |
package |
l’identificatore C del programma, in minuscolo | Il nome di import. |
python |
distribution |
package con _ al posto di - |
Il nome della distribuzione (PyPI). |
python |
version |
0.1.0 |
La versione della distribuzione. |
python |
embed |
assente | Un modulo puntato del pacchetto dell’host (host.formal, oppure host._formal per uno privato): l’output è quel modulo, incorporato, senza una distribuzione propria. Esclude package, distribution e version. |
swift |
module |
il nome del programma in UpperCamelCase | Il modulo Swift; il target C è <module>Program. |
swift |
embed |
assente | true: i due target che il pacchetto dell’host deve dichiarare, senza Package.swift (incorporato). |
ts |
package |
il nome del programma, in minuscolo | Il nome del pacchetto npm. |
ts |
version |
0.1.0 |
La versione del pacchetto. |
ts |
embed |
assente | true: un modulo del pacchetto dell’host, senza package.json (incorporato). Esclude package e version. |
Go è sempre un pacchetto del modulo dell’host; non ha embed. Vedi
pacchetti generati per ciò che scrive ciascun generatore.
Tipi extern
Un programma costruito sul modello di un altro programma (un pacchetto Lake che ne richiede un
altro) usa i tipi di quel programma. Generati separatamente, ogni pacchetto avrebbe il proprio
tipo per essi, e un valore dell’uno non potrebbe essere passato all’altro. La tabella
extern-types di un linguaggio indica, per un tipo Lean, il tipo dell’altro pacchetto
generato da usare al suo posto:
[go.extern-types."TaggedUrn.Exec.Wf"]
package = "github.com/machinefabric/tagged-urn-go/formal" # ciò che un import indica
name = "Wf" # il tipo, come lo ha chiamato quel generatore
| Linguaggio | package |
name |
|---|---|---|
c |
l’header del pacchetto che lo fornisce (provider.h) |
il prefisso dei suoi elementi per il tipo (provider_pos) |
go |
il percorso di import | il tipo Go |
python |
il modulo | la classe |
swift |
il modulo | il tipo |
ts |
lo specificatore di modulo | il tipo |
Il tipo deve essere usato dalle funzioni o dalle operazioni delle facility del programma
(LNG0107 altrimenti). I valori passano allora tra i due pacchetti così
come sono: i dati per valore, e i valori tenuti tramite handle come lo stesso handle, poiché
ogni pacchetto di un processo gira sull’unico runtime.
In TypeScript ogni programma gira in una propria istanza WebAssembly, con una propria tabella di handle, quindi possono essere tipi extern solo i tipi i cui valori sono dati; un tipo i cui valori contengono un handle (un tipo opaco, una funzione) viene rifiutato indicandone il motivo.
Entrambi i pacchetti devono essere stati generati dalla stessa definizione del tipo, altrimenti
un programma leggerebbe i valori dell’altro con il layout sbagliato. Ogni tipo generato porta
l’impronta del suo layout (un digest dei suoi costruttori, dei loro campi e di ogni tipo che
raggiungono, insieme alla versione di Lean), e un pacchetto che usa un tipo extern controlla
quella del pacchetto che lo fornisce prima che qualcosa venga eseguito: in fase di
compilazione in Rust, al caricamento del pacchetto in Go (init), Python (import), Swift e C
(il primo uso del programma), e in TypeScript (la valutazione del modulo). Una discrepanza
indica il tipo e il pacchetto; rigenerali entrambi dalla stessa definizione Lean.
Variabili d’ambiente
| Variabile | Significato |
|---|---|
ELAN_HOME |
Dove elan tiene le toolchain (predefinito ~/.elan). |
LUNGO_CACHE_DIR |
Radice della cache di lungo: i worker compilati in workers/, i runtime scaricati in runtime/, il wasi-sdk in wasi-sdk/. Predefiniti: $XDG_CACHE_HOME/lungo, ~/.cache/lungo oppure %LOCALAPPDATA%\lungo. |
WASI_SDK_PATH |
Un wasi-sdk con cui collegare il WebAssembly del binding TypeScript, al posto della release fissata che lungo scarica. |
Punti di ingresso
| Funzione | Uso |
|---|---|
compile_lean(project) |
In build.rs, con la configurazione predefinita. |
configure() |
Un Builder con la configurazione predefinita. |
Builder::compile_lean(self, project) |
In build.rs. Genera in <out_dir>/<name> e stampa le direttive di Cargo: rerun-if-changed (vedi emit_rerun_if_changed) e, in modalità LeanOracle, le direttive di collegamento. project è relativo al pacchetto Cargo. |
Builder::run(&self, project, &Environment) |
La stessa pipeline per un dato Environment; restituisce un BuildOutcome. |
Builder::analyze / Builder::generate |
Le due metà di run: l’analisi del worker, poi la generazione del codice, senza pubblicare. |
Builder::from_options(lean, rust, assurance) |
Un Builder a partire da LeanOptions ([lean]), RustOptions ([rust]) e AssurancePolicy ([assurance]). |