In this section

lungo is configured in two places that describe the same settings:

  • lungo.toml, read by the lungo command, for every output language;
  • a lungo_build::Builder in a Cargo build.rs, for the Rust output (compile_lean(project) is configure().compile_lean(project)).

Every setting has a default. Unknown keys are errors (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")
}

The file

Key Meaning
project The Lake project directory. Required.
[lean] The settings every language shares: what is compiled and exported, the modules read for their assurance records, the trust policy, the program’s name, the worker, the toolchain.
[assurance] The assurance policy: the exports that must carry a proved claim, and the assumptions nothing may rest on.
[rust] The Rust generator’s settings.
[c], [go], [python], [swift], [ts] A built-in generator’s output directory, options and extern types.
[plugins.<name>] A plugin’s output directory and options. <name> is lowercase letters, digits and -, and not the name of a built-in generator.

Paths in the file (project, out, out-dir, toolchain-dir) are relative to the file’s directory. lungo keeps scratch files in .lungo/ next to the file; add it to .gitignore.

Program

Set in [lean], or with the Builder methods:

Builder TOML key Type Default Meaning
root_module(m) root-modules list of module names the default targets’ roots Modules of the project whose code is compiled, with everything they import. Each must belong to the project’s root package.
export(d) exports list of declaration names [] Declarations that receive public functions.
export_module(m) export-modules list of module names [] Modules (with their submodules) whose public definitions receive public functions.
assurance_module(m) assurance-modules list of module names [] Modules loaded only for the assurance records they declare, such as laws proved apart from the code they are about. They are imported into the environment lungo reads but never compiled into the program, so they change nothing the program does. Each must belong to a package of the Lake workspace and not be a root module.
name(n) name string the Lake package’s name The program’s name: of the generated module, package and symbol prefix. Letters, digits, _ and -, not starting with a digit or -.

Which externs the host implements is not a setting: the program’s Lean code declares them, as the operations of facilities (@[lungo_facility] and @[lungo_operation]; see how to call host code from Lean). Every generated package asks the host for every operation of every facility the program’s linked modules declare. An operation’s extern key is the symbol of its @[extern "symbol"], or the declaration’s name for the other extern forms.

Without root_module, the roots are what lake build builds: the root modules of every default target of the root package (defaultTargets in lakefile.toml, @[default_target] in lakefile.lean), which are Lean libraries (their roots) or Lean executables (their root). A package without default targets needs root_module (LNG0301).

Without export and export_module, the root modules and their submodules are exported. From an exported module, definitions are exported unless they are private, internal (_-prefixed components), instances or their methods, compiler-generated (recursors, matchers, noConfusion, projections, constructors, structural auxiliaries), syntax node kinds (syntax, notation, macro), or meta definitions.

Trust policy

Set in [lean]:

Builder TOML key Default Rejects an export that…
deny_sorry(b) deny-sorry true depends on sorry
deny_axioms(b) deny-axioms false depends on an axiom other than propext, Classical.choice, Quot.sound
deny_unsafe(b) deny-unsafe false has an unsafe definition in its executable closure (outside the Lean toolchain)

deny_sorry and deny_axioms also apply to the evidence of every claim (the theorem it names): a claim proved with sorry, or with an axiom the policy denies, is refused as an export would be. With deny-sorry = false, such a claim is reported with status incomplete, and is not a proved claim for require-claims.

Violations fail the build with LNG0601.

Assurance policy

Set in [assurance], or with the Builder methods. lungo first checks the program’s assurance records themselves (their form, the declarations they name, the shape of each claim); a problem with one fails the build whatever the policy, with its own code (LNG0701–LNG0710). Then:

Builder TOML key Default Meaning
require_claims(path) require-claims [] Every export the path selects must be the subject of at least one proved claim (LNG0602 otherwise). . selects every export; any other path selects the export it names and every export in it as a namespace (Formal selects Formal.apply, Formal.Se selects nothing).
forbid_assumption(name) forbid-assumptions [] No proved claim may assume the assumption name; if name is a facility, no claim may assume any of its assumptions and no export may call any of its operations (LNG0603 otherwise).

A path that selects no export, or a name that is neither an assumption nor a facility of the program, is an error (LNG0107): it cannot have any effect.

