One binary does everything: compiling, linking, serving editors, cleaning up. Every flag has a short and a long spelling (-c and --compile are the same flag), values are case-insensitive where they name a choice, and flags that take a list separate its items with commas.

A representative build:

mica --compile --link --optimize release,full_optimizations \
     --platform linux,amd64,utf-8 \
     --source Hello.mica --build build

Modes

FlagEffect
-c | --compilecompile source files to assembly
-l | --linklink the compiled objects into the output program or library — requires --compile
-r | --runcompile one source file and immediately execute it, like a script; --run - reads the source from standard input
-lsp | --language-serverrun as a language server over standard input and output; the former spelling --lsp stays accepted as an alias; the VS Code extension is the packaged client, and any LSP-capable editor can be pointed at the command
-in | --inspectprint the manifest a linked program, archive or shared object carries, as one line of JSON, without starting it: among its members its own version and the libraries it was built against with theirs
-fm | --formatformat Mica source files in place to the house layout and print each rewritten path; a directory formats every .mica file beneath it, and - reads standard input and writes standard output; combines only with --check
-ck | --checkwith --format: write nothing, print every path that is not formatted, and exit with 1 when one is not
-p | --purgeempty the build directory first — requires --build, and may run without --compile
-v | --versionprint version information and exit
-h | --helpprint the flag summary and exit

At least one of --compile or --purge must be present; everything else qualifies them. --language-server stands alone: it claims standard output for the protocol and prints no banner. --inspect stands alone too: it reads one program file, prints its manifest and no banner, and refuses any other flag and any further word. --format is a mode of its own: it combines only with --check, and the paths it formats follow the flags, mica --format --check src; it changes white space only, so every token, every comment and every line break stays.

The run mode

mica --run tool.mica compiles the file into a temporary directory at the debug tier — checks maximal, latency milliseconds — executes it, forwards the program’s exit code as its own, and cleans up. Nothing is cached and nothing lands beside your file.

mica --run tool.mica alpha beta      # everything after the file belongs to the program
mica tool.mica alpha beta            # the bare spelling means the same
mica --optimize O2 tool.mica         # the run mode's flags may precede the file
mica --run - << 'EOF'                # a here-document is a program
program Hi; imp WriteLn : std; begin WriteLn("hi"); end.
EOF

The rules, each of which is the scripting convention:

  • Arguments. Everything after the source file belongs to the program (readable through the process unit’s ArgCount and Arg); an optional -- between file and arguments is accepted. Compiler flags come before --run, or before the file in the bare spelling.
  • Exit code. The program’s exit code is the process exit code — callers branch on it.
  • Streams. The program owns standard output. The compiler is silent on success, keeps warnings, and speaks on standard error only.
  • Shebang. A leading #! line belongs to the operating system, and the compiler’s source preparation removes it on every road — the build, the editor, and the run mode all read the file identically, with line numbers preserved. The bare spelling makes #!/usr/bin/env mica a working first line — chmod +x and the file runs — and it also accepts an existing file with no extension, so a script installed under a command name stays a command.
  • Projects. The nearest mica.project up the directory tree contributes its encoding and contracts — a script beside your project imports your libraries with no flags — and when the file is one of the project’s own sources, the whole source set compiles with it.
  • Flags. The run mode owns compilation, linking, and the build directory; it combines with --optimize, --stdlib, --memory-class, --tasking, --processes, --runtime-flags, --stack-size, and --remarks, and refuses everything else with one line. Everything after the file is the program’s; a runtime-flag group at the head of it reaches the program’s runtime. It targets the host architecture; cross builds go through --compile.

Inputs and outputs

FlagValueEffect
-s | --sourcefile.mica,file.mica,…the source files of the build, comma-separated
-pj | --projectpath to mica.project or its directoryread the compilation’s facts — sources, encoding, consumed contracts, version — from a project file; every explicit flag overrides its entry
-b | --builddirectorywhere every generated file lands; the linked binary is named after the first source file’s program or library
-sl | --stdlibpath to an archivename a standard library explicitly; when omitted, the compiler resolves mica-stdlib-<arch>.a next to its own executable first, then under /usr/lib/
-xc | --external-contractone or more paths to mica.external or its directory, comma-separatedconsume external libraries’ interop contracts from explicit locations instead of the source-directory lookup; several paths let one program import several separately built libraries, each through its own emitted contract

The project file. A mica.project beside the sources states what belongs to the source tree rather than to any one invocation:

