Coming from mocalpha
Which moc flags map to moxzi, and which deliberately differ?
moxzi aims to be a drop-in replacement for moc on the common path: compile a Motoko entry file into a deployable canister module, with the same diagnostics and the same package flag. The constraint is that it is a different compiler implementation of the same language, so the surface it exposes is narrower on purpose — there is no interpreter, no REPL, and no warning-control machinery.
The flags below were checked against moxzi build --help from the CLI's clap definitions (moxzi/src/main.rs) and against moc --help from moc 1.14.1, the version the compiler is ported to — the string a moxzi-built canister carries in its motoko:compiler metadata is 1.14.1, and it earns that claim by measurement: zero unported upstream language tests, a 384-of-384 module sweep over the top 40 mops packages, and a byte-identical self-compile.
The command itself#
moc -c --idl -o main.wasm --package base .mops/base@0.16.0/src src/Main.mo
moxzi build src/Main.mo -o main.wasm --package base .mops/base@0.16.0/src
The differences visible in that one line: the entry file is a positional argument to a build subcommand rather than a trailing operand, -c is implied, and --idl is implied (moxzi always writes the .did unless told not to).
Direct equivalents#
| moc | moxzi | Notes |
|---|---|---|
-c | moxzi build | compiling is what build means |
-o <file> | -o, --out <WASM> | defaults to the entry name with .wasm |
--package <name> <path> | --package <NAME> <PATH> | identical semantics, repeatable |
--idl | on by default | --no-idl turns it off |
-no-link | --no-link | note moc's single dash |
--stable-regions | --stable-regions | |
--max-stable-pages <n> | --max-stable-pages <N> | 0 means the canister default (65536) |
--stabilization-instruction-limit <n> | --stabilization-instruction-limit <N> | 0 means the canister default |
-measure-rts-stack | --measure-rts-stack | note moc's single dash |
--trap-on-call-error | --trap-on-call-error | |
--print-deps | moxzi deps | different output: moxzi prints the whole closure with VFS paths, not one file's direct imports |
--enhanced-migration <dir> | --enhanced-migration <DIR> | the migration-chain system; see Migrations |
--stable-baseline <file.most> | --stable-baseline <MOST> | the deployed signature the chain is checked against. One deliberate improvement: moxzi carries upstream's post-1.14.1 fix (#6318), so the check resumes at the migration the baseline records as already applied instead of replaying the whole chain — 1.14.1 itself wrongly errors after a field-dropping migration |
--stable-compatible <pre> <post> | moxzi stable-compatible <pre> <post> | a subcommand rather than a flag; same M0169/M0170/M0216 verdicts |
--public-metadata <name>, --omit-metadata <name> | same names | one difference of DEFAULT: raw moc is all-private, moxzi's default is dfx's (candid:service and candid:args public). Passing --public-metadata replaces that default, as it does in moc |
--default-persistent-actors | --default-persistent-actors | verified equivalent: both rewrite a bare actor to persistent actor |
Deliberate differences#
| Area | moc | moxzi | Why |
|---|---|---|---|
Non-persistent actors | rejects with M0220 by default; --legacy-actors opts out | rejects with M0220; --legacy-actors is retired | the two agree on the default. moxzi drops the legacy escape hatch entirely: silently compiling an actor that does not declare its state survives is the mistake worth failing on. --default-persistent-actors rewrites bare actors on both |
| Candid emission | --idl, off by default | always on, --no-idl to suppress | a canister without its interface file is not deliverable |
| Metadata visibility | raw default is all-private | candid:service and candid:args are public | follows dfx, not raw moc, so a deployed canister's interface is readable without controller rights |
| Backend | --legacy-persistence still selectable | enhanced orthogonal persistence only | --no-eop is retired: the classical backend's IR is never closed and traps in ConstFold on any program |
| Warnings | printed, and controllable (-A/-W/-E) | printed, not controllable | a successful build prints the warnings the compiler emits (float precision M0266, migration-chain M0254, and others), but there is no per-code leveling machinery. Coverage is also narrower than moc's — see Language support status |
| GC selection | --incremental-gc, --copying-gc, … | none | incremental GC with EOP is the only configuration |
--force-gc | forces GC in the generated code, for testing | forces the compiler's own collector to run at each message boundary | same name, different subject: moxzi's is a host-side knob and does not change the artifact |
Verified behavioural difference: --debug#
moc's --debug is the default and keeps debug { … } expressions; --release strips them. In moxzi, --debug currently makes no observable difference:
moxzi build dbg.mo -o dbg-rel.wasm
moxzi build dbg.mo -o dbg-dbg.wasm --debug
cmp dbg-rel.wasm dbg-dbg.wasm # identical
For the same source, moc's --release output contains no trace of the debug string while its --debug output does; both moxzi outputs contain it. In other words moxzi behaves like moc's default, and there is no --release equivalent that strips debug expressions. If you rely on --release stripping, do not assume it here.
Flags with no moxzi equivalent#
| moc | Status in moxzi |
|---|---|
-r, -i, -iR, -t (interpret, REPL, trace) | absent — moxzi only compiles |
--check (type-check only) | absent |
--stable-types (separate .most emission) | absent as a flag — the signature is always embedded in the module's motoko:stable-types section, which is what --stable-compatible/upgrades read |
-A, -W, -E, -Werror, --hide-warnings, --warn-help | absent — warnings print but there is no leveling machinery |
--error-format, --error-detail, --error-recovery, --ai-errors, --explain | absent — diagnostics come out in moc's plain file:line.col-line.col: kind [Mxxxx], message form only |
--actor-idl, --actor-alias, --actor-id-alias, --actor-env-alias | absent |
-g, --map (debug info, source maps) | absent |
--profile*, --sanity-checks, -dp, -dt, -dl | absent |
--args <file>, --args0 <file> | absent |
-fshared-code / -fno-shared-code | absent |
--experimental-*, --rts-stack-pages | absent |
moxzi flags moc has no analogue for#
| Flag | What it is for |
|---|---|
--stack-budget <N> | how often the compiler's own scheduler yields — a cost knob, not an output knob |
--root <DIR> | what /src maps to in the virtual filesystem |
--compiler / --linker, MOXZI_COMPILER / MOXZI_LINKER | which compiler and linker wasm to run |
--remote <URL> --canister <ID> | run the compile on a compiler canister instead of locally |
--progress <N>, --status-secs <S>, --max-steps <N> | observe and bound a long build |
--timings | per-phase timing plus the compiler's memory numbers |
The environment variables moxzi reads are MOXZI_COMPILER, MOXZI_LINKER, MOXZI_MOPS, MOXZI_IDENTITY, MOXZI_WASM_STACK, MOXZI_NATIVE_STACK, MOXZI_MEM_RESERVE, MOXZI_FUEL and MOXZI_PARSE_WINDOW.
Unverified / to confirm#
These could not be checked against a running binary in this repo and should be treated as open questions rather than documented behaviour:
- Whether moxzi's
--stable-regions,--max-stable-pages,--stabilization-instruction-limit,--measure-rts-stackand--trap-on-call-errorproduce byte-identical results to moc's. The flags exist on both sides and moxzi documents them as passthroughs; no differential test for them was found here. -v. Both compilers have it and they are not the same thing: moc's is general verbose output, moxzi's forwards the compiler canister's debug output and prints the resolved closure. Treat the outputs as unrelated.--debug's intended semantics. The option is wired through to the compiler's release-mode environment, so the observed no-op may be an unimplemented stripping pass rather than a design choice.
Next#
- Reading diagnostics — the codes are moc's; this is how to read them and report a mismatch.
- Compiling and linking — how
moxzi buildmaps ontomoc -cplus a separate link step. - Projects and packages —
--packageand the mops path in detail.