Clause
← All documentation

Executables

Contract for programs built by clau -o or a project build. Positional inputs, or exactly one selected project target, link into the -o path; a project build links each selected executable target to its manifest output (linking, projects).

Entry selection

The entry is an exported function of arity 1 that receives the argument list.

SourceSpellingScope
CLI--entry MODULE[:FUNCTION]Positional batch, or the single selected project target
Manifestentry = "MODULE[:FUNCTION]" in a [[targets]] tableThat target
DefaultOnly escript, else only module exporting main/1Only when an executable is requested (-o, or a project target with output)
FailureDiagnostic (exit 1)
Module not in the batch<origin>: entry module M is not among the compiled modules (origin: --entry or manifest file:line:col [target t] (entry))
No F/1<file>:<line>:<col>: entry function M:F/1 is not defined at the module declaration
Only other arities... is not defined; found F/N, but the entry receives one argument (the argument list) at that definition
F/1 not exported<file>:<line>:<col>: entry function M:F/1 is not exported at the definition
No selection, no main/1 exportno entry point: no module exports main/1; choose the entry with --entry MODULE[:FUNCTION] (an exported FUNCTION/1; FUNCTION defaults to main)
No selection, severalambiguous entry point: main/1 is exported by a, b; choose the entry with ... (same hint)

For project targets the hint also names the manifest key: ... --entry MODULE[:FUNCTION] or with entry = "MODULE[:FUNCTION]" in this target's [[targets]] table of the project manifest ..., for example:

[[targets]]
name = "app"
sources = ["src/*.erl"]
entry = "app:start"   # calls app:start/1; plain "app" calls app:main/1

Arguments

Entry(Argv) receives a proper list of strings (lists of Unicode code points), excluding the program name and the leading runtime options, otherwise unchanged and in order, like escript.

Runtime options

The runtime reads its options from the CLAUSE_FLAGS environment variable (words split on spaces and tabs, no quoting) and then from the leading command-line arguments, so the command line wins. Both are parsed the same way; a value goes in the next argument or after =.

OptionEffect
--max-atoms NAtom table size, 1 to 2^26 (67,108,864); default 2^20 (1,048,576), like OTP's +t
--max-heap BYTESCap on each process's heap block, fragments and off-heap binaries, at least the minimum heap (233 words); default uncapped
--max-stack BYTESCap on each process's frame stack; default uncapped
--max-memory BYTESCap on the memory of all processes together (heaps, off-heap binaries, stacks); default uncapped
--schedulers NScheduler workers running processes, 1 to 1,024; default one per logical processor, like OTP's +S (workers)
--args-file FILEOptions file like OTP's vm.args: reserved, reports runtime option --args-file is not implemented
--Ends the runtime options; the following arguments all go to Entry

On the command line, parsing stops at the first argument that is not a runtime option, so prog data --max-atoms 9 passes all three arguments to the program. In CLAUSE_FLAGS every word must be a runtime option. An invalid value, a word that is not an option in the variable, or --args-file stops the program before any module is registered: clau: runtime failure: <reason>, exit 70. Process counts are not limited and memory is uncapped by default. Byte values are decimal without suffixes and round down to whole words; a program reaching a cap fails with resource_limit, exit 70 (runtime memory limit).

Exit status

OutcomeStatus
Entry returns (any value)0
erlang:halt()0
erlang:halt(N), non-negative integerN (POSIX hosts keep the low 8 bits)
erlang:halt(Slogan) with a stringSlogan on stderr, then 1 (no crash dump)
erlang:halt(abort)Native abort (no flushing)
Any exception escaping the entry, including throw and exit(normal)Report on stderr, 1
Entry process ended by an exit signal (processes)Reported as an uncaught exit, 1; reason normal: 0
Runtime startup or infrastructure failure (ABI mismatch, registration, memory before entry)Message on stderr, 70
Host memory exhausted (heap, off-heap binary or stack growth refused; no memory cap by default, memory exhaustion)clau: runtime failure: entry call failed: out_of_memory, 70