{
    "sources": ["Consumer.mica"],
    "encoding": "utf-8",
    "contracts": ["../build/Utilities", "../build/LibB"],
    "version": "1.4.0",
    "requires": {"Utilities": "2.0"}
}

--project reads it, explicit flags override its entries one by one, and a --platform that names no encoding — linux,arm64 — completes its encoding from the file. The version has no flag: it is the program’s or library’s own, written as Semantic Versioning writes one. A library is linked only under a version, so a library’s build names its project file, and a build that reads a project file reads the version it states. requires states which versions of each library the build accepts, "2.0" every version from 2.0.0 up to 3.0.0, and a library outside its requirement refuses the build by name. A library’s build carries its version into the contract it emits, and every program built against the library names it in its build, Using library 'Utilities' 2.0.0, and in its manifest. The language server discovers the project on its own by walking up from the open file, so the editor analyzes each source under the same sources, encoding, and contracts the build uses, with no configuration. The file is ignored by compilers older than 6.12.5.

Naming a standard library explicitly is also a statement of trust: a mica-stdlib-<encoding>.external contract beside the named archive is used as that library’s import surface. An auto-resolved standard library uses only the surface embedded in the compiler binary — no file on disk changes what an installed compiler believes. One contradiction is refused rather than honoured: an archive that does not match the declared --memory-class — a hosted archive for a fixed-arena program, or the reverse — is refused with the consequence spelled out, because honouring it would link a fixed-arena program with no arena at all.

What is built

FlagValuesEffect
-om | --output-modifiernone · archive · objectthe library output kind: archive produces a static library (.a), object a shared object (.so), none (default) an executable program — requires --link
-ext | --externalstatic · sharedhow external C libraries are linked; the default is static, which needs no rpath and ships as one artifact — requires --link
-ec | --emit-contractwhen linking a library, emit its interop contract (mica.external) beside the archive so other builds can import it — requires --link
-np | --no-piedisable position-independent-executable output — requires --link
-st | --staticlink the program wholly statically, so the binary carries its own libc and runs on a machine that has none — program outputs only, requires --link
-sp | --stripstrip the symbol table from the linked program or shared object, the shipping shape; without it a build of any tier keeps every function’s name, so a profiler, a backtrace and a debugger read the program’s own procedures — requires --link, not for archives

Target selection

FlagValueEffect
-pf | --platformos,arch,encodingthe target platform, e.g. linux,arm64,utf-8 — requires --compile
-asm | --assemblyintel · attthe emitted assembly syntax; the default is intel — requires --compile

The accepted values: operating system linux; architecture amd64 or arm64; string encoding utf-32 or utf-8. All four Linux combinations are valid. When no platform is named, the build targets the machine it runs on: Linux with the host’s own architecture, utf-32 encoded. The string encoding is fixed per binary — utf-32 is the general-purpose default, utf-8 the interop-oriented choice; format specifiers follow it (%ls under utf-32, %s under utf-8), and the compiler checks them at compile time.

Optimization

FlagValueEffect
-o | --optimizecomma-separated setselect the optimization profile and passes — requires --compile; when the flag is omitted entirely, the build is a plain debug build

The three spellings almost everyone uses:

LevelExpands toMeaning
O0debugevery variable observable, every line breakable, every GPU kernel finished before the program goes on — the profile a debugger wants
O1release,standard_optimizationsthe release profile with the standard pass set
O2release,full_optimizationsthe release profile with the full optimizing set

O3 is refused by name, with an explanation: the transformations that would distinguish it from O2 — vectorization, loop unrolling — do not exist yet, and an alias that silently meant O2 would be a promise the compiler does not keep.

The set may also name its members directly: the profiles debug and release (mutually exclusive; naming neither in a non-empty set defaults to release), checked for the checked runtime diagnostics, a flag beside either profile — O2,checked ships every guard on the optimizing lowering, debug,checked keeps every variable observable at the trap, and checked alone means release,checked as any set naming no profile means release — profiling for the line table, the subprogram entries and the inlining records at any tier — O2,profiling is the build a profiler attributes to source lines and a debugger shows an inlined procedure in as its own frame, with no variable locations and the code of the plain build to the byte — the group names standard_optimizations and full_optimizations, and the individual pass names constant_folding, assembly_peephole, stub_allocator, graph_allocator, function_inlining, loop_optimization, fp_contract, heap_contract — plus the two code-generation modes il_static_single_assignment and il_direct_lowering, which are mutually exclusive and exist for differential testing of the middle end. Individually named passes are an instrument for working on the compiler; programs are shipped with O0, O1, or O2.

