Building with moxzialpha
Compile Motoko to a deployable wasm module, control warnings and output, and see where build time goes.
moxzi build compiles a Motoko entry file and writes a wasm module you can deploy, plus its Candid interface. This page covers the options you'll use day to day. Every flag is listed in the CLI reference.
Build a module#
actor {
public query func greet(name : Text) : async Text {
"Hello, " # name # "!"
};
};
mkdir -p out
moxzi build hello.mo -o out/hello.wasm
ls out
hello.mo -> out/hello.wasm + out/hello.did (243956 bytes, 1 file(s), 50 steps, 0.51s)
compiled by ~/.local/lib/moxzi/compiler.wasm (sha256 fbfb83d4ee2a40739c33c20dff3a3fc98c56b92eb5c76eed624c8efe298bc463), moxzi 0.1.0-alpha.9
hello.did
hello.wasm
| Part of the output | Meaning |
|---|---|
out/hello.wasm + out/hello.did | The files written. Without -o, they go next to the entry file |
247440 bytes | Size of the deployable module |
1 file(s) | Source files in the build, including package files |
58 steps | Compiler work units. Larger projects take more |
compiled by … (sha256 …) | The compiler that produced this module. The same compiler and the same sources always produce the same bytes |
The output directory must already exist.
The module is ready to deploy. Install it on the Internet Computer with dfx or icp, host it with moxzid, or load it with moxzi-web.
Every actor is persistent: its variables keep their values across upgrades. Writing persistent actor still compiles, with warning M0217 that the keyword is redundant.
Warnings#
Warnings print before the summary line and don't stop the build:
actor {
var orders : Nat = 0;
public func order(quantity : Nat) : async Nat {
let unused = quantity * 2;
orders += quantity;
orders
};
};
moxzi build shop.mo
/src/shop.mo:5.9-5.15: warning [M0194], unused identifier: `unused`
shop.mo -> shop.wasm + shop.did (244475 bytes, 1 file(s), 50 steps, 0.51s)
compiled by ~/.local/lib/moxzi/compiler.wasm (sha256 fbfb83d4ee2a40739c33c20dff3a3fc98c56b92eb5c76eed624c8efe298bc463), moxzi 0.1.0-alpha.9
Turn a warning into an error with -E, or silence it with -A:
moxzi build shop.mo -E M0194 || echo "exit code $?"
Error: compilation failed:
/src/shop.mo:5.9-5.15: type error [M0194], unused identifier: `unused`
exit code 1
moxzi build shop.mo -A M0194
shop.mo -> shop.wasm + shop.did (244475 bytes, 1 file(s), 50 steps, 0.56s)
compiled by ~/.local/lib/moxzi/compiler.wasm (sha256 fbfb83d4ee2a40739c33c20dff3a3fc98c56b92eb5c76eed624c8efe298bc463), moxzi 0.1.0-alpha.9
-W CODE enables a warning that's off by default. All three options repeat, and they're applied in command-line order. They work the same way as in moc.
Common options#
| Option | Effect |
|---|---|
-o, --out FILE | Where to write the wasm. The .did goes beside it |
--no-idl | Don't write the .did file |
--gzip | Also write FILE.gz. The IC accepts gzipped modules, and you need one to pass a large module as a call argument |
--debug | Keep debug { … } blocks. moxzi builds release by default; moc builds debug by default |
--package NAME PATH | Make mo:NAME/… imports resolve to PATH. Repeatable. See Projects and packages |
--root DIR | The project directory, which the compiler sees as /src. Defaults to the nearest directory with a mops.toml or dfx.json, else the entry file's directory |
--stable-types | Also write the stable signature as a .most file, used to check upgrades |
--compact-rts | Link a runtime that keeps the heap smaller. For moxzid and moxzi-web only; not for the IC |
--gzip with --no-idl:
moxzi build hello.mo --gzip --no-idl
ls hello.wasm*
hello.mo -> hello.wasm + hello.wasm.gz (243956 bytes, 1 file(s), 50 steps, 0.60s)
compiled by ~/.local/lib/moxzi/compiler.wasm (sha256 fbfb83d4ee2a40739c33c20dff3a3fc98c56b92eb5c76eed624c8efe298bc463), moxzi 0.1.0-alpha.9
hello.wasm
hello.wasm.gz
Large projects#
On a project with hundreds of files, raise the compiler's scheduling budget with --stack-budget. It changes how often the compiler pauses between work units, not what it produces. On a large project it can cut a build from hours to minutes:
moxzi build hello.mo --stack-budget 20000
To watch a long build, add --progress 500 to print a line every 500 steps, or --status-secs 10 to also print the current compiler phase, at most every ten seconds.
Build time#
--timings breaks down where the time went:
moxzi build hello.mo --timings
hello.mo -> hello.wasm + hello.did (243956 bytes, 1 file(s), 50 steps, 0.53s)
compiled by ~/.local/lib/moxzi/compiler.wasm (sha256 fbfb83d4ee2a40739c33c20dff3a3fc98c56b92eb5c76eed624c8efe298bc463), moxzi 0.1.0-alpha.9
rts: allocated 0.07 GB, reclaimed 0.06 GB, peak live 5 MB, heap 11 MB, committed 201 MB
on-chain estimate: ~68 rounds (~0.02 h at 1s/round, ~0.01 h at 0.4s) | dirty-budget floor 1 rounds
timings: module 0.037s (cached), sources 0.001s, instantiate 0.002s, compile 0.140s, link 0.329s (55322 -> 243956 bytes)
| Phase | What it is |
|---|---|
module | Loading the compiler. (cached) means it was already prepared for your CPU; the first build after an install or upgrade says (JIT) and takes about a second longer |
sources | Reading source files |
compile | Compiling |
link | Adding the Motoko runtime to the compiled code |
For a small program, linking takes longer than compiling. Link time is roughly fixed; compile time grows with your program.
moxzi cache path shows where prepared compilers are cached, and moxzi cache clear empties the cache.
Compiling and linking separately#
moxzi build compiles your code and then links it with the Motoko runtime. --no-link stops after compiling, and moxzi link does the second half:
moxzi build hello.mo --no-link -o unlinked.wasm
moxzi link unlinked.wasm -o hello.wasm
hello.mo -> unlinked.wasm + unlinked.did (55322 bytes, 1 file(s), 50 steps, 0.19s)
compiled by ~/.local/lib/moxzi/compiler.wasm (sha256 fbfb83d4ee2a40739c33c20dff3a3fc98c56b92eb5c76eed624c8efe298bc463), moxzi 0.1.0-alpha.9
unlinked.wasm -> hello.wasm (55322 -> 243956 bytes, 0.33s)
An unlinked module can't be deployed and fails wasm validation. The on-chain builder produces unlinked modules; moxzi build --remote links them for you, so you only need moxzi link when you fetch one yourself.
Listing the files in a build#
moxzi deps shows every file the build would read and the path the compiler sees it at:
moxzi deps hello.mo
root : .
pkgs : none (no mops.toml)
reqs : none
entry : /src/hello.mo
files : 1 (97 bytes)
97 /src/hello.mo
<- ./hello.mo
The compiler sees your project's files under /src and packages under /pkg/NAME. Paths in error messages use these names, which keeps builds identical across machines.
Limitations#
| Limitation | What to do |
|---|---|
One entry file per moxzi build | Run it once per canister |
| No type-check-only mode | Run a build and discard the output |
No interpreter or REPL (moc -r, moc -i) | Use moxzid to run the actor |
Next steps#
- Projects and packages: multiple files and
mopsdependencies. - Fixing build errors: reading diagnostics and common fixes.
- Coming from moc: flag-by-flag equivalents.