machdocs
Home GitHub

CLI

The mach binary is the compiler driver. It dispatches on the first argument to a small set of commands - build, run, test, and more - that compile, execute, and manage a project rooted at a mach.toml.

Invocation

mach <command> [options]

The compiler dispatches on argv[1]. With no command, or an unknown one, it prints usage and exits non-zero. The project commands - build, run, test, and doc - take the project root as a required positional and walk up from it until a mach.toml is found. A bare invocation with no path is a user error.

Flags are matched exactly: --flag value (the value follows in the next argument) or a bare --flag toggle.

Restriction

The combined --flag=value form and bundled short flags are not recognized. Each flag and its value are separate arguments.

Commands

CommandSummary
buildcompile the project to objects and (for a kind = "bin" artifact) a linked binary
runbuild, then execute the produced binary
testbuild the test binary and run the collected tests
cleanremove the project's build output
depmanage git-backed dependencies (clone, lock, vendor)
initscaffold a new project
docgenerate Markdown reference docs from source doc-comments
infoprint compiler version, build host, and registered target capabilities
helpprint usage; mach help <command> for detail

Global flags

Read by build, run, test, and doc, which share one config parser. Passing a verbosity flag and --quiet together is a parse error.

FlagValueEffect
-v-verbose readout: build phase timing, or per-test lines under mach test
-vv--v plus per-module / per-file (or passing-test) detail
--quiet, -q-suppress non-error output
--target <name>target nameselect a [target.<name>] entry
--profile <name>profile nameselect a [profile.<name>] variant; absent, the first declared
--bin <name>artifact namenarrow the build to one bin-kind artifact
--lib <name>artifact namenarrow to one library artifact (mutually exclusive with --bin)
-o <path>pathoverride the linked-binary path; accepted only when the selection resolves to a single build cell
--all-targets-build every declared target rather than the manifest default
-g-emit debug info for this build, overriding the profile's debug key
--pie-emit a position-independent (ET_DYN) executable
--subsystem <kind>console, guithe environment a windows executable declares; overrides the artifact's subsystem key, inert off windows
--emit-asm-emit per-module .s assembly text beside each object
--emit-ir-emit per-module .ir SSA text beside each object
--verify-ir-run the IR verifier after each optimisation pass
Note

IR and assembly emission is a CLI concern only - there is no profile key for it. There are no --no-emit-* inverses, no --release flag (use -O1 / -O2 or --profile), no --color flag, and no --verbose long form.

Note

mach dep and mach init do not use the shared config parser; they read only their own flags.

build

mach build <path> [options]

Compiles the project rooted at <path> (for example mach build .). With no --bin or --lib, it builds every declared artifact for the default target and profile. Every reachable module is driven through sema, lower, optimise, and codegen to one relocatable object under the manifest's obj template. For a kind = "bin" artifact the objects are linked into the resolved out path; for a static artifact they are archived into an ar archive there, and with --emit obj the objects are the deliverable and nothing is linked.

FlagValueEffect
-O0-force the debug pipeline, overriding the profile
-O1, -O2-select the release pipeline (both select the same one today)
--emit <kind>obj, exeobj stops at the objects; exe (default) links a binary
--jobs <n>countcodegen worker threads (default: host CPUs; 1 serialises)
--explain-print the resolved build plan and exit without building
-L <dir>diradd a search directory for -l-resolved inputs; repeatable
-l <name>namelink a named object, archive, or shared library; repeatable

Plus the global flags. An -O<n> flag overrides the selected profile's opt for this invocation; absent one, the profile decides. A bare .o / .a / .so / .dylib / .dll argument, or any /-bearing path, is linked verbatim.

ext fun declarations are forward references resolved at link time by external precompiled code - a loose .o object, a static .a archive, or a shared .so library. Inputs come from the command line and from the manifest's merged libs overlay; both sets are linked. An input that resolves to no existing file is a hard error, so a typo never silently drops a dependency.

How an input resolves decides static vs dynamic linking. A loose .o or static .a is a static input merged into the executable (an archive contributes every member object). A shared .so is a dynamic dependency: its DT_SONAME is recorded and undefined ext symbols are bound at load time through an emitted PLT. A static definition always wins over a dynamic import of the same name. -l prefers a static candidate, so the .so fallback applies only when none exists (the common case for system libraries like libc). Manifest libs resolve before CLI inputs, giving a deterministic link order.

Note

Dynamic linking is implemented for the ELF (Linux) and PE (Windows) targets. The Mach-O (Darwin) import path is not yet implemented.

run

mach run <path> [options] [-- args...]

Executes the binary mach build already produced for <path> - a post-build convenience, not a rebuild. The build selection flags (--target, --profile, --bin / --lib) resolve which artifact to run; the build-only -O0 / -O1 / -O2 are accepted but have no effect, and --emit is rejected. Arguments after a -- separator are forwarded to the child as its argv; the child's exit code becomes this command's exit code.

Changed

mach run does not build. Run mach build first, or the binary it executes will be the one from your last build.

FlagValueEffect
--runner <cmd>commandexecute the binary as <cmd> <binary> <args...> instead of directly

--runner names a host-side launcher for binaries the host cannot exec directly, for example mach run . --target windows --runner wine. <cmd> is a single command name or path (no shell-style word splitting); a bare name is resolved on PATH. Without the flag the binary is exec'd directly, and a launch failure reports exit 127 when execve rejects the binary, with no auto-detection.

test

mach test <path> [options]