The policy is part of what an output is generated from: tightening it makes lungo generate check an output again rather than keep it as up to date.

Worker

Set in [lean]:

Builder TOML key Default Meaning
worker_timeout(d) worker-timeout none Wall-clock seconds after which the worker’s processes are killed (LNG0304).
worker_cpu_limit(d) worker-cpu-limit none Processor seconds the worker may use (LNG0305).
worker_memory_limit(bytes) worker-memory-limit none Memory the worker may use. Enforced on Linux and Windows; an error (LNG0104) elsewhere.
hermetic(b) hermetic false Run the worker with only PATH, HOME, USERPROFILE, SystemRoot, SYSTEMROOT, TEMP, TMP, TMPDIR, LANG, LC_ALL, ELAN_HOME, LOCALAPPDATA, APPDATA from the environment, plus Lake’s environment for the project.
hermetic_worker_cache(b) hermetic-worker-cache false Keep the compiled worker beside the build output instead of in the shared cache.
lean_option(name, value) lean-options {} Lean options in effect while the worker loads the project and runs Lean metaprograms.
max_errors(n) max-errors 0 Report at most n errors from the worker; 0 reports all.

Toolchain

Set in [lean]:

Builder TOML key Default Meaning
toolchain_policy(p) install-toolchain Strict / false Install (true) installs a missing pinned toolchain with elan. Strict (false) fails with LNG0103.
toolchain_dir(dir) toolchain-dir elan’s installation Use the toolchain installed in dir.

Rust

Set in [rust], or with the Builder methods:

Builder TOML key Default Meaning
mode(m) mode pure-rust pure-rust generates Rust on the lungo runtime. lean-oracle runs Lean’s native backend behind the same API (see platforms).
rust_extern(key, path) rust-externs {} The Rust function implementing each operation of the program’s facilities: extern key → Rust path. Every operation the program declares has one (LNG0401 otherwise). A key that is an extern but not an operation is refused (LNG0706), and a key no extern uses is unused (LNG0405).
out_dir(d) out-dir $OUT_DIR/lungo The directory receiving <name>/. In build.rs, relative to the Cargo package, and include_lean! finds only the default (use include! for another). For lungo generate, the Rust output (--rust_out overrides it).
facade_namespace(n) facade-namespace first component of the first root module The Lean namespace placed at the root of the generated module. Names outside it are placed under _root_.
embed_sources(b) embed-sources false Embed the local Lean sources, available through __meta::source.
emit_rerun_if_changed(b) emit-rerun-if-changed whether the build runs under Cargo Print cargo::rerun-if-changed for every input, and cargo::rerun-if-env-changed for the environment variables.

One build script may compile several Lean projects; each generates its own module, and two that would generate the same module are an error (LNG0107). Give one of them another name.

Shaping the generated code

These settings select generated items by path. The path . selects every item; any other path selects the Lean name it spells and every name in it as a namespace: Formal selects Formal.Sess and Formal.Sess.isOpen, but Formal.Se selects neither. Fields are named as in names.json: <Structure>.<field>, <Constructor>.<binder>, or <Constructor>#<index>. A path other than . that selects nothing is an error (LNG0107): it cannot have any effect.

Builder TOML key Default Meaning
type_attribute(path, attr) type-attributes [] Adds the Rust attribute attr to every generated struct and enum path selects.
struct_attribute(path, attr) struct-attributes [] The same, for structs only.
enum_attribute(path, attr) enum-attributes [] The same, for enums only.
field_attribute(path, attr) field-attributes [] Adds attr to every field of a generated type path selects.
skip_debug(paths) skip-debug [] Generates the selected types without #[derive(Debug)], for the application to implement Debug.
disable_comments(paths) disable-comments [] Generates the selected types and functions without documentation comments.
extern_type(lean, path) extern-types {} Uses the existing Rust type at path for the Lean type lean instead of generating one.

In TOML, attribute settings are lists of { path, attribute } tables, skip-debug and disable-comments lists of paths, and extern-types a table from Lean type to Rust path.

Attributes are written as in Rust source, #[…], and are placed after the derives lungo generates (Clone, Debug, and PartialEq, Eq, Hash where every field has them), so they may be #[derive(…)]s of further traits or attributes of those derives, such as #[serde(…)]. The serde feature of the lungo crate implements serde for the facade types.

