Axle v0.13.3

Command-line reference

The axle binary is the whole toolchain. This page is the surface: one section per subcommand, then the flags that cut across them.

axle new     <NAME> [--lib | --workspace]
axle build   [SOURCE] [-O LEVEL] [-o PATH] [--emit KIND]
axle run     [SOURCE] [-O LEVEL] [-- ARGS]
axle check   [SOURCE] [--target TRIPLE]
axle ports   [SOURCE] [--target TRIPLE]
axle fmt     [FILES...] [--check]
axle bench   <SOURCE> [-O LEVEL]
axle profile [SOURCE] [-O LEVEL] [-- ARGS]

SOURCE is a .axle file or a directory holding an axle.toml. Omit it and build, run, check and ports use the current directory — Projects and dependencies covers what a project is.

new

axle new hello               # hello/axle.toml + hello/src/main.axle
axle new mathx --lib         # hello/src/lib.axle instead — a library crate
axle new studio --workspace  # a root manifest, app/ (bin) and core/ (lib)

--lib and --workspace are mutually exclusive. --workspace writes a root axle.toml listing the members, an app binary and a core library that app depends on — a working cross-crate build out of the box. Build it from app/, which is where the binary crate lives.

build

Compiles and links. A project build writes target/<name> (<name>.exe on Windows), where <name> is [package] name; a single-file build writes the artefact beside you, named after the file’s stem. -o overrides either, and --emit swaps the extension — target/<name>.ll, <stem>.o, and so on.

axle build                    # the project in the current directory
axle build hello              # … or at a path
axle build hello.axle         # a single file
axle build -O 3 -o hello      # optimised, named output
axle build --emit llvm        # stop after the LLVM pass pipeline, print the IR
axle build --incremental      # skip codegen + link when nothing moved
FlagEffect
-o, --output PATHwhere the artefact goes
-O LEVELoptimisation level (03, below)
--optimizelegacy bool shortcut for -O 2; an explicit -O beside it still wins
--emit KINDstop at an intermediate stage (below)
--incrementalskip codegen and the link on a cache hit
--link-lib LIBlink a native library
--lib-path DIRadd a directory to the native-library search path
--target TRIPLEcross-compile
--target-cpu CPUtune for a named CPU (znver3, skylake, …)
--target-features F+avx2,+fma
--pieforce a position-independent executable
--codegen-units Nhow many object files to build from, concurrently; the default follows the program’s size and the machine’s cores, and N is a ceiling (lowered to 8, and to the number of function bodies there are to split)
--alloc-statsprint the program’s allocation tally to its stderr
--timingsper-phase timings on stderr
--features NAMESturn features on in the root crate
-v, --verboseper-phase detail

--codegen-units 1 is the single-module reference. A non-binary --emit uses one unit regardless, because an intermediate artefact is a whole-program artefact by definition.

--alloc-stats instruments the program rather than the compiler: each allocation costs a call and two atomics, so measure time without it.

run

axle run                      # build the project in the current directory, then run it
axle run hello.axle -- a b    # run one file, passing a and b to the program

A project directory builds a native binary and executes it. A single .axle file runs through the LLVM JIT instead, which means lli must be on your PATH and must be the LLVM your compiler was built against — the IR handed to it is that version’s. When in doubt, axle build hello.axle && ./hello needs no JIT.

run takes -O, --link-lib, --lib-path, --pie, --features and the -- ARGS tail. It never uses the build cache: a binary that is about to be executed is always built fresh.

check

axle check                    # analyse the project, generate nothing
axle check --target x86_64-unknown-linux-gnu

Lexes, parses and runs sema — no codegen, no link. --target selects which port is active, so this is how the half of your program written for another platform is found broken without that platform’s toolchain. It takes --target and --features.

ports

axle ports                    # which ports the project declares, and what each owes

Prints one row per module path that crosses a port boundary, one column per port, and the file to write for each hole. It is the same reading the build refuses on, so a listing that shows a port complete is a tree the build agrees about. See code that differs by operating system.

fmt

axle fmt src/                 # format in place
axle fmt --check src/         # list what would change, exit non-zero, write nothing

Layout comes from the [fmt] table of axle.toml when there is one — see the manifest reference — and from the formatter’s defaults otherwise.

bench

axle bench tests/bench/x.axle
axle bench x.axle --compare cpp,rust --format json --output bench.json

Runs the program repeatedly and reports timings.

FlagDefaultEffect
-O LEVELsweeps 03a single level instead of the sweep
--runs N10timed iterations
--warmup N3untimed iterations first; their average calibrates --min-seconds
--min-seconds Ssize the run count from the warmup timings so the measured total stays near this budget, --runs becoming the floor
--compare cpp,rust,…build and run other-language baselines from <stem>.cpp / <stem>.rs next to the input
--format text\|jsontextreport format
--output PATHwrite the report to a file (--format json; stdout otherwise)

bench is the one subcommand whose absent -O means something other than a default: it sweeps 0, 1, 2 and 3 in a single invocation.

profile

axle profile game.axle --top 20
axle profile game.axle -- --snap

Runs a program and reports where its time and memory went, as two flamegraphs — <name>.cpu.svg and <name>.ram.svg — plus the heaviest functions of each with their file and line.

The default instruments the build: the compiler emits entry and exit hooks, so every frame is named, including the ones the optimiser inlined. That is also why the result moves with -O: a function that no longer costs a call has its share attributed to where the work ended up. --sample asks the OS instead (perf on Linux, an ETW session on Windows) — no instrumentation overhead, but only frames that still have a symbol.

FlagDefaultEffect
-O LEVEL3optimisation level to build at — a profile of unoptimised code tells you about the compiler, not the program
-o, --output PATHthe program’s own namebase path for the flamegraphs: -o report.svg writes report.cpu.svg and report.ram.svg
--timeout SECS30how long the program may run before it is asked to stop
--top N15how many functions the hot list carries
--frequency HZ999sampling frequency, with --sample only
--sampleask the OS to sample instead of instrumenting the build
--features NAMESfeatures to enable
-- ARGSpassed to the program after --

A program with a main loop is ended by --timeout or by Ctrl-C, and the report is written either way — that is how a game is profiled, not a failure of the run.

-O LEVEL

LevelWhat runs
0nothing — neither the HIR transforms nor the LLVM pipeline
1every HIR transform, no LLVM pipeline
2… plus LLVM’s own pipeline
3… plus LLVM’s more aggressive passes
axle build -O 0                # is an optimisation responsible for this?

0 is the level to build at when the question is whether an optimisation changed behaviour: it turns off both halves, so a difference between -O 0 and -O 3 is a difference the optimiser made. The default is 1 for build and run, and 3 for profile.

--emit KIND

Stops the build at an intermediate stage and writes that instead of a binary.

KindWhat you get
astthe parsed syntax tree
hirAxle’s typed IR, after the sema transforms
llvmtextual LLVM IR after the LLVM pass pipeline
llvm-rawthe IR exactly as codegen emitted it, before any LLVM pass
bitcodeLLVM bitcode
asmtarget assembly
objecta relocatable object file
headera C header declaring the program’s extern "C" exports
binarythe default — a linked executable

llvm-raw against llvm is the pair to reach for when deciding whether an oddity is Axle’s or LLVM’s.

Exit codes

0 on success. 1 on any user error, with the diagnostics rendered against the source; an internal failure prints internal compiler error: … rather than a stack trace.

See also

clireferencebuildtooling