读懂 MoonBit 工程配置:moon.mod、moon.pkg、moon.work 全解析

3 阅读11分钟

基于 MoonBit 0.9 版本实现,本文系统说明 moon.modmoon.pkgmoon.work 的职责、关系、区别、支持的配置项、兼容写法,以及常见错误与排查方式。本文以 moonbitlang/moon 仓库中的真实实现为依据,目标是给出一份面向实际使用、尽量与当前行为一致的中文参考说明。


Moon 当前涉及三类项目清单:

  • 模块清单
    • moon.mod
    • moon.mod.json
  • 包清单
    • moon.pkg
    • moon.pkg.json
  • 工作区清单
    • moon.work

它们对应三个不同层级:

文件层级作用
moon.mod / moon.mod.jsonmodule描述模块身份、模块依赖、源码根目录、模块级默认配置
moon.pkg / moon.pkg.jsonpackage描述单个包的导入、构建、测试、target 支持等
moon.workworkspace描述多个模块组成的工作区

最重要的区别是:

  • module 是依赖解析单位
  • package 是编译单位
  • workspace 是多个 module 的组织单位

基本关系

module 与 package 的关系

一个 module 可以包含多个 package。

module 根目录由以下文件之一标识:

  • moon.mod
  • moon.mod.json

package 目录由以下文件之一标识:

  • moon.pkg
  • moon.pkg.json