An extern type implements lungo::LeanType for the backend in use, has the Lean type’s parameters, and represents its values as the Lean type does; in practice it is the type another lungo build generated for the same Lean type. It is not generated, and types containing it derive only Clone and Debug. It also implements lungo::LeanLayout with the Lean type’s layout fingerprint, which the generated module checks when it is compiled (see extern types); a type generated by lungo implements it already. See How to share types between Lean projects.

Generator options

A language’s table holds its output directory, out, and its options, options, a table of strings. --<language>_opt=KEY=VALUE on the command line adds to (and overrides) them. A generator rejects options it does not know.

Language Option Default Meaning
c embed absent true: a directory of the host’s CMake project rather than a project of its own (embedded).
go package the program’s C identifier, lowercased The Go package name.
python package the program’s C identifier, lowercased The import name.
python distribution package with _ as - The distribution (PyPI) name.
python version 0.1.0 The distribution’s version.
python embed absent A dotted module of the host’s package (host.formal, or host._formal for one private to it): the output is that module, embedded, with no distribution of its own. Excludes package, distribution and version.
swift module the program’s name in UpperCamelCase The Swift module; the C target is <module>Program.
swift embed absent true: the two targets for the host package to declare, with no Package.swift (embedded).
ts package the program’s name, lowercased The npm package name.
ts version 0.1.0 The package’s version.
ts embed absent true: a module of the host’s package, with no package.json (embedded). Excludes package and version.

Go is always a package of the host’s module; it has no embed. See generated packages for what each generator writes.

Extern types

A program built on another program’s model (a Lake package requiring another) uses that program’s types. Generated separately, each package would have its own type for them, and a value of one could not be passed to the other. A language’s extern-types table names, for a Lean type, the other generated package’s type to use instead:

[go.extern-types."TaggedUrn.Exec.Wf"]
package = "github.com/machinefabric/tagged-urn-go/formal"   # what an import names
name = "Wf"                                                 # the type, as that generator named it
Language package name
c the providing package’s header (provider.h) the prefix of its items for the type (provider_pos)
go the import path the Go type
python the module the class
swift the module the type
ts the module specifier the type

The type must be one the program’s functions or facility operations use (LNG0107 otherwise). Values then pass between the two packages as they are: data by value, and values held by handle as the same handle, since every package of a process runs on the one runtime.

In TypeScript each program runs in a WebAssembly instance of its own, with a handle table of its own, so only types whose values are data can be extern types; a type whose values hold a handle (an opaque type, a function) is refused with the reason.

Both packages must have been generated from the same definition of the type, or one program would read the other’s values at the wrong layout. Every generated type carries its layout fingerprint (a digest of its constructors, their fields and every type they reach, with the Lean version), and a package using an extern type checks the providing package’s before anything runs: at compile time in Rust, when the package is loaded in Go (init), Python (import), Swift and C (the program’s first use), and TypeScript (module evaluation). A mismatch names the type and the package; regenerate both from the same Lean definition.

Environment variables

Variable Meaning
ELAN_HOME Where elan keeps toolchains (default ~/.elan).
LUNGO_CACHE_DIR Root of lungo’s cache: compiled workers in workers/, downloaded runtimes in runtime/, the wasi-sdk in wasi-sdk/. Defaults: $XDG_CACHE_HOME/lungo, ~/.cache/lungo, or %LOCALAPPDATA%\lungo.
WASI_SDK_PATH A wasi-sdk to link the TypeScript binding’s WebAssembly with, instead of the pinned release lungo downloads.

Entry points

Function Use
compile_lean(project) In build.rs, with the default configuration.
configure() A Builder with the default configuration.
Builder::compile_lean(self, project) In build.rs. Generates into <out_dir>/<name> and prints Cargo directives: rerun-if-changed (see emit_rerun_if_changed) and, in LeanOracle mode, link directives. project is relative to the Cargo package.
Builder::run(&self, project, &Environment) The same pipeline for a given Environment; returns a BuildOutcome.
Builder::analyze / Builder::generate The two halves of run: the worker’s analysis, then code generation, without publishing.
Builder::from_options(lean, rust, assurance) A Builder of a LeanOptions ([lean]), a RustOptions ([rust]) and an AssurancePolicy ([assurance]).