Builds one dispatcher executable covering every test declaration (under the tests template) and runs each test as its own process (<exe> <idx>), reporting a per-module roll-up that expands failures. A crashing test reports its signal and the run continues. Only the current project's own tests run by default. A test build always links executables, even for a library target.

FlagValueEffect
--filter <pattern>patternrun only tests whose name contains <pattern>
--include-deps-also run tests declared in dependency modules
--list-list the collected tests and exit
--format <kind>human, jsonhuman (default), or a json NDJSON event stream for tooling
--jobs <n>countrun up to n test processes at once, and size the build's codegen workers
--runner <cmd>commandlaunch every test as <cmd> <exe> <idx> instead of exec'ing it directly

Plus the build and global flags. --runner has the same semantics as on run. Without it, a test the host cannot launch reports a per-test failure - FAIL(exit 127) when execve rejects the binary, FAIL(spawn) when the spawn itself fails.

clean

mach clean <path>

Removes the project's build output: the output directory trees declared by the manifest's out / obj / ir / asm templates. <path> is a project directory or a manifest file. It is idempotent and takes no options. Exit codes are its own: 0 ok, 1 no project or a bad manifest, 2 an IO failure.

dep

mach dep <action> [args]

Manages the project's dependency tree. A dependency has exactly one source form: a git URL plus a ref, acquired into the dep directory with plain git operations, or a path to another project tree, materialised as a relative symlink so the build resolves it by the same vendor layout.

ActionArgsEffect
pull-realise the manifest: clone missing git deps (transitively), link path deps, re-resolve a changed ref, repair drift, write mach.lock. Idempotent.
update<name> or --allthe only lock-advancer: re-resolve branch refs to current remote tips. Tag/commit refs are a no-op. Never edits the manifest.
add<name> --git <url> [--ref <ref>] or --path <dir>append a [dep.<name>] stanza, then pull.
remove<name> [--purge]drop the entry from mach.toml and mach.lock; --purge also deletes the vendored checkout.
list-print each entry with its source form, ref, locked commit, and state (synced, missing, drifted, path).

mach build never requires git or the network: a project whose dep tree is present builds on a bare machine. Only the network-shaped commands (pull, update, add) use git, discovered on PATH and invoked with an allowlisted environment. Git's absence is a clean error naming the operation that needed it. The same name required from two different sources or refs is a hard error naming both requirers; there is no version resolution.

Lockfile

The manifest is intent; mach.lock is the record of resolving it. After a pull, mach dep writes a TOML file recording each git dep's url, ref, and resolved commit (path deps have no lock entry).

# generated by `mach dep pull`; do not edit by hand.
version = 1

[dep.mach-std]
url = "https://github.com/briar-systems/mach-std"
ref = "branch/dev"
commit = "6b78ae1e8c3c9cc45e4ab4b916fd191d61e76aff"

pull honours the lock except where the manifest ref was edited, where it re-resolves loudly. A checked-out commit that differs from the lock is drift, repaired and reported, never silent. The writer is idempotent: an up-to-date lock is left untouched. Commit mach.lock to pin builds.

init

mach init [dir] [options]

Scaffolds a new project in [dir] (default: the current directory). Writes a complete mach.toml with a [project] block, [target.*] platforms for linux/windows/darwin, one artifact, debug and release profiles, a [dep.mach-std] dependency, a starter source file, and a cloned mach-std. Every collision is checked before any file is written, so a refused init leaves nothing behind.

FlagValueEffect
--name <name>nameproject id (default: the directory base name)
--force-scaffold even when mach.toml, src/main.mach, or src/lib.mach already exists
--lib-library layout: write src/lib.mach and scaffold a kind = "static" artifact instead of a kind = "bin" one

The first non-flag argument is the target directory. A default binary scaffold links and runs from mach build . without further manifest edits.

doc, info, and help

mach doc <path> loads the module graph and generates Markdown reference docs from source doc-comments - one page per module plus an index. Each pub declaration is paired with the run of # comment lines immediately preceding it. --out <dir> sets the output directory (default doc/api); --target <name> selects a target for module discovery. The hand-written language material is never touched.

mach info prints an at-a-glance identity of the binary: its version, the host it was built for, and the registered capability surface. It needs no project. The output is line-oriented and stable for scripts.

mach 
host: linux/x86_64
isa: x86_64 aarch64 riscv64 riscv32 spirv mos6502
os: linux darwin windows freestanding
abi: sysv64 win64 aapcs64 lp64 lp64f lp64d ilp32 ilp32f ilp32d spirv mos6502
object: elf coff macho raw spv

mach info targets prints the concrete (os, isa) tuples this binary can build, one per line. It is derived from the same joint capability declarations composition reads, so it never advertises a tuple that would fail to resolve.

The capability lines are read from the binary's target registries, so they report exactly what this build can target. mach info --version prints the version string alone on one line, for tooling.

mach help [command] prints the top-level usage summary, or - with a known command - that command's detail page. An unknown command prints usage and exits non-zero.

Exit codes

The commands share a stable convention for scripting:

CodeMeaning
0success (for test, all tests passed)
1user error: missing project path, no mach.toml, unknown target, compile errors, an unresolvable link input (for test, any test failed)
2internal error

mach run instead returns the child's exit code on a successful build, falling back to 1 on a build/user error and 2 internally.

See also

  • Manifest - the mach.toml reference for targets, profiles, and libs
  • Dependencies - git and path deps managed by mach dep
  • Testing - the test declaration behind mach test
  • Project layout - the directory shape mach init scaffolds