MoonBit 构建系统教程

moon 是 MoonBit 语言的构建系统,目前基于 n2 项目。moon 支持并行构建和增量构建,此外它还支持管理和构建 mooncakes.io 上的第三方包。

准备工作

在开始之前,请确保安装好以下内容:

  1. MoonBit CLI 工具: 从这里下载。该命令行工具用于创建和管理 MoonBit 项目。

    使用 moon help 命令可查看使用说明。

    $ moon help
    ...
    
  2. Moonbit Language Visual Studio Code 插件: 可以从 VS Code 市场安装。该插件为 MoonBit 提供了丰富的开发环境,包括语法高亮、代码补全、交互式除错和测试等功能。

安装完成后,让我们开始创建一个新的 MoonBit 模块。

创建一个新模块

使用 moon new 创建一个新项目,默认的配置是:

$ 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

这会在 my-project 下创建一个名为 username/hello 的新模块。上述过程也可以使用 moon new my-project 代替。

了解模块目录结构

上一步所创建的模块目录结构如下所示:

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

这里简单解释一下目录结构:

  • moon.mod.json 用来标记这个目录是一个模块。它包含了模块的元信息,例如模块名、版本等。

    {
      "name": "username/hello",
      "version": "0.1.0",
      "readme": "README.md",
      "repository": "",
      "license": "Apache-2.0",
      "keywords": [],
      "description": "",
      "source": "src"
    }
    

    source 字段指定了模块的源代码目录,默认值是 src。该字段存在的原因是因为 MoonBit 模块中的包名与文件路径相关。例如,当前模块名为 username/hello,而其中一个包所在目录为 lib/moon.pkg.json,那么在导入该包时,需要写包的全名为 username/hello/lib。有时,为了更好地组织项目结构,我们想把源码放在 src 目录下,例如 src/lib/moon.pkg.json,这时需要使用 username/hello/src/lib 导入该包。但一般来说我们并不希望 src 出现在包的路径中,此时可以通过指定 "source": "src" 来忽略 src 这层目录,便可使用 username/hello/lib 导入该包。

  • src/libsrc/main 目录:这是模块内的包。每个包可以包含多个 .mbt 文件,这些文件是 MoonBit 语言的源代码文件。但是,无论一个包有多少 .mbt 文件,它们都共享一个 moon.pkg.json 文件。lib/*_test.mbtlib 包中的独立测试文件,这些文件用于黑盒测试,无法直接访问 lib 包的私有成员。

  • moon.pkg.json 是包描述文件。它定义了包的属性,例如,是否是 main 包,所导入的其他包。

    • main/moon.pkg.json:

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

    这里,"is_main: true" 表示这个包需要被链接成目标文件。在 wasm/wasm-gc 后端,会被链接成一个 wasm 文件,在 js 后端,会被链接成一个 js 文件。

    • lib/moon.pkg.json:

      {}
      

    这个文件只是为了告诉构建系统当前目录是一个包。

如何使用包

我们的 username/hello 模块包含两个包:username/hello/libusername/hello/main

username/hello/lib 包含 hello.mbthello_test.mbt 文件:

hello.mbt

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

hello_test.mbt

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

username/hello/main 只包含一个 main.mbt 文件:

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

为了执行程序,需要在 moon run 命令中指定 username/hello/main 包的文件系统路径

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

你也可以省略 ./

$ moon run src/main
Hello, world!

你可以使用 moon test 命令进行测试:

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

如何导入包

在 MoonBit 的构建系统中,模块名用于引用其内部包。

如果想在 src/main/main.mbt 中使用 username/hello/lib 包,你需要在 src/main/moon.pkg.json 中指定:

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

这里,username/hello/lib 指定了从 username/hello 模块导入 username/hello/lib 包,所以你可以在 main/main.mbt 中使用 @lib.hello()

注意,src/main/moon.pkg.json 中导入的包名是 username/hello/lib,在 src/main/main.mbt 中使用 @lib 来引用这个包。这里的导入实际上为包名 username/hello/lib 生成了一个默认别名。在接下来的章节中,你将学习如何为包自定义别名。

创建和使用包

首先,在 lib 下创建一个名为 fib 的新目录:

mkdir src/lib/fib

现在,你可以在 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:

{}

在创建完这些文件后,你的目录结构应该如下所示:

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

src/main/moon.pkg.json 文件中,导入 username/hello/lib/fib 包,并自定义别名为 my_awesome_fibonacci

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

这行导入了 username/hello/lib/fib 包。导入后,你可以在 main/main.mbt 中使用 fib 包了。

main/main.mbt 的文件内容替换为:

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())
}

为了执行程序,需要在 moon run 命令中指定 username/hello/main 包的文件系统路径:

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

添加测试

让我们添加一些测试来验证我们的 fib 实现。在 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)
}

这些代码测试了斐波那契数列的前五项。test { ... } 定义了一个内联测试块。内联测试块中的代码在测试模式下执行。

内联测试块在非测试模式下(moon buildmoon run)会被丢弃,因此不会导致生成的代码大小膨胀。

用于黑盒测试的独立测试文件

除了内联测试,MoonBit 还支持独立测试文件。以 _test.mbt 结尾的源文件被认为是黑盒测试的测试文件。例如,在 src/lib/fib 目录中,创建一个名为 fib_test.mbt 的文件,并粘贴以下代码:

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)
}

注意,构建系统会自动为以 _test.mbt 结尾的文件创建一个新的包,用于黑盒测试,并且自动导入当前包。因此,在测试块中需要使用 @fib 来引用 username/hello/lib/fib 包,而不需要在 moon.pkg.json 中显式地导入该包。

最后,使用 moon test 命令,它会扫描整个项目,识别并运行所有内联测试以及以 _test.mbt 结尾的文件。如果一切正常,你会看到:

$ 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

  • --strip — Enable stripping debug information

  • --no-strip — Disable stripping debug information

  • --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)

  • --warn-list <WARN_LIST> — Warn list config

  • --alert-list <ALERT_LIST> — Alert list config

  • --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] [PACKAGE_PATH]

Arguments:
  • <PACKAGE_PATH> — The package(and it's deps) to check
Options:
  • --std — Enable the standard library (default)

  • --nostd — Disable the standard library

  • -g, --debug — Emit debug information

  • --release — Compile in release mode

  • --strip — Enable stripping debug information

  • --no-strip — Disable stripping debug information

  • --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)

  • --warn-list <WARN_LIST> — Warn list config

  • --alert-list <ALERT_LIST> — Alert list config

  • --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

  • --patch-file <PATCH_FILE> — The patch file to check, Only valid when checking specified package

  • --no-mi — Whether to skip the mi generation, Only valid when checking specified package

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

  • --strip — Enable stripping debug information

  • --no-strip — Disable stripping debug information

  • --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)

  • --warn-list <WARN_LIST> — Warn list config

  • --alert-list <ALERT_LIST> — Alert list config

  • --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

  • --strip — Enable stripping debug information

  • --no-strip — Disable stripping debug information

  • --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)

  • --warn-list <WARN_LIST> — Warn list config

  • --alert-list <ALERT_LIST> — Alert list config

  • -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

  • --patch-file <PATCH_FILE> — Path to the patch file

  • --doc — Run doc test

moon clean

Remove the target directory

Usage: moon clean

moon fmt

Format source code

Usage: moon fmt [OPTIONS] [ARGS]...

Arguments:
  • <ARGS>
Options:
  • --check — Check only and don't change the source code

  • --sort-input — Sort input files

  • --block-style <BLOCK_STYLE> — Add separator between each segments

    Possible values: false, true

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
  • --no-alias — Do not use alias to shorten package names in the output

moon add

Add a dependency

Usage: moon add [OPTIONS] <PACKAGE_PATH>

Arguments:
  • <PACKAGE_PATH> — The package path to add
Options:
  • --bin — Whether to add the dependency as a binary

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 sourceing 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.

模块配置

moon 使用 moon.mod.json 文件来识别、描述一个模块。

模块名

name 字段用于指定模块的名称,必须指定。

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

模块名可以包含字母、数字、_-/

对于发布到 mooncakes.io 的模块,模块名必须以用户名开头,例如:

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

版本

version 字段用于指定模块的版本。

该字段为可选项,对于发布到 mooncakes.io 的模块,版本号必须符合 语义化版本 2.0.0 规范。

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

依赖

deps 字段用于指定模块的依赖。

moon addmoon remove 等命令自动管理。

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

README 文件

readme 字段用于指定模块的 README 文件路径。

仓库地址

repository 字段用于指定模块的仓库地址。

许可证

license 字段用于指定模块的许可证。许可证类型必须符合 SPDX 许可证列表

{
  "license": "MIT"
}

关键词

keywords 字段用于指定模块的关键词。

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

描述

description 字段用于指定模块的描述。

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

源码目录

source 字段用于指定模块的源码目录。

它必须为当前 moon.mod.json 文件所在目录的子目录。且必须为相对路径

当使用 moon new 命令创建模块时,会自动生成一个 src 目录,并且 source 字段的默认值为 src

{
  "source": "src"
}

source 字段不存在,或者其值为 null 或空字符串 "" 时,相当于设置 "source": "."。这表示源码目录为该 moon.mod.json 文件所在的目录。

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

warn 列表

关闭对应的编译器预设警告编号。

例如,如下配置中 -2 代表关闭编号为 2(Unused variable) 的警告

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

可用 moonc build-package -warn-help 查看编译器预设的警告编号

$ 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 列表

关闭用户预设 alter。

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

包配置

moon 使用 moon.pkg.json 文件来识别、描述一个包。

包名

包名不可配置,它由包的目录名决定。

is-main 字段

is-main 字段用于指定一个包是否需要被链接成一个可执行的文件。

链接所生成的产物与后端相关,当该字段为 true 时:

  • 对于 wasmwasm-gc 后端,将会生成一个可以独立运行的 WebAssembly 模块。
  • 对于 js 后端,将会生成一个可以独立运行的 JavaScript 文件。

import 字段

import 字段用于指定一个包所依赖的其他包。

test-import 字段

test-import 字段用于指定该包对应的黑盒测试包所依赖的其他包。

wbtest-import字段

wbtest-import 字段用于指定该包对应的白盒测试包所依赖的其他包。

链接选项

moon 默认只会链接 is-maintrue 的包,如果需要链接其他包,可以通过 link 选项指定。

link 选项用于指定链接选项,它的值可以为布尔值或一个对象。

  • link 值为 true 时,表示需要链接该包。构建时所指定的后端不同,产物也不同。

    {
      "link": true
    }
    
  • link 值为对象时,表示需要链接该包,并且可以指定链接选项,详细配置请查看对应后端的子页面。

wasm 后端链接选项

可配置选项

  • exports 选项用于指定 wasm 后端导出的函数名。

    例如,如下配置将当前包中的 hello 函数导出为 wasm 模块的 hello 函数, foo 函数导出为 wasm 模块的 foo 函数。在 wasm 宿主中,可以通过 hellobar 函数来调用当前包中的 hellofoo 函数。

    {
      "link": {
        "wasm": {
          "exports": [
            "hello",
            "foo:bar"
          ]
        },
      }
    }
    
  • heap-start-address 选项用于指定 moonc 编译到 wasm 后端时能够使用的线性内存的起始地址。

    例如,如下配置将线性内存的起始地址设置为 1024。

    {
      "link": {
          "wasm": {
            "heap-start-address": 1024
        },
      }
    }
    
  • import-memory 选项用于指定 wasm 模块导入的线性内存。

    例如,如下配置将 wasm 模块导入的线性内存指定为 env 模块的 memory 变量。

    {
      "link": {
        "wasm": {
          "import-memory": {
            "module": "env",
            "name": "memory"
          }
        },
      }
    }
    
  • export-memory-name 选项用于指定 wasm 模块导出的线性内存名称。

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

wasm-gc 后端链接选项

wasm-gc 后端与 wasm 后端的链接选项类似,只不过没有 heap-start-address 选项。

js 后端链接选项

可配置选项

  • exports 选项用于指定 JavaScript 模块的导出函数名。

    例如,如下配置将当前包中的 hello 函数导出为 JavaScript 模块的 hello 函数。在 JavaScript 宿主中,可以通过 hello 函数来调用当前包中的 hello 函数。

    {
      "link": {
        "js": {
          "exports": [
            "hello"
          ]
        }
      }
    }
    
  • format 选项用于指定 JavaScript 模块的输出格式。

    目前支持的格式有:

    • esm
    • cjs
    • iife

    例如,如下配置将当前包的输出格式指定为 ES Module。

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

warn 列表

关闭对应的编译器预设警告编号。

例如,如下配置中 -2 代表关闭编号为 2(Unused variable) 的警告

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

可用 moonc build-package -warn-help 查看编译器预设的警告编号

$ 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 列表

关闭用户预设 alter。

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

条件编译

条件编译的最小单位是文件。

在条件编译表达式中,支持三种逻辑操作符:andornot,其中 or 操作符可以省略不写。

例如,["or", "wasm", "wasm-gc"] 可以简写为 ["wasm", "wasm-gc"]

条件表达式中的条件可以分为后端和优化级别:

  • 后端条件"wasm""wasm-gc""js"
  • 优化等级条件"debug""release"

条件表达式支持嵌套。

如果一个文件未在 "targets" 中列出,它将默认在所有条件下编译。

示例:

{
    "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" 用于指定预构建命令,预构建命令会在 moon check|build|test 等构建命令之前执行。

"pre-build"是一个数组,数组中的每个元素是一个对象,对象中包含 inputoutputcommand 三个字段,inputoutput 可以是字符串或者字符串数组,command 是字符串,command 中可以使用任意命令行命令,以及 $input$output 变量,分别代表输入文件、输出文件,如果是数组默认使用空格分割。

目前内置了一个特殊命令 :embed,用于将文件转换为 MoonBit 源码,--text 参数用于嵌入文本文件,--binary 用于嵌入二进制文件,--text 为默认值,可省略不写。--name 用于指定生成的变量名,默认值为 resource。命令的执行目录为当前 moon.pkg.json 所在目录。

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

如果当前包目录下的 a.txt 的内容为

hello,
world

执行 moon build 后,在此 moon.pkg.json 所在目录下生成如下 a.mbt 文件

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

Config JSON Schema

moon.mod.json

moon.pkg.json