moxzi
Docs / On-chain builds / How on-chain builds run

How on-chain builds runalpha

Why an on-chain build takes minutes, what the compiler canister does at each stage, and what it keeps afterwards.

An Internet Computer message can run at most 40 billion instructions. A compile needs far more than that in total, so the compiler canister runs it as a job: a state machine that does a slice of work per message and keeps its progress in canister memory between messages.

Time is set by message count#

Each step uses a small part of the per-message limit. What takes time is that each message waits for its turn in a block, about one second on mainnet. So a build's duration is roughly its number of steps times the block time:

BuildSourceStepsTime
hello.mo1 fileabout 60about a minute
A 660-file application15 MBabout 4,000about an hour

More cycles don't make a build faster. moxzi build --timings prints an estimate for your project from a local build.

Stages#

moxzi build --remote calls the canister's step(job) method in a loop. Each call returns #more until the job is #done or #err. The stages are:

StageWork
ParseRead and parse your files and their imports
Type checkCheck each declaration, one per step
LowerTranslate to the compiler's intermediate form and run its passes
Code generationGenerate wasm, in many steps
EmitWrite the module, its names and its metadata
LinkAdd the Motoko runtime

Between steps the job is only data in the canister. If moxzi build stops, nothing is lost; continue with --resume-job ID.

The canister can also drive a job itself with timers (startSelfDriven), so a build continues with no client connected.

Repeated builds#

The canister can cache whole builds. A build with the same source files, the same options and the same compiler returns the stored result without compiling. The operator turns the cache on; until then, every build compiles.

What's kept#

When a job finishes, the canister keeps the module, its Candid interface, the diagnostics and the build record, and frees everything else. Stored modules are limited to 100 MiB in total; the oldest are dropped first. Build records are kept longer, in a ring of the most recent few hundred builds, and survive upgrades of the compiler canister.

A build in progress doesn't survive an upgrade of the compiler canister. Payments do.

Watching a build#

These methods on the compiler canister are open to the job's owner and to operators:

MethodReturns
status(job)The current stage and the work done so far
jobDiags(job)Errors and warnings
jobStats()Totals for the canister. Open to anyone
buildRecord(job)The build record. Open to anyone
On this pageTime is set by message countStagesRepeated buildsWhat's keptWatching a build