The Motoko build system relies on Nix to manage
dependencies, drive the build and run the test suite. You should install nix by
running, as a normal user with sudo permissions,
sh <(curl -L https://nixos.org/nix/install) --daemon
You should also enable a nix cache to get all dependencies pre-built.
The cachix command also requires sudo permissions.
nix-env -iA cachix -f https://cachix.org/api/v1/install
cachix use ic-hs-test
Technically, this is optional, but without this you will build lots of build dependencies manually, which can take several hours.
If you want just to use moc, you can install the moc binary into your nix
environment by running
$ nix-env -i -f . -A moc
in a check-out of the motoko repository.
To enter a shell with the necessary dependencies available, use
$ nix-shell
(The first shell start may take several minutes, afterwards being much faster.)
Within this shell you can run
makeinsrc/to build all binaries,make mocinsrc/to build just themocbinary,make DUNE_OPTS=--watch mocto keep rebuilding as source files are changingmakeinrts/to build the Motoko runtimemakeintest/to run the test suite.
This invokes dune under the hood, which will, as a side effect, also create
.merlin files for integration with Merlin, the Ocaml Language Server
A good way to check that everything is fine, i.e. if this will pass CI, is to run
$ nix-build --no-out-link
For more details on our CI and CI setup, see CI.md.
We make frequent releases, at least weekly. The steps to make a release (say, version 0.14.1) are:
-
Make sure that the top section of
Changelog.mdhas a title like## 0.14.1 (2025-02-10)with today’s date.
-
Make sure the markdown doc for base is up-to-date: For now, in a nix-shell:
make -C src make -C doc base git diff
If not, create and merge a separate PR to update the doc (adding any new files) and goto step 0.
-
Define a shell variable
export MOC_MINOR=1 -
Look at
git log --first-parent 0.14.$(expr $MOC_MINOR - 1)..HEADand check that everything relevant is mentioned in the changelog section, and possibly clean it up a bit, curating the information for the target audience. -
git commit -am "chore: Releasing 0.14."$MOC_MINOR -
Create a PR from this commit, and label it
automerge-squash. E.g. withgit push origin HEAD:$USER/0.14.$MOC_MINOR. Mergify will merge it intomasterwithout additional approval, but it will take some time as the title (version number) enters into thenixdependency tracking. -
git switch master; git pull --rebase. The release commit should be yourHEAD -
git tag 0.14.$MOC_MINOR -m "Motoko 0.14."$MOC_MINOR -
git push origin 0.14.$MOC_MINOR
Pushing the tag should cause GitHub Actions to create a “Release” on the GitHub project. This will fail if the changelog is not in order (in this case, fix and force-push the tag). It will also fail if the nix cache did not yet contain the build artifacts for this revision. In this case, restart the GitHub Action on GitHub’s UI.
After releasing the compiler you can update motoko-base's master
branch to the next-moc branch.
- Wait ca. 5min after releasing to give the CI/CD pipeline time to upload the release artifacts
- Change into
motoko-base git switch next-moc; git pullgit switch -c $USER/update-moc-0.14.$MOC_MINOR- Revise and update the
CHANGELOG.md, by adding a top entry for the release - Update the
moc_versionenv variable in.github/workflows/{ci, package-set}.ymlandmops.tomlto the new released version:perl -pi -e "s/moc_version: \"0\.14\.\\d+\"/moc_version: \"0.14.$MOC_MINOR\"/g; s/moc = \"0\.14\.\\d+\"/moc = \"0.14.$MOC_MINOR\"/g; s/version = \"0\.14\.\\d+\"/version = \"0.14.$MOC_MINOR\"/g" .github/workflows/ci.yml .github/workflows/package-set.yml mops.toml git add .github/ CHANGELOG.md mops.toml && git commit -m "Motoko 0.14."$MOC_MINOR- You can
git pushnow
Make a PR off of that branch and merge it using a normal merge (not
squash merge) once CI passes. It will eventually be imported into this
repo by a scheduled niv-updater-action.
Finally tag the base release (so the documentation interpreter can do the right thing):
git switch master && git pullgit tag moc-0.14.$MOC_MINORgit push origin moc-0.14.$MOC_MINOR
If you want to update the portal documentation, typically to keep in sync with a dfx release, follow the instructions in https://github.com/dfinity/portal/blob/master/MAINTENANCE.md.
To build with coverage enabled, compile the binaries in src/ with
make DUNE_OPTS="--instrument-with bisect_ppx"`
and then use bisect-ppx-report html to produce a report.
The full report can be built with
nix-build -A tests.coverage
and the report for latest master can be viewed at
https://dfinity.github.io/motoko/coverage/.
(This section is currently defunct, and needs to be update to work with the dune build system.)
- Build with profiling within nix-shell (TODO: How to do with dune)
make -C src clean make BUILD=p.native -C src moc - Run
mocas normal, e.g.this should dump amoc -g -c foo.mo -o foo.wasmgmon.outfile in the current directory. - Create the report, e.g. using
(Note that you have to run this in the directory with
gprof --graph src/mocgmon.out, but pass it the path to the binary.)
Specifically some advanced techniques to obtain performance deltas for the
GC can be found in rts/Benchmarking.md.
When the .cabal file of a Haskell package is changed you need to make sure the
corresponding .nix file (stored in nix/generated/) is kept in sync with it. These files are automatically generated; run
nix-shell nix/generate.nix
to update.
Don't worry if you forget to update the default.nix file, the CI job
check-generated checks if these files are in sync and fail with a diff if
they aren't.