module 负责:

  • 模块名与模块版本
  • 模块级依赖
  • 包扫描根目录(source
  • 模块级 target 默认值
  • 发布元信息

package 负责:

  • 当前包导入哪些包
  • 当前包是否是入口包(is-main
  • 测试导入
  • 条件编译
  • pre-build
  • package 级 supported-targets

workspace 与 module 的关系

workspace 用 moon.work 表示,用于把多个 module 组织在一起。

它不替代 module,而是建立在多个 module 之上。

常见布局如下:

repo/
  moon.work
  app/
    moon.mod.json
    src/
      moon.pkg.json
  lib/
    moon.mod.json
    src/
      moon.pkg.json

这里:

  • repo/ 是 workspace 根
  • app/lib/ 是两个独立 module
  • 每个 module 各自有自己的 package 结构

moon.modmoon.mod.json

共同职责

moon.modmoon.mod.json 都表示模块清单。
它们用于描述:

  • name
  • version
  • deps
  • bin-deps
  • source
  • preferred-target
  • supported-targets
  • 发布元信息
  • 模块脚本
  • 模块级规则

当前实现中的读取顺序

当前实现中,如果同一目录同时存在:

  • moon.mod
  • moon.mod.json

则会优先读取 moon.mod
如果没有 moon.mod,才会读取 moon.mod.json

因此:

不要在同一个 module 目录下同时维护这两个文件。

两者的主要区别

moon.mod.json

这是完整 JSON 格式,字段最完整,最适合作为主配置格式。

moon.mod

这是 DSL 格式。
它并不是“可以随意替代 moon.mod.json 的完整自由写法”,当前实现中它只支持一部分顶层键,并且许多配置依赖兼容映射。

因此:

复杂模块配置推荐优先使用 moon.mod.json

moon.mod.json 支持的主要字段

以下字段可以从当前实现中的 MoonModJSON 和 schema 直接确认。

必填字段

name

模块名,必填。

{
  "name": "chenbimo/demo"
}

推荐使用两段式命名:

  • 用户名/模块名

例如:

  • moonbitlang/core
  • chenbimo/demo

常用字段

version

模块版本。

{
  "name": "chenbimo/demo",
  "version": "0.1.0"
}

按 semver 解析。

deps

模块依赖。

当前实现中,deps 支持以下几类值:

registry 简写

{
  "deps": {
    "moonbitlang/x": "0.1.0"
  }
}

registry 对象写法

{
  "deps": {
    "moonbitlang/x": {
      "version": "0.1.0"
    }
  }
}

本地路径依赖

{
  "deps": {
    "chenbimo/lib": {
      "path": "../lib"
    }
  }
}

git 依赖

{
  "deps": {
    "chenbimo/lib": {
      "git": "https://github.com/chenbimo/lib.git",
      "branch": "main",
      "version": "0.1.0"
    }
  }
}

就当前核对到的 schema 而言,git dependency 明确包含:

  • git
  • branch
  • version

至少在这份实现证据中,没有直接确认 tag / rev 是 manifest 字段。

bin-deps

模块级二进制依赖。

{
  "bin-deps": {
    "moonbitlang/formatter": {
      "version": "0.1.0",
      "bin_pkg": ["moonbitlang/formatter"]
    }
  }
}

它与普通 deps 的区别是:

  • deps 用于代码依赖
  • bin-deps 用于工具/可执行依赖

另外,bin-deps 只针对输入/root module 处理,不按普通依赖那样传递传播。

source

包扫描根目录。

{
  "name": "chenbimo/demo",
  "source": "src"
}

含义:

  • Moon 从 src/ 开始递归寻找 moon.pkg / moon.pkg.json
  • package 路径相对于 source 计算
  • source 本身不计入 package 的逻辑路径

如果不写,默认值等价于:

  • "."

当前实现还要求:

  • source 不能是绝对路径
  • source 不能包含非法字符 < > : " | ? *

preferred-target

模块级默认偏好 target。

{
  "preferred-target": "wasm-gc"
}

当前可确认的合法值:

  • wasm
  • wasm-gc
  • js
  • native
  • llvm

它表示“默认偏好后端”,不表示“只允许这个后端”。

supported-targets

模块级支持的 target 集合。

{
  "supported-targets": "js"
}

也兼容旧数组语法:

{
  "supported-targets": ["js", "native"]
}

当前实现/文档明确支持的词项包括:

  • js
  • wasm
  • wasm-gc
  • native
  • llvm
  • all

推荐使用字符串表达式,例如:

  • "js"
  • "all-js"
  • "js+wasm-gc"

发布相关字段

以下字段在 schema 中明确存在:

  • description
  • license
  • keywords
  • repository
  • readme
  • include
  • exclude

示例:

{
  "name": "chenbimo/demo",
  "version": "0.1.0",
  "description": "A demo MoonBit module",
  "license": "Apache-2.0",
  "repository": "https://github.com/chenbimo/demo",
  "readme": "README.md",
  "keywords": ["moonbit", "demo"]
}

scripts

模块脚本配置。

当前实现中,至少能明确确认一个被实际消费的脚本键:

  • postadd

例如:

{
  "scripts": {
    "postadd": "python3 tools/postadd.py"
  }
}

rule

模块级规则。

{
  "rule": [
    {
      "name": "gen",
      "command": "python3 tools/gen.py"
    }
  ]
}

约束:

  • rule.name 不能重复

实验字段

当前实现中还存在实验字段:

  • --moonbit-unstable-prebuild

它是实验性能力,不应当视作稳定公共接口。

moon.mod(DSL)支持的内容

这一节是最需要注意的部分。

当前实现中允许的顶层键

moon.mod 当前实现接受的顶层键只有:

  • import
  • options
  • warnings
  • name
  • version
  • rule
  • supported_targets

这意味着:

不是所有 moon.mod.json 字段都可以直接写在 moon.mod 顶层。

最适合用 moon.mod 的场景

moon.mod 更适合:

  • 声明模块名
  • 声明版本
  • 声明少量 registry 依赖
  • supported_targets
  • warnings
  • rule

如果你需要更完整、更稳定的字段支持,建议直接使用:

  • moon.mod.json

moon.mod 中的 import

这是 moon.mod 中最重要、也最受限制的部分。

当前实现中:

moon.modimport 只支持带版本号的 registry dependency。

也就是说,它的语义必须是:

  • 模块名@版本

例如:

  • moonbitlang/x@0.1.0

当前实现明确不支持:

  • 本地路径依赖
  • git 依赖
  • 无版本 registry dependency
  • 结构化 dependency object

因此,如果你需要写:

  • path
  • git
  • 更复杂的 dependency object

请直接使用:

  • moon.mod.json

options

options 是 DSL 的兼容入口。
实现会把 options 中的对象内容并入最终模块 JSON。

因此,从实现机制上说,一些不能直接写在 moon.mod 顶层的字段,可能通过 options 间接表达,例如:

  • source
  • description
  • license
  • repository
  • readme
  • keywords
  • include
  • exclude
  • preferred-target
  • scripts
  • deps
  • bin-deps

但是这里要强调:

这属于兼容路径,不是最推荐的主写法。

如果你的模块已经需要这些字段,通常更推荐改用:

  • moon.mod.json

warningswarn-list

在 DSL 中写的是:

  • warnings

最终会映射到 JSON 字段:

  • warn-list

对应关系如下:

DSLJSON
warningswarn-list

supported_targetssupported-targets

在 DSL 中写的是:

  • supported_targets

最终会映射到 JSON 字段:

  • supported-targets

对应关系如下:

DSLJSON
supported_targetssupported-targets

rule

rulemoon.mod 顶层原生支持的复杂字段之一,而且允许重复出现。
不过:

  • 可以有多条 rule
  • rule.name 不能重复

关于 DSL 的具体标点语法

当前实现已经明确限制了:

  • 允许哪些顶层键
  • import 的语义限制
  • options / warnings / supported_targets 的兼容作用

但如果讨论到:

  • 括号长什么样
  • 对象字面量的具体写法
  • 某个分隔符是否唯一正确

这类“DSL 外观”问题,在这次核对中没有拿到足够直接、完整的官方样例来给出唯一模板。

因此本文采取更保守的做法:

  • 确认语义
  • 不把某种具体标点形式写死成“唯一合法格式”

如果你追求最低歧义,仍然建议优先使用:

  • moon.mod.json

moon.pkgmoon.pkg.json

它们的职责

moon.pkg / moon.pkg.json 描述单个 package 的构建与导入行为。

常见职责包括:

  • import 哪些 package
  • 是否是入口包(is-main
  • whitebox / blackbox test import
  • package 级 supported-targets
  • pre-build
  • 条件编译 targets
  • link
  • native-stub
  • virtual
  • sub-package
  • warn-list

package 与 module 的分工

module 级(moon.mod*

负责:

  • 模块名
  • 模块版本
  • 模块依赖
  • source
  • 发布信息
  • 模块级默认 target / 支持 target

package 级(moon.pkg*

负责:

  • 当前包 import 谁
  • 当前包是否是 is-main
  • 测试导入
  • pre-build
  • target 约束
  • link / native-stub / virtual 等包级行为

moon.pkg.json 的常见字段

根据当前 schema,可确认的常见字段包括:

  • import
  • wbtest-import
  • test-import
  • test-import-all
  • is-main
  • supported-targets
  • pre-build
  • targets
  • link
  • native-stub
  • virtual
  • sub-package
  • warn-list
  • name
  • overrides
  • max-concurrent-tests
  • proof-enabled
  • regex-backend

最小示例

{
  "is-main": true
}

带导入的示例

{
  "is-main": true,
  "import": ["moonbitlang/x"]
}

表示:

  • 这是一个 main package
  • 它导入了 moonbitlang/x

package 级 supported-targets

package 也可以限制自己的 target 支持集合:

{
  "supported-targets": "js"
}

如果 module 也定义了 supported-targets,实际效果是:

  • package 支持集 ∩ module 支持集

pre-build

package 可以声明生成步骤,例如:

{
  "pre-build": [
    {
      "input": ["assets/a.txt"],
      "output": ["generated/a.mbt"],
      "command": "tool"
    }
  ]
}

moon.work

作用

moon.work 用于描述工作区。
它把多个 module 放在一起,使部分命令可以在工作区范围内运行。

它不负责 package 细节,也不替代 module manifest。

当前实现明确支持的字段

当前可以明确确认 moon.work 支持:

  • members
  • preferred_target

示例:

members = ["./app", "./lib"]
preferred_target = "wasm-gc"

members

members 列出当前工作区包含的 module 路径。

这些路径相对于 workspace 根目录解释。

preferred_target

工作区级默认 target。
当 module 本身没有设置 preferred-target 时,workspace 的 preferred_target 可以作为默认后备。

三者如何协同工作

单模块项目

单模块项目通常只需要:

  • 一个 moon.mod.json
  • 若干个 moon.pkg.json

多模块仓库

多模块仓库通常是:

  • 每个 module 各自维护自己的 moon.mod.json
  • 仓库根维护一个 moon.work

哪些命令是 workspace 级?

当前实现中,以下命令可以在 workspace 范围内运行:

  • moon build
  • moon check
  • moon test
  • moon fmt
  • moon info

哪些命令更偏 module 级?

以下命令更偏向针对单个 module:

  • moon add
  • moon remove
  • moon tree
  • moon package
  • moon publish
  • moon doc
  • moon prove

即使在 workspace 下,它们通常也需要一个明确的目标 module。

推荐写法与兼容写法

文件格式层面

推荐

  • moon.mod.json
  • moon.pkg.json
  • moon.work

兼容

  • moon.mod
  • moon.pkg

字段名层面

推荐/标准字段DSL/兼容字段
supported-targetssupported_targets
warn-listwarnings

options

options 是 DSL 兼容入口。
它能工作,但不是最推荐的主配置方式。

只要你已经依赖 options 写较多复杂字段,通常就意味着更适合改用:

  • moon.mod.json

关于 moon.mod 中的依赖写法

这是最关键的一条:

moon.modimport 只支持带版本号的 registry dependency。

如果你需要:

  • path dependency
  • git dependency
  • 结构化 dependency object

请直接用:

  • moon.mod.json

常见错误与排查

以下错误或错误类型可以直接从当前实现中确认。

moon.mod 顶层键不允许

现象

moon.mod 顶层写了不支持的键,例如直接写某些 JSON 字段。

典型报错

  • Unexpected key '...' found in moon.mod.

说明

当前实现中,moon.mod 顶层只接受:

  • import
  • options
  • warnings
  • name
  • version
  • rule
  • supported_targets

处理建议

  • 简单字段保留在 DSL 顶层
  • 复杂字段改用 moon.mod.json

moon.mod 顶层重复键

典型报错

  • Duplicate key '...' found in moon.mod.

说明

除了 rule 以外,moon.mod 顶层不允许重复键。

rule 名字重复

典型报错

  • Duplicate rule name '...' found in moon.mod.

处理建议

确保每条 rule.name 唯一。

moon.modimport 写了不受支持的依赖

典型报错

  • moon.mod only supports versioned registry dependencies in import, found '...'
  • moon.mod does not support local dependency '...' in import; use workspace configuration in moon.work instead
  • moon.mod only supports registry dependencies in import, found structured dependency '...'

说明

moon.modimport 只支持:

  • 模块名@版本

处理建议

  • path / git / 复杂依赖 → 改用 moon.mod.json

source 非法

典型报错类型

  • source should not contain invalid chars ...
  • source not a subdirectory of the parent directory

说明

当前实现要求:

  • source 不能是绝对路径
  • 不能包含非法字符 < > : " | ? *

处理建议

  • 使用相对路径
  • 推荐写法如:"src""packages""."

name 为空

典型报错

  • `name` should not be empty

处理建议

确保 module manifest 中始终有合法的 name

preferred-target 非法

典型报错类型

  • `preferred-backend` is not a valid backend

当前可确认的合法值

  • wasm
  • wasm-gc
  • js
  • native
  • llvm

supported-targets 格式错误

典型报错类型

  • `supported_targets` bad format

处理建议

确认值符合当前支持语法,例如:

  • "js"
  • "all-js"
  • ["js", "native"]

并优先使用字符串表达式。

推荐实践

新项目推荐方案

单模块项目

推荐使用:

  • moon.mod.json
  • moon.pkg.json

多模块仓库

推荐使用:

  • 每个 module 使用 moon.mod.json
  • 仓库根使用 moon.work

什么时候可以继续用 moon.mod

当你的 module 配置非常简单,例如只需要:

  • name
  • version
  • 少量简单 registry 依赖
  • supported_targets
  • warnings
  • rule

这时可以使用 moon.mod

什么时候建议直接改用 moon.mod.json

只要你需要以下任意一个功能,就建议改用 moon.mod.json

  • source
  • path dependency
  • git dependency
  • bin-deps
  • scripts
  • 发布元信息
  • preferred-target
  • 更稳定、更清晰的模块配置方式

最小示例

单模块项目

moon.mod.json

{
  "name": "chenbimo/demo",
  "version": "0.1.0",
  "source": "src"
}

src/moon.pkg.json

{
  "is-main": true
}

带依赖的模块

moon.mod.json

{
  "name": "chenbimo/demo",
  "version": "0.1.0",
  "source": "src",
  "deps": {
    "moonbitlang/x": "0.1.0"
  },
  "preferred-target": "wasm-gc",
  "supported-targets": "all"
}

src/moon.pkg.json

{
  "is-main": true,
  "import": ["moonbitlang/x"]
}

多模块工作区

moon.work

members = ["./app", "./lib"]
preferred_target = "wasm-gc"

app/moon.mod.json

{
  "name": "chenbimo/app",
  "version": "0.1.0",
  "source": "src",
  "deps": {
    "chenbimo/lib": {
      "path": "../lib"
    }
  }
}

lib/moon.mod.json

{
  "name": "chenbimo/lib",
  "version": "0.1.0",
  "source": "src"
}

结论

如果只记住最核心的内容,可以记住下面四点:

  1. moon.mod* 管 module
  2. moon.pkg* 管 package
  3. moon.work 管 workspace
  4. 复杂配置优先用 JSON manifest

更具体一点:

  • moon.mod 是 DSL/兼容路径,可用于简单场景
  • moon.mod.json 是更完整、更稳定的模块清单格式
  • moon.mod 中的 import 只支持带版本号的 registry dependency
  • moon.work 当前只负责组织多个 module,并提供工作区级默认 target

如果你希望获得:

  • 最稳定的行为
  • 最清晰的字段语义
  • 最少的兼容映射困扰

推荐采用:

moon.mod.json + moon.pkg.json + moon.work

速查表

文件层级主要职责推荐程度
moon.modmoduleDSL 模块清单,适合简单场景兼容可用
moon.mod.jsonmodule完整模块清单推荐
moon.pkgpackageDSL 包清单兼容可用
moon.pkg.jsonpackage完整包清单推荐
moon.workworkspace工作区清单推荐