Invalid halt/1 arguments raise badarg in the caller. When the entry finishes, the program exits: other processes are stopped without running further, as with OTP's halt/1 after escript returns. A halt in any process ends the program with its status, and a runtime failure in any process ends it with 70; an exception in a spawned process ends only that process (processes).

halt/0,1, error/1,2,3, exit/1 and throw/1 are callable with or without the erlang: prefix; a local definition or -compile({no_auto_import, ...}) keeps the unqualified name local, as in OTP. halt/2 is not available. halt(N) keeps the low 31 bits of any non-negative integer, as OTP does. A slogan is a proper list of at most 1,023 Unicode code points. A halt unwinds the entry through the checked error channel like an error, so it stops the program only after generated cleanup.

Output streams

Startup object

Compiling with an explicit entry (--entry or manifest entry) adds a startup module after the batch's modules. With --emit it is published as clausev1_start.{obj,o,ll,bc} next to the module artifacts (the name cannot collide with a module artifact). It contains a constant abi::v1::StartupDescriptor (startup.hpp): ABI revision, term width, every module descriptor in source order, the entry module/function spellings and an escript flag. Its int main(int, char **) calls the runtime's CLAUSE_main_v1, which:

  1. Checks the startup and every module descriptor for ABI revision and width before anything is registered; a mismatch exits 70.
  2. Starts the runtime and registers all modules; any failure stops before the entry and discards the runtime (exit 70), so no Erlang code runs against a partial batch.
  3. Creates the entry process, builds argv and queues the call of M:F/1 as the main process, then runs it and every process it spawns on the cooperative executor (processes) until it ends.
  4. Maps the outcome to the exit status above, printing reports after flushing stdout, then releases every process and shuts the runtime down on every path (except halt(abort)).

clau -o links these objects itself (linking). Manual linking (the native harness recipe without a harness source):

& $tool --emit obj --entry app --artifact-dir build/app app.erl helper.erl
clang-cl /MT build/app/*.obj build/debug/lib/clause_runtime.lib /Fe:app.exe

Any Clang-compatible link of the objects with Clause::generated_program works the same way (see tests/compiler/linking/startup.cmake).

Linking

clau [-O0|-O2|-Os] -o PATH a.erl b.erl ... (or --project FILE [--target T] -o PATH for one selected target) compiles the batch in memory, adds the startup object for the entry and links an executable:

clau -O2 -o build/demo examples/compile/answer.erl examples/compile/client.erl
./build/demo          # build/demo.exe on Windows

-Os additionally places every generated and runtime function and data object in its own section and links with --gc-sections (ELF), -dead_strip (Mach-O) or /OPT:REF /OPT:ICF (MSVC), so code no entry path reaches is removed.

Failure (exit 1)Diagnostic
No Clangcannot find clang++ or clang on PATH; install LLVM/Clang or pass --linker / linker not found: X
No runtimeruntime library not found: P; build the clause_runtime target or pass --runtime-library
Not an archiveruntime library is not a static library: P: ...
Wrong targetruntime library P contains x86_64 coff objects, but the executable targets T; ...
Link errorlinking O failed: <clang> exited with status N: followed by the linker output (first 64 KiB)
Bad destinationoutput directory does not exist: D, artifact destination is not a regular file: O, artifact destination aliases an input: O

Escripts

A source file whose first line starts with #! is compiled as an escript, in any mode and with any file name (positional inputs or project .erl files). Rules follow OTP 29 escript for source scripts:

OTP comparison

Goldens for program fixtures run the entry under OTP with the same rules (oracle); the same oracle generates the executable golden cases that the end-to-end runner links and runs under every policy. Differences from escript for ordinary modules: uncaught exceptions exit 1 instead of 127, and main/1 must be exported. Escript sources keep OTP's rules (see above).