MoonBit's Build System Tutorial

Moon is the build system for the MoonBit language, currently based on the n2 project. Moon supports parallel and incremental builds. Additionally, moon also supports managing and building third-party packages on mooncakes.io

Prerequisites

Before you begin with this tutorial, make sure you have installed the following:

  1. MoonBit CLI Tools: Download it from the https://www.moonbitlang.com/download/. This command line tool is needed for creating and managing MoonBit projects.

    Use moon help to view the usage instructions.

    $ moon help
    ...
    
  2. MoonBit Language plugin in Visual Studio Code: You can install it from the VS Code marketplace. This plugin provides a rich development environment for MoonBit, including functionalities like syntax highlighting, code completion, and more.

Once you have these prerequisites fulfilled, let's start by creating a new MoonBit module.

Creating a New Module

To create a new module, enter the moon new command in the terminal, and you will see the module creation wizard. By using all the default values, you can create a new module named username/hello in the my-project directory.

$ moon new
Enter the path to create the project (. for current directory): my-project
Select the create mode: exec
Enter your username: username
Enter your project name: hello
Enter your license: Apache-2.0
Created my-project

If you want use all default values, you can use moon new my-project to create a new module named username/hello in the my-project directory.

Understanding the Module Directory Structure

After creating the new module, your directory structure should resemble the following:

my-project
├── LICENSE
├── README.md
├── moon.mod.json
└── src
    ├── lib
    │   ├── hello.mbt
    │   ├── hello_test.mbt
    │   └── moon.pkg.json
    └── main
        ├── main.mbt
        └── moon.pkg.json

