MoonBit 构建系统教程#
Moon 是 MoonBit 语言的构建系统,目前基于 n2 项目。Moon 支持并行和增量构建。此外,moon 还在 mooncakes.io 上管理和构建第三方包。
先决条件#
在开始本教程之前,请确保你已安装以下内容:
MoonBit CLI 工具:从 https://www.moonbitlang.cn/download/ 下载。这个命令行工具用于创建和管理 MoonBit 项目。
使用
moon help
查看使用说明。$ moon help ...
Visual Studio Code 中的 MoonBit 语言 插件:你可以从 VS Code 市场安装。此插件为 MoonBit 提供了丰富的开发环境,包括语法高亮、代码补全等功能。
一旦你满足了这些先决条件,我们就可以开始创建一个新的 MoonBit 模块。
创建一个新模块#
要创建一个新模块,在终端中输入 moon new <path>
命令,其中 path 是你想要创建项目的文件夹目录,之后项目会被创建。使用默认值,你会在 my_project
目录中创建一个名为 username/my_project
的新模块。
$ moon new my_project
Initialized empty Git repository in my_project/.git/
Created username/my_project at my_project
你也可以通过使用 --user
选项和 --name
选项分别指定用户名和模块名称。如果你已经登录,用户名将默认为你的用户名。
理解模块目录结构#
创建新模块后,你的目录结构应该如下:
my_project
├── Agents.md
├── cmd
│ └── main
│ ├── main.mbt
│ └── moon.pkg.json
├── LICENSE
├── moon.mod.json
├── moon.pkg.json
├── my_project_test.mbt
├── my_project.mbt
├── README.mbt.md
└── README.md -> README.mbt.md
备注
在 Windows 系统上,你需要管理员权限或启用开发者模式才能创建符号链接。
以下是目录结构的简要说明:
moon.mod.json
用于标识目录为 MoonBit 模块。它包含模块的元数据,如模块名称、版本等。{ "name": "username/my_project", "version": "0.1.0", "readme": "README.md", "repository": "", "license": "Apache-2.0", "keywords": [], "description": "" }
.
和cmd/main
目录:这些是模块中的包。每个包可以包含多个.mbt
文件,这些文件是 MoonBit 语言的源代码文件。但是,无论一个包有多少.mbt
文件,它们都共享一个公共的moon.pkg.json
文件。*_test.mbt
是独立测试文件,这些文件用于黑盒测试,因此同一个包的私有成员不能直接访问。moon.pkg.json
是包描述符。它定义了包的属性,例如它是否是 main 包以及它导入的包。cmd/main/moon.pkg.json
:{ "is-main": true, "import": [ { "path": "username/my_project", "alias": "lib" } ] }
这里,
"is_main: true"
声明该包包含moon run
指令的入口。moon.pkg.json
:{}
此文件为空。它的目的只是告诉构建系统这个文件夹是一个包。
README.mbt.md
是 README 文件。内部编写的代码块将通过moon check
和moon test
进行类型检查和测试。
使用包#
我们的 username/my_project
模块包含两个包:username/my_project
和 username/my_project/cmd/main
。
username/my_project
包包含 my_project.mbt
和 my_project_test.mbt
文件:
///|
pub fn fib(n : Int) -> Int64 {
for i = 0, a = 0L, b = 1L; i < n; i = i + 1, a = b, b = a + b {
} else {
b
}
}
///|
test "fib" {
let array = [1, 2, 3, 4, 5].map(fib(_))
// `inspect` is used to check the output of the function
// Just write `inspect(value)` and execute `moon test --update`
// to update the expected output, and verify them afterwards
inspect(array, content="[1, 2, 3, 5, 8]")
}
备注
生成的文件名取决于包名。
username/my_project/cmd/main
包包含一个 main.mbt
文件:
///|
fn main {
println(@lib.fib(10))
}
要执行程序,在 moon run
命令中指定文件系统路径到 username/my_project/cmd/main
包:
$ moon run cmd/main
89
你可以使用 moon test
命令进行测试:
$ moon test
Total tests: 1, passed: 1, failed: 0.
包导入#
在 MoonBit 的构建系统中,模块的依赖被定义在包级别。要在 username/my_project/cmd/main
中导入 username/my_project
包,你需要在 cmd/main/moon.pkg.json
中指定:
{
"is-main": true,
"import": [
{
"path": "username/my_project",
"alias": "lib"
}
]
}
这里,username/my_project
指定从 username/my_project
模块导入 username/my_project
包,并且有别名 lib
,所以你可以在 cmd/main/main.mbt
中使用 @lib.fib(10)
。
创建和使用新包#
首先,在 lib
下创建一个名为 fib
的新目录:
mkdir fib
现在,你可以在 fib
下创建新文件:
pub fn fib_slow(n : Int) -> Int {
match n {
0 => 0
1 => 1
_ => fib_slow(n - 1) + fib_slow(n - 2)
}
}
pub fn fib_fast(num : Int) -> Int {
fn aux(n, acc1, acc2) {
match n {
0 => acc1
1 => acc2
_ => aux(n - 1, acc2, acc1 + acc2)
}
}
aux(num, 0, 1)
}
{}
在创建这些文件后,你的目录结构应该如下:
.
├── Agents.md
├── cmd
│ └── main
│ ├── main.mbt
│ └── moon.pkg.json
├── fib
│ ├── fast.mbt
│ ├── moon.pkg.json
│ └── slow.mbt
├── LICENSE
├── moon.mod.json
├── moon.pkg.json
├── my_project_test.mbt
├── my_project.mbt
├── README.mbt.md
└── README.md -> README.mbt.md
在 cmd/main/moon.pkg.json
文件中,导入 username/my_project/fib
包并将其别名定制为 my_awesome_fibonacci
:
{
"is_main": true,
"import": [
{
"path": "username/my_project/fib",
"alias": "my_awesome_fibonacci"
}
]
}
这一行导入了 fib
包,它是 username/my_project
模块中 fib
包的一部分。在这样做之后,你可以在 cmd/main/main.mbt
中使用 fib
包。
fn main {
let a = @my_awesome_fibonacci.fib_slow(10)
let b = @my_awesome_fibonacci.fib_fast(11)
println("fib(10) = \{a}, fib(11) = \{b}")
}
为了执行你的程序,指定 main 包的路径:
$ moon run cmd/main
fib(10) = 55, fib(11) = 89
添加测试#
让我们添加一些测试来验证我们的 fib 实现。在 fib/fib_test.mbt
中添加以下内容:
test {
inspect(fib_slow(0))
inspect(fib_slow(1))
inspect(fib_slow(2))
}
这段代码测试斐波那契数列的前三项。test { ... }
定义了一个内联测试块。内联测试块中的代码在测试模式下执行。
内联测试块在非测试编译模式(moon build
和 moon run
)中被丢弃,因此它们不会导致生成的代码大小膨胀。
这里我们使用了快照测试。执行 moon test --update
,文件应该被更改为:
test {
inspect(@fib.fib_slow(0), content="0")
inspect(@fib.fib_slow(1), content="1")
inspect(@fib.fib_slow(2), content="1")
}
注意,测试代码使用 @fib
来引用 fib
包。构建系统通过使用以 _test.mbt
结尾的文件自动为黑盒测试创建一个新包。
最后,使用 moon test
命令,它会扫描整个项目,识别并运行所有测试。如果一切正常,你将看到:
$ moon test
Total tests: 2, passed: 2, failed: 0.