What each level does

LevelCode pathRegister allocatorDebug informationRuntime floor
debug (O0)direct loweringnone: every value lives on the stackfullrecords the allocation site of every cell
releasestatic single assignmentlinear scannoneplain
release,standard_optimizations (O1)static single assignment, constant folding, assembly peepholelinear scannoneplain
release,full_optimizations (O2)static single assignment, constant folding, assembly peephole, inlining, loop optimizationsgraph colouringnoneplain

release alone takes the static-single-assignment road with no pass beside it: it is the setting that exercises the middle end in isolation, and a program ships with O1 or O2. A set that names no level is a release build, so full_optimizations alone is the same build as O2. profiling adds the line table, the subprogram entries and the inlining records to any release level. The standard library is the same prebuilt archive at every level.

A program that computes on an NVIDIA GPU may add fp_tensor_float32: O2,fp_tensor_float32 lets every float32 matrix product the program runs, the reverse products of its tape included, read its inputs in TF32 on the card’s tensor cores — ten bits of mantissa beside float32’s exponent range, sums kept in float32 — the setting nanoGPT trains with. An attention keeps float32’s precision either way, as PyTorch’s float32 attention does under that setting. A product’s digits then differ from float32’s from about the fourth significant one on, which is why the flag belongs to no level and is named only for a program; a library’s build refuses it, because the program that links the library decides for all its products.

Every release build, O1 and O2 among them, lets the GPU work through its kernels and products while the program goes on, and a copy back to the processor waits for their results; O0 waits for each one, so a kernel that fails is named where it failed.

Deployment classes

FlagValuesEffect
-mc | --memory-classhosted-heap · fixed-arena · fixed-arena=<bytes>the memory deployment class; selects the matching standard-library archive. hosted (default) uses the operating system’s heap; fixed-arena places the whole program heap in one arena of the given size, for deployments that must not allocate after start
-tk | --taskingsingle · multicore · multicore,<carriers> · multicore,<carriers>,fixedthe tasking flavor. multicore runs tasks on a carrier pool and links the multicore standard-library archive; the count, from 1 to 1024, is the pool’s size unless the program is started with a carriers runtime flag, and with no count the pool sizes itself at start to the processors the program may use (the least of the processors online, its affinity mask and its cgroup’s CPU quota, see how many carriers a pool starts). ,fixed pins the count: the program refuses the carriers flag
-ps | --processesa counthow many worker processes run the tasks the program places on processes at once, from 1 to 1024; a task placed beyond the count waits until a worker ends. The program’s processes runtime flag replaces the count at start, and without one the count is the processors the program may use (see how many worker processes run at once). A program’s decision: refused for a library. Combines with --run
-rf | --runtime-flagsopen · sealed · sealed,rtp · nonewhat the built program accepts in the runtime-flag group at the head of its arguments: open every flag the build did not pin (the debug default), sealed only info and check (the release default), sealed,rtp those two and the runtime protocol’s rtp= flags, none no group at all

Diagnostics and analysis

FlagValueEffect
-ss | --stack-sizebytesgive the program this many bytes of stack: every frame the stack holds compiles quietly and a frame it cannot hold is refused — in both directions, so a small embedded request tightens the limit — while the default stack warns at frames above 1 MiB; a linked program raises its own stack limit before main runs (default: the platform’s 8 MiB). Combines with --run
-vb | --verbosereport the per-source optimization statistics beside the build: what each pass folded, inlined, forwarded, elided and declined — requires --compile
-rm | --remarksreport the compiler’s remarks: hints from its own knowledge about your code — be careful here, or do it another way. A remark never gates a build and is spoken only when asked for; combines with every road, --run included — requires --compile
-exp | --exportwrite every intermediate representation to the build directory — requires --compile; the compiler, exported walks all fourteen stages
-pr | --profileprint a per-phase and per-pass compile-time table and write profile.json to the build directory — requires --compile
-q | --qualitysemantic_analysis · intermediate_code · no_quality_gatesextra verification runs inside the compiler, for root-cause analysis of internal compiler errors — requires --compile
-cp | --cpu-profilefilewrite a CPU profile of the compiler itself to the file
-mp | --mem-profilefilewrite a memory profile of the compiler itself to the file

The combination rules

The compiler refuses inconsistent combinations rather than guessing: --link requires --compile; --no-pie, --emit-contract, --output-modifier and --external require --link; --optimize, --platform, --assembly, --export, --profile and --quality require --compile; --purge requires --build. Each refusal names the rule.