Here's a brief explanation of the directory structure:

  • moon.mod.json is used to identify a directory as a MoonBit module. It contains the module's metadata, such as the module name, version, etc. source specifies the source directory of the module. The default value is src.

    {
      "name": "username/hello",
      "version": "0.1.0",
      "readme": "README.md",
      "repository": "",
      "license": "Apache-2.0",
      "keywords": [],
      "description": "",
      "source": "src"
    }
    
  • lib and main directories: These are the packages within the module. Each package can contain multiple .mbt files, which are the source code files for the MoonBit language. However, regardless of how many .mbt files a package has, they all share a common moon.pkg.json file. lib/*_test.mbt are separate test files in the lib package, these files are for blackbox test, so private members of the lib package cannot be accessed directly.

  • moon.pkg.json is package descriptor. It defines the properties of the package, such as whether it is the main package and the packages it imports.

    • main/moon.pkg.json:

      {
        "is_main": true,
        "import": [
          "username/hello/lib"
        ]
      }
      

    Here, "is_main: true" declares that the package needs to be linked by the build system into a wasm file.

    • lib/moon.pkg.json:

      {}
      

    This file is empty. Its purpose is simply to inform the build system that this folder is a package.

Working with Packages

Our username/hello module contains two packages: username/hello/lib and username/hello/main.

The username/hello/lib package contains hello.mbt and hello_test.mbt files:

hello.mbt

pub fn hello() -> String {
    "Hello, world!"
}

hello_test.mbt

test "hello" {
  if @lib.hello() != "Hello, world!" {
    fail!("@lib.hello() != \"Hello, world!\"")
  }
}

The username/hello/main package contains a main.mbt file:

fn main {
  println(@lib.hello())
}

To execute the program, specify the file system's path to the username/hello/main package in the moon run command:

$ moon run ./src/main
Hello, world!

You can also omit ./

$ moon run src/main
Hello, world!

You can test using the moon test command:

$ moon test
Total tests: 1, passed: 1, failed: 0.

Package Importing

In the MoonBit's build system, a module's name is used to reference its internal packages. To import the username/hello/lib package in src/main/main.mbt, you need to specify it in src/main/moon.pkg.json:

{
  "is_main": true,
  "import": [
    "username/hello/lib"
  ]
}

Here, username/hello/lib specifies importing the username/hello/lib package from the username/hello module, so you can use @lib.hello() in main/main.mbt.

Note that the package name imported in src/main/moon.pkg.json is username/hello/lib, and @lib is used to refer to this package in src/main/main.mbt. The import here actually generates a default alias for the package name username/hello/lib. In the following sections, you will learn how to customize the alias for a package.

Creating and Using a New Package

First, create a new directory named fib under lib:

mkdir src/lib/fib

Now, you can create new files under src/lib/fib:

a.mbt:

pub fn fib(n : Int) -> Int {
  match n {
    0 => 0
    1 => 1
    _ => fib(n - 1) + fib(n - 2)
  }
}

b.mbt:

pub fn fib2(num : Int) -> Int {
  fn aux(n, acc1, acc2) {
    match n {
      0 => acc1
      1 => acc2
      _ => aux(n - 1, acc2, acc1 + acc2)
    }
  }

  aux(num, 0, 1)
}

moon.pkg.json:

{}

After creating these files, your directory structure should look like this:

my-project
├── LICENSE
├── README.md
├── moon.mod.json
└── src
    ├── lib
    │   ├── fib
    │   │   ├── a.mbt
    │   │   ├── b.mbt
    │   │   └── moon.pkg.json
    │   ├── hello.mbt
    │   ├── hello_test.mbt
    │   └── moon.pkg.json
    └── main
        ├── main.mbt
        └── moon.pkg.json

In the src/main/moon.pkg.json file, import the username/hello/lib/fib package and customize its alias to my_awesome_fibonacci:

{
  "is_main": true,
  "import": [
    "username/hello/lib",
    {
      "path": "username/hello/lib/fib",
      "alias": "my_awesome_fibonacci"
    }
  ]
}

This line imports the fib package, which is part of the lib package in the hello module. After doing this, you can use the fib package in main/main.mbt. Replace the file content of main/main.mbt to:

fn main {
  let a = @my_awesome_fibonacci.fib(10)
  let b = @my_awesome_fibonacci.fib2(11)
  println("fib(10) = \{a}, fib(11) = \{b}")

  println(@lib.hello())
}

To execute your program, specify the path to the main package:

$ moon run ./src/main
fib(10) = 55, fib(11) = 89
Hello, world!

Adding Tests

Let's add some tests to verify our fib implementation. Add the following content in src/lib/fib/a.mbt:

src/lib/fib/a.mbt

test {
  assert_eq!(fib(1), 1)
  assert_eq!(fib(2), 1)
  assert_eq!(fib(3), 2)
  assert_eq!(fib(4), 3)
  assert_eq!(fib(5), 5)
}

This code tests the first five terms of the Fibonacci sequence. test { ... } defines an inline test block. The code inside an inline test block is executed in test mode.

Inline test blocks are discarded in non-test compilation modes (moon build and moon run), so they won't cause the generated code size to bloat.

Stand-alone test files for blackbox tests

Besides inline tests, MoonBit also supports stand-alone test files. Source files ending in _test.mbt are considered test files for blackbox tests. For example, inside the src/lib/fib directory, create a file named fib_test.mbt and paste the following code:

src/lib/fib/fib_test.mbt

test {
  assert_eq!(@fib.fib(1), 1)
  assert_eq!(@fib.fib2(2), 1)
  assert_eq!(@fib.fib(3), 2)
  assert_eq!(@fib.fib2(4), 3)
  assert_eq!(@fib.fib(5), 5)
}

Notice that the test code uses @fib to refer to the username/hello/lib/fib package. The build system automatically creates a new package for blackbox tests by using the files that end with _test.mbt. This new package will import the current package automatically, allowing you to use @lib in the test code.

Finally, use the moon test command, which scans the entire project, identifies, and runs all inline tests as well as files ending with _test.mbt. If everything is normal, you will see:

$ moon test
Total tests: 3, passed: 3, failed: 0.
$ moon test -v
test username/hello/lib/hello_test.mbt::hello ok
test username/hello/lib/fib/a.mbt::0 ok
test username/hello/lib/fib/fib_test.mbt::0 ok
Total tests: 3, passed: 3, failed: 0.

Command-Line Help for moon

This document contains the help content for the moon command-line program.

Command Overview:

moon

Usage: moon <COMMAND>

Subcommands:
  • new — Create a new MoonBit module
  • build — Build the current package
  • check — Check the current package, but don't build object files
  • run — Run a main package
  • test — Test the current package
  • clean — Remove the target directory
  • fmt — Format source code
  • doc — Generate documentation
  • info — Generate public interface (.mbti) files for all packages in the module
  • add — Add a dependency
  • remove — Remove a dependency
  • install — Install dependencies
  • tree — Display the dependency tree
  • login — Log in to your account
  • register — Register an account at mooncakes.io
  • publish — Publish the current module
  • package — Package the current module
  • update — Update the package registry index
  • coverage — Code coverage utilities
  • generate-build-matrix — Generate build matrix for benchmarking (legacy feature)
  • upgrade — Upgrade toolchains
  • shell-completion — Generate shell completion for bash/elvish/fish/pwsh/zsh to stdout
  • version — Print version information and exit

moon new

Create a new MoonBit module

Usage: moon new [OPTIONS] [PACKAGE_NAME]

Arguments:
  • <PACKAGE_NAME> — The name of the package
Options:
  • --lib — Create a library package instead of an executable

  • --path <PATH> — Output path of the package

  • --user <USER> — The user name of the package

  • --name <NAME> — The name part of the package

  • --license <LICENSE> — The license of the package

    Default value: Apache-2.0

  • --no-license — Do not set a license for the package

moon build

Build the current package

Usage: moon build [OPTIONS]

Options:
  • --std — Enable the standard library (default)

  • --nostd — Disable the standard library

  • -g, --debug — Emit debug information

  • --release — Compile in release mode

  • --target <TARGET> — Select output target

    Possible values: wasm, wasm-gc, js, native, all

  • --serial — Handle the selected targets sequentially

  • --enable-coverage — Enable coverage instrumentation

  • --sort-input — Sort input files

  • --output-wat — Output WAT instead of WASM

  • -d, --deny-warn — Treat all warnings as errors

  • --no-render — Don't render diagnostics from moonc (don't pass '-error-format json' to moonc)

  • --frozen — Do not sync dependencies, assuming local dependencies are up-to-date

  • -w, --watch — Monitor the file system and automatically build artifacts

moon check

Check the current package, but don't build object files

Usage: moon check [OPTIONS]

Options:
  • --std — Enable the standard library (default)

  • --nostd — Disable the standard library

  • -g, --debug — Emit debug information

  • --release — Compile in release mode

  • --target <TARGET> — Select output target

    Possible values: wasm, wasm-gc, js, native, all

  • --serial — Handle the selected targets sequentially

  • --enable-coverage — Enable coverage instrumentation

  • --sort-input — Sort input files

  • --output-wat — Output WAT instead of WASM

  • -d, --deny-warn — Treat all warnings as errors

  • --no-render — Don't render diagnostics from moonc (don't pass '-error-format json' to moonc)

  • --output-json — Output in json format

  • --frozen — Do not sync dependencies, assuming local dependencies are up-to-date

  • -w, --watch — Monitor the file system and automatically check files

moon run

Run a main package

Usage: moon run [OPTIONS] <PACKAGE_OR_MBT_FILE> [ARGS]...

Arguments:
  • <PACKAGE_OR_MBT_FILE> — The package or .mbt file to run
  • <ARGS> — The arguments provided to the program to be run
Options:
  • --std — Enable the standard library (default)

  • --nostd — Disable the standard library

  • -g, --debug — Emit debug information

  • --release — Compile in release mode

  • --target <TARGET> — Select output target

    Possible values: wasm, wasm-gc, js, native, all

  • --serial — Handle the selected targets sequentially

  • --enable-coverage — Enable coverage instrumentation

  • --sort-input — Sort input files

  • --output-wat — Output WAT instead of WASM

  • -d, --deny-warn — Treat all warnings as errors

  • --no-render — Don't render diagnostics from moonc (don't pass '-error-format json' to moonc)

  • --frozen — Do not sync dependencies, assuming local dependencies are up-to-date

  • --build-only — Only build, do not run the code

moon test

Test the current package

Usage: moon test [OPTIONS]

Options:
  • --std — Enable the standard library (default)

  • --nostd — Disable the standard library

  • -g, --debug — Emit debug information

  • --release — Compile in release mode

  • --target <TARGET> — Select output target

    Possible values: wasm, wasm-gc, js, native, all

  • --serial — Handle the selected targets sequentially

  • --enable-coverage — Enable coverage instrumentation

  • --sort-input — Sort input files

  • --output-wat — Output WAT instead of WASM

  • -d, --deny-warn — Treat all warnings as errors

  • --no-render — Don't render diagnostics from moonc (don't pass '-error-format json' to moonc)

  • -p, --package <PACKAGE> — Run test in the specified package

  • -f, --file <FILE> — Run test in the specified file. Only valid when --package is also specified

  • -i, --index <INDEX> — Run only the index-th test in the file. Only valid when --file is also specified

  • -u, --update — Update the test snapshot

  • -l, --limit <LIMIT> — Limit of expect test update passes to run, in order to avoid infinite loops

    Default value: 256

  • --frozen — Do not sync dependencies, assuming local dependencies are up-to-date

  • --build-only — Only build, do not run the tests

  • --no-parallelize — Run the tests in a target backend sequentially

  • --test-failure-json — Print failure message in JSON format

moon clean

Remove the target directory

Usage: moon clean

moon fmt

Format source code

Usage: moon fmt [OPTIONS]

Options:
  • --check — Check only and don't change the source code
  • --sort-input — Sort input files

moon doc

Generate documentation

Usage: moon doc [OPTIONS]

Options:
  • --serve — Start a web server to serve the documentation

  • -b, --bind <BIND> — The address of the server

    Default value: 127.0.0.1

  • -p, --port <PORT> — The port of the server

    Default value: 3000

  • --frozen — Do not sync dependencies, assuming local dependencies are up-to-date

moon info

Generate public interface (.mbti) files for all packages in the module

Usage: moon info [OPTIONS]

Options:
  • --frozen — Do not sync dependencies, assuming local dependencies are up-to-date

moon add

Add a dependency

Usage: moon add <PACKAGE_PATH>

Arguments:
  • <PACKAGE_PATH> — The package path to add

moon remove

Remove a dependency

Usage: moon remove <PACKAGE_PATH>

Arguments:
  • <PACKAGE_PATH> — The package path to remove

moon install

Install dependencies

Usage: moon install

moon tree

Display the dependency tree

Usage: moon tree

moon login

Log in to your account

Usage: moon login

moon register

Register an account at mooncakes.io

Usage: moon register

moon publish

Publish the current module

Usage: moon publish [OPTIONS]

Options:
  • --frozen — Do not sync dependencies, assuming local dependencies are up-to-date

moon package

Package the current module

Usage: moon package [OPTIONS]

Options:
  • --frozen — Do not sync dependencies, assuming local dependencies are up-to-date
  • --list

moon update

Update the package registry index

Usage: moon update

moon coverage

Code coverage utilities

Usage: moon coverage <COMMAND>

Subcommands:
  • report — Generate code coverage report
  • clean — Clean up coverage artifacts

moon coverage report

Generate code coverage report

Usage: moon coverage report [args]... [COMMAND]

Arguments:
  • <args> — Arguments to pass to the coverage utility
Options:
  • -h, --help — Show help for the coverage utility

moon coverage clean

Clean up coverage artifacts

Usage: moon coverage clean

moon generate-build-matrix

Generate build matrix for benchmarking (legacy feature)

Usage: moon generate-build-matrix [OPTIONS] --output-dir <OUT_DIR>

Options:
  • -n <NUMBER> — Set all of drow, dcol, mrow, mcol to the same value
  • --drow <DIR_ROWS> — Number of directory rows
  • --dcol <DIR_COLS> — Number of directory columns
  • --mrow <MOD_ROWS> — Number of module rows
  • --mcol <MOD_COLS> — Number of module columns
  • -o, --output-dir <OUT_DIR> — The output directory

moon upgrade

Upgrade toolchains

Usage: moon upgrade [OPTIONS]

Options:
  • -f, --force — Force upgrade

moon shell-completion

Generate shell completion for bash/elvish/fish/pwsh/zsh to stdout

Usage: moon shell-completion [OPTIONS]

Discussion: Enable tab completion for Bash, Elvish, Fish, Zsh, or PowerShell The script is output on stdout, allowing one to re-direct the output to the file of their choosing. Where you place the file will depend on which shell, and which operating system you are using. Your particular configuration may also determine where these scripts need to be placed.

The completion scripts won't update itself, so you may need to
periodically run this command to get the latest completions.
Or you may put `eval "$(moon shell-completion --shell <SHELL>)"`
in your shell's rc file to always load newest completions on startup.
Although it's considered not as efficient as having the completions
script installed.

Here are some common set ups for the three supported shells under
Unix and similar operating systems (such as GNU/Linux).

Bash:

Completion files are commonly stored in `/etc/bash_completion.d/` for
system-wide commands, but can be stored in
`~/.local/share/bash-completion/completions` for user-specific commands.
Run the command:

    $ mkdir -p ~/.local/share/bash-completion/completions
    $ moon shell-completion --shell bash >> ~/.local/share/bash-completion/completions/moon

This installs the completion script. You may have to log out and
log back in to your shell session for the changes to take effect.

Bash (macOS/Homebrew):

Homebrew stores bash completion files within the Homebrew directory.
With the `bash-completion` brew formula installed, run the command:

    $ mkdir -p $(brew --prefix)/etc/bash_completion.d
    $ moon shell-completion --shell bash > $(brew --prefix)/etc/bash_completion.d/moon.bash-completion

Fish:

Fish completion files are commonly stored in
`$HOME/.config/fish/completions`. Run the command:

    $ mkdir -p ~/.config/fish/completions
    $ moon shell-completion --shell fish > ~/.config/fish/completions/moon.fish

This installs the completion script. You may have to log out and
log back in to your shell session for the changes to take effect.

Elvish:

Elvish completions are commonly stored in a single `completers` module.
A typical module search path is `~/.config/elvish/lib`, and
running the command:

    $ moon shell-completion --shell elvish >> ~/.config/elvish/lib/completers.elv

will install the completions script. Note that use `>>` (append) 
instead of `>` (overwrite) to prevent overwriting the existing completions 
for other commands. Then prepend your rc.elv with:

    `use completers`

to load the `completers` module and enable completions.

Zsh:

ZSH completions are commonly stored in any directory listed in
your `$fpath` variable. To use these completions, you must either
add the generated script to one of those directories, or add your
own to this list.

Adding a custom directory is often the safest bet if you are
unsure of which directory to use. First create the directory; for
this example we'll create a hidden directory inside our `$HOME`
directory:

    $ mkdir ~/.zfunc

Then add the following lines to your `.zshrc` just before
`compinit`:

    fpath+=~/.zfunc

Now you can install the completions script using the following
command:

    $ moon shell-completion --shell zsh > ~/.zfunc/_moon

You must then open a new zsh session, or simply run

    $ . ~/.zshrc

for the new completions to take effect.

Custom locations:

Alternatively, you could save these files to the place of your
choosing, such as a custom directory inside your $HOME. Doing so
will require you to add the proper directives, such as `source`ing
inside your login script. Consult your shells documentation for
how to add such directives.

PowerShell:

The powershell completion scripts require PowerShell v5.0+ (which
comes with Windows 10, but can be downloaded separately for windows 7
or 8.1).

First, check if a profile has already been set

    PS C:\> Test-Path $profile

If the above command returns `False` run the following

    PS C:\> New-Item -path $profile -type file -force

Now open the file provided by `$profile` (if you used the
`New-Item` command it will be
`${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1`

Next, we either save the completions file into our profile, or
into a separate file and source it inside our profile. To save the
completions into our profile simply use

    PS C:\> moon shell-completion --shell powershell >>
    ${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

This discussion is taken from `rustup completions` command with some changes.
Options:
  • --shell <SHELL> — The shell to generate completion for

    Default value: <your shell>

    Possible values: bash, elvish, fish, powershell, zsh

moon version

Print version information and exit

Usage: moon version [OPTIONS]

Options:
  • --all — Print all version information
  • --json — Print version information in JSON format
  • --no-path — Do not print the path

This document was generated automatically by clap-markdown.

Module Configuration

moon uses the moon.mod.json file to identify and describe a module.

Module Name

The name field is used to specify the name of the module, and it is required.

{
  "name": "example",
  ...
}

The module name can contain letters, numbers, _, -, and /.

For modules published to mooncakes.io, the module name must begin with the username. For example:

{
  "name": "moonbitlang/core",
  ...
}

Version

The version field is used to specify the version of the module.

This field is optional. For modules published to mooncakes.io, the version number must follow the Semantic Versioning 2.0.0 specification.

{
  "name": "example",
  "version": "0.1.0",
  ...
}

Deps

The deps field is used to specify the dependencies of the module.

It is automatically managed by commands like moon add and moon remove.

{
  "name": "username/hello",
  "deps": {
    "moonbitlang/x": "0.4.6"
  }
}

README

The readme field is used to specify the path to the module's README file.

Repository

The repository field is used to specify the URL of the module's repository.

License

The license field is used to specify the license of the module. The license type must comply with the SPDX License List.

{
  "license": "MIT"
}

Keywords

The keywords field is used to specify the keywords for the module.

{
  "keywords": ["example", "test"]
}

Description

The description field is used to specify the description of the module.

{
  "description": "This is a description of the module."
}

Source directory

The source field is used to specify the source directory of the module.

It must be a subdirectory of the directory where the moon.mod.json file is located and must be a relative path.

When creating a module using the moon new command, a src directory will be automatically generated, and the default value of the source field will be src.

{
  "source": "src"
}

When the source field does not exist, or its value is null or an empty string "", it is equivalent to setting "source": ".". This means that the source directory is the same as the directory where the moon.mod.json file is located.

{
  "source": null
}
{
  "source": ""
}
{
  "source": "."
}

Warning List

This is used to disable specific preset compiler warning numbers.

For example, in the following configuration, -2 disables the warning number 2 (Unused variable).

{
  "warn-list": "-2",
}

You can use moonc build-package -warn-help to see the list of preset compiler warning numbers.

$ moonc -v                      
v0.1.20240914+b541585d3

$ moonc build-package -warn-help
Available warnings: 
  1 Unused function.
  2 Unused variable.
  3 Unused type declaration.
  4 Redundant case in a pattern matching (unused match case).
  5 Unused function argument.
  6 Unused constructor.
  7 Unused module declaration.
  8 Unused struct field.
 10 Unused generic type variable.
 11 Partial pattern matching.
 12 Unreachable code.
 13 Unresolved type variable.
 14 Lowercase type name.
 15 Unused mutability.
 16 Parser inconsistency.
 18 Useless loop expression.
 19 Top-level declaration is not left aligned.
 20 Invalid pragma
 21 Some arguments of constructor are omitted in pattern.
 22 Ambiguous block.
 23 Useless try expression.
 24 Useless error type.
 26 Useless catch all.
  A all warnings

Alert List

Disable user preset alerts.

{
  "alert-list": "-alert_1-alert_2"
}

Package Configuration

moon uses the moon.pkg.json file to identify and describe a package.

Name

The package name is not configurable; it is determined by the directory name of the package.

is-main

The is-main field is used to specify whether a package needs to be linked into an executable file.

The output of the linking process depends on the backend. When this field is set to true:

  • For the wasm and wasm-gc backends, a standalone WebAssembly module will be generated.
  • For the js backend, a standalone JavaScript file will be generated.

import

The import field is used to specify other packages that a package depends on.

test-import

The test-import field is used to specify other packages that the black-box test package of this package depends on.

wbtest-import

The wbtest-import field is used to specify other packages that the white-box test package of this package depends on.

Link Options

By default, moon only links packages where is-main is set to true. If you need to link other packages, you can specify this with the link option.

The link option is used to specify link options, and its value can be either a boolean or an object.

  • When the link value is true, it indicates that the package should be linked. The output will vary depending on the backend specified during the build.

    {
      "link": true
    }
    
  • When the link value is an object, it indicates that the package should be linked, and you can specify link options. For detailed configuration, please refer to the subpage for the corresponding backend.

wasm Backend Link Options

Configurable Options

  • The exports option is used to specify the function names exported by the wasm backend.

    For example, in the following configuration, the hello function from the current package is exported as the hello function in the wasm module, and the foo function is exported as the bar function in the wasm module. In the wasm host, the hello and bar functions can be called to invoke the hello and foo functions from the current package.

    {
      "link": {
        "wasm": {
          "exports": [
            "hello",
            "foo:bar"
          ]
        }
      }
    }
    
  • The heap-start-address option is used to specify the starting address of the linear memory that can be used when compiling to the wasm backend.

    For example, the following configuration sets the starting address of the linear memory to 1024.

    {
      "link": {
        "wasm": {
          "heap-start-address": 1024
        }
      }
    }
    
  • The import-memory option is used to specify the linear memory imported by the wasm module.

    For example, the following configuration specifies that the linear memory imported by the wasm module is the memory variable from the env module.

    {
      "link": {
        "wasm": {
          "import-memory": {
            "module": "env",
            "name": "memory"
          }
        }
      }
    }
    
  • The export-memory-name option is used to specify the name of the linear memory exported by the wasm module.

    {
      "link": {
        "wasm": {
          "export-memory-name": "memory"
        }
      }
    }
    

wasm-gc Backend Link Options

The link options for the wasm-gc backend are similar to those for the wasm backend, except there is no heap-start-address option.

JS Backend Link Options

Configurable Options

  • The exports option is used to specify the function names to export in the JavaScript module.

    For example, in the following configuration, the hello function from the current package is exported as the hello function in the JavaScript module. In the JavaScript host, the hello function can be called to invoke the hello function from the current package.

    {
      "link": {
        "js": {
          "exports": [
            "hello"
          ]
        }
      }
    }
    
  • The format option is used to specify the output format of the JavaScript module.

    The currently supported formats are:

    • esm
    • cjs
    • iife

    For example, the following configuration sets the output format of the current package to ES Module.

    {
      "link": {
        "js": {
          "format": "esm"
        }
      }
    }
    

Warning List

This is used to disable specific preset compiler warning numbers.

For example, in the following configuration, -2 disables the warning number 2 (Unused variable).

{
  "warn-list": "-2",
}

You can use moonc build-package -warn-help to see the list of preset compiler warning numbers.

$ moonc -v                      
v0.1.20240914+b541585d3

$ moonc build-package -warn-help
Available warnings: 
  1 Unused function.
  2 Unused variable.
  3 Unused type declaration.
  4 Redundant case in a pattern matching (unused match case).
  5 Unused function argument.
  6 Unused constructor.
  7 Unused module declaration.
  8 Unused struct field.
 10 Unused generic type variable.
 11 Partial pattern matching.
 12 Unreachable code.
 13 Unresolved type variable.
 14 Lowercase type name.
 15 Unused mutability.
 16 Parser inconsistency.
 18 Useless loop expression.
 19 Top-level declaration is not left aligned.
 20 Invalid pragma
 21 Some arguments of constructor are omitted in pattern.
 22 Ambiguous block.
 23 Useless try expression.
 24 Useless error type.
 26 Useless catch all.
  A all warnings

Alert List

Disable user preset alerts.

{
  "alert-list": "-alert_1-alert_2"
}

Conditional Compilation

The smallest unit of conditional compilation is a file.

In a conditional compilation expression, three logical operators are supported: and, or, and not, where the or operator can be omitted.

For example, ["or", "wasm", "wasm-gc"] can be simplified to ["wasm", "wasm-gc"].

Conditions in the expression can be categorized into backends and optimization levels:

  • Backend conditions: "wasm", "wasm-gc", and "js"
  • Optimization level conditions: "debug" and "release"

Conditional expressions support nesting.

If a file is not listed in "targets", it will be compiled under all conditions by default.

Example:

{
    "targets": {
        "only_js.mbt": ["js"],
        "only_wasm.mbt": ["wasm"],
        "only_wasm_gc.mbt": ["wasm-gc"],
        "all_wasm.mbt": ["wasm", "wasm-gc"],
        "not_js.mbt": ["not", "js"],
        "only_debug.mbt": ["debug"],
        "js_and_release.mbt": ["and", ["js"], ["release"]],
        "js_only_test.mbt": ["js"],
        "js_or_wasm.mbt": ["js", "wasm"],
        "wasm_release_or_js_debug.mbt": ["or", ["and", "wasm", "release"], ["and", "js", "debug"]]
    }
}

Pre-build

The "pre-build" field is used to specify pre-build commands, which will be executed before build commands such as moon check|build|test.

"pre-build" is an array, where each element is an object containing input, output, and command fields. The input and output fields can be strings or arrays of strings, while the command field is a string. In the command, you can use any shell commands, as well as the $input and $output variables, which represent the input and output files, respectively. If these fields are arrays, they will be joined with spaces by default.

Currently, there is a built-in special command :embed, which converts files into MoonBit source code. The --text parameter is used to embed text files, and --binary is used for binary files. --text is the default and can be omitted. The --name parameter is used to specify the generated variable name, with resource being the default. The command is executed in the directory where the moon.pkg.json file is located.

{
  "pre-build": [
    {
      "input": "a.txt",
      "output": "a.mbt",
      "command": ":embed -i $input -o $output"
    }
  ]
}

If the content of a.txt in the current package directory is:

hello,
world

After running moon build, the following a.mbt file will be generated in the directory where the moon.pkg.json is located:

let resource : String =
  #|hello,
  #|world
  #|

Config JSON Schema

moon.mod.json

moon.pkg.json