包配置#

moon 使用包配置文件来标识和描述一个包。旧格式是 moon.pkg.json,新格式是 moon.pkg。访问 moon 的仓库 查看完整的 JSON 模式。

moon.pkg.json 的支持已弃用。新项目应使用 moon.pkg;现有 JSON 配置可以按照下文说明通过 moon fmt 迁移。

新格式(moon.pkg#

新格式是简洁的 DSL。你可以通过以下命令从现有 moon.pkg.json 生成或重新格式化:

moon -C <module_dir> fmt

示例:

import {
  "moonbit-community/language/packages/virtual",
}

pkgtype(kind: "executable")

options(
  overrides: [ "moonbit-community/language/packages/implement" ],
)

moon.pkg 中,依赖通过 import { ... } 块声明。使用 @alias 设置自定义别名:

import {
  "moonbit-community/language/packages/pkgA",
  "moonbit-community/language/packages/pkgC" @c,
  "moonbitlang/core/builtin",
}

moon.pkg.json 的大多数字段都可以写在 options(...) 块中。formatterpkgtype 等稳定声明有专用的顶层形式。在 options 中使用包含 - 的旧配置键时,必须加引号。

options(
  "virtual": { "has-default": true },
)

moon.pkg 格式支持 //... 注释。

moon.pkg 的完整语法定义如下:

moon_pkg ::= statement*
statement ::= import | assign | apply

import ::= "import" "{" (import_item ",")* import_item? "}" import_kind?
import_item ::= STRING ("@" PKG_NAME)?
import_kind ::= "for" STRING

assign ::= LIDENT "=" expr

apply ::= LIDENT "(" (argument ",")* argument? ")"
argument ::= LIDENT ":" expr | STRING ":" expr  

expr ::= array | object | apply | STRING | INT | "true" | "false"
array ::= "[" (expr ",")* expr? "]"
object ::= "{" (field ",")* field? "}"

名称#

包名称不可配置;它由包的文件夹目录名称确定。

格式化#

formatter 字段用于为此包配置 moon fmt。目前它支持 ignore,即格式化器应跳过的文件名列表。

这对于生成文件或你有意保持为不同格式的文件很有用。由 pre-build 生成的文件已经会被自动跳过,因此 formatter.ignore 主要用于额外排除你想忽略的文件。

formatter(ignore: ["generated.mbt", "snapshot.mbt"])
{
  "formatter": {
    "ignore": ["generated.mbt", "snapshot.mbt"]
  }
}

包类型#

使用一条 pkgtype 声明指定包的构建类型。例如,可执行包使用:

pkgtype(kind: "executable")

可用的类型包括 libraryexecutableforeign_library。默认值是 libraryexecutable 取代旧的 options("is-main": true)foreign_library 取代旧的 options(link: true)。这些类型互为替代项,不能同时声明。

在外部库包中,#export_name 为公开的非泛型函数指定其在生成的 Wasm、JavaScript 或 C 输出中的稳定符号名称:

#export_name("attr_add")
pub fn add_by_attr(n : Int) -> Int {
  n + 42
}

MoonBit 目前要求导出名是有效的 C 符号标识符且在包内唯一,无论选择哪个后端都是如此。

警告

已知编译器问题:#export_name 目前会对所有后端施加 C 符号标识符限制。WebAssembly 导出名是 UTF-8 字符串,并不限于 C 标识符。

该属性不能用于泛型函数或带可选参数的函数。对于新的导出,优先使用 #export_name,而不是各后端的 exports 链接配置。

导出声明的作用域是生成产物的包。依赖中的属性或 exports 配置在该依赖自身构建为产物时生效,但不会向下游包的产物添加符号。若要暴露依赖的功能,请在执行导出的包中定义并导出一个包装函数。

备注

native 后端目前不支持将 foreign_library 包导出为库产物。

is-main(已弃用)#

is-main 字段已弃用。为了兼容现有包配置,它仍可使用;但新建或迁移后的 moon.pkg 应改用 pkgtype(kind: "executable")。以下旧声明与该 pkgtype 声明等价:

链接过程的输出取决于后端。当此字段设置为 true 时:

  • 对于 Wasm 和 wasm-gc 后端,将生成一个独立的 WebAssembly 模块。

  • 对于 js 后端,将生成一个独立的 JavaScript 文件。

options(
  "is-main": true,
)
{
  "is-main": true
}

导入依赖#

导入#

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

例如,以下导入 pkgApkgC,将 pkgC 别名为 c。 用户可以使用 @c 访问 pkgC 中的定义。

import {
  "moonbit-community/language/packages/pkgA",
  "moonbit-community/language/packages/pkgC" @c,
  "moonbitlang/core/builtin",
}
{
    "import": [
        "moonbit-community/language/packages/pkgA",
        {
            "path": "moonbit-community/language/packages/pkgC",
            "alias": "c"
        },
        "moonbitlang/core/builtin"
    ]
}

大多数 core 包在这里仍按普通包处理:如果你使用 @json@test 或其他普通的 core 别名,请将对应的 moonbitlang/core/... 包加入 import,以避免 core_package_not_imported 警告。

prelude 是例外。它默认可用,因此它暴露的名称不需要显式导入对应的包。

测试导入#

测试导入于指定此包的黑盒测试包依赖的其他包,配置语法与 import 相同

import {
  "path/to/package1",
  "path/to/package2" @pkg2,
} for "test"
{
  "test-import": {
    "path/to/package1",
    {
      "path": "path/to/package2",
      "alias": "pkg2"
    }
  }
}

test-import-all 字段用于指定是否导入被测试包的公共定义(默认为 true)。

白盒测试导入#

白盒测试导入用于指定此包的白盒测试包依赖的其他包,配置语法与 import 相同。

import {
  "path/to/package1",
  "path/to/package2" @pkg2,
} for "wbtest"
{
  "wbtest-import": {
    "path/to/package1",
    {
      "path": "path/to/package2",
      "alias": "pkg2"
    }
  }
}

最大并发测试数#

max-concurrent-tests 字段用于限制在 moon test 执行该包时,此包的测试同时运行的最大数量。

当同一包中的测试共享端口、临时文件或其他不应全部并行运行的外部资源时,这很有用。

options(
  "max-concurrent-tests": 2,
)
{
  "max-concurrent-tests": 2
}

条件编译#

条件编译的最小单元是一个文件。

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

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

表达式中的条件可以被归类为后端和优化层次:

  • 后端条件"wasm""wasm-gc""js"

  • 优化层次条件"debug""release"

条件表达式支持嵌套。

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

示例:

options(
  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"]]
  }
)
{
  "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"]]
  }
}

支持的目标#

supported_targets 字段用于声明一个包打算支持哪些后端。它使用的是目标集合表达式,而不是数组:

supported_targets = "js"
{
  "supported-targets": "js"
}

示例:

  • js 表示单个后端

  • +js+wasm-gc 表示显式指定一组后端

  • +all-js 表示除 js 之外的所有后端

为了兼容,旧的数组语法仍然可以使用:

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

这是包级元数据,不是条件编译规则:

  • 使用 supported_targets 声明该包支持的后端集合

  • 使用 targets 为不同后端包含或排除单独的文件

  • moon.mod 中使用 preferred_targetmoon checkmoon runmoon build 等命令选择默认后端

当模块和包都声明了 supported_targets 时,实际生效的后端集合就是它们的交集。

命令行为取决于所选择的后端:

  • moon checkmoon buildmoon testmoon bench 只保留支持所选后端的包

  • moon run 要求被选中的包支持所选后端

  • moon info 会跳过不支持的选中包,并给出警告

  • moon bundle 会跳过不支持所选后端的包目标

在根包选择完成后,Moon 还会检查可达的必需依赖。如果某个必需依赖不支持所选后端,命令会以正常的面向用户的错误信息失败。

注意:

  • 省略 supported_targets 表示支持所有后端

  • --target all 会展开为 wasmwasm-gcjsnative,但不包括 llvm

  • llvm 仍然是合法的 supported_targets

  • 旧的数组语法已被弃用,但为了兼容仍然接受

一种常见的配置方式是:

  • supported_targets = "native" 标记仅支持 native 的包

  • moon.mod 中设置 preferred_target = "native"

  • 只有当包内某些文件因后端不同而变化时,才使用 targets

原生存根文件#

native-stub 字段列出应在 native 构建中与此包一起编译的 C 存根源文件。

这通常与 FFI 文档中的 extern "C" 声明 一起使用,此时存根文件提供用 C 编写比直接用 MoonBit 编写更容易的包装函数或适配代码。

路径相对于包目录。

options(
  "native-stub": [ "stub.c", "helpers.c" ],
)
{
  "native-stub": ["stub.c", "helpers.c"]
}

Rule 和 dev_build#

rule 声明一个可复用的命令,dev_build 将一条 rule 应用于具体的输入和输出文件。这些预构建步骤会在 moon checkmoon buildmoon test 等开发命令之前运行。

此机制面向包作者在包开发期间使用。当该包作为依赖被下游用户使用时,出于安全原因,这些预构建步骤不会被触发,因此依赖不会在构建期间执行任意命令。请将生成的输出文件提交到仓库,使下游用户可以直接基于这些文件构建。

rule(name: "...", command: "...") 声明一个可复用的命令模板。name 字段标识该 rule,command 是一个 shell 命令字符串。命令可以引用 $input$output,它们由使用该 rule 的 dev_build 条目提供。一个包可以声明多个 rule 条目。

dev_build(rule: "...", input: "...", output: "...") 声明一个预构建步骤。它选择一条 rule,并提供展开该 rule 命令时使用的输入和输出路径。一个包可以声明多个 dev_build 条目。

预构建命令以模块根目录作为工作目录。输入、输出和其他预构建路径都相对于模块根目录解析。

可以在同一个 moon.pkg 中声明包级 rule,也可以在 moon.mod 中声明模块级 rule。包级 rule 只对同一个 moon.pkg 中的 dev_build 条目可见;模块级 rule 对模块内每个包中的 dev_build 条目可见。解析 rule 名称时,moon 会先在同一个 moon.pkg 中查找包级 rule,再在 moon.mod 中查找模块级 rule。

rule(name: "copy", command: "cat $input > $output")
dev_build(rule: "copy", input: "a.txt", output: "a.mbt")

moon.pkg.json 不支持 ruledev_build 条目。请改用已废弃的 pre-build 配置:

{
  "pre-build": [
    {
      "input": "a.txt",
      "output": "a.mbt",
      "command": "cat $input > $output"
    }
  ]
}

在此示例中,运行 moon check 等开发命令时,会在检查包之前将 a.txt 的内容复制到 a.mbt

警告列表#

警告列表用于禁用或启用警告。若要让已启用的警告导致命令失败,请使用 --deny-warn。警告列表是由一个或多个警告名称组成的字符串,每个名称前都有一个符号前缀:

  • -用于关闭警告

  • +用于启用警告

例如,在以下配置中,-unused_value 禁用函数或者变量未使用警告。

warnings = "-unused_value"
{
  "warn-list": "-unused_value"
}

如果需要禁用多种警告,可以直接连接起来进行组合。

warnings = "-unused_value-unreachable_code"
{
  "warn-list": "-unused_value-unreachable_code"
}

如果需要激活某种原来未启用的警告,则使用加号。

warnings = "+unused_optional_argument"
{
  "warn-list": "+unused_optional_argument"
}

旧配置可能使用 @ 前缀将警告提升为错误。该前缀仅为兼容性而保留,新配置不应再使用。需要让警告导致构建失败时,请使用 moon check --deny-warn(其他 CI 命令使用对应的选项)。

也可以在 warnings 中使用警告编号。在以下输出中,mnemonic 是警告列表使用的符号名称,id 是同一警告的数字形式。

moonc check -warn-help 当前输出的列表如下:

Available warnings:
mnemonic                   description                                                     id state
unused_value               Unused variable or function.                                     1 warn
unused_value               Unused variable.                                                 2 warn
unused_type_declaration    Unused type declaration.                                         3 warn
missing_priv               Unused abstract type.                                            4 warn
unused_type_variable       Unused type variable.                                            5 warn
unused_constructor         Unused constructor.                                              6 warn
unused_field               Unused field or constructor argument.                            7 warn
redundant_modifier         Redundant modifier.                                              8 warn
struct_never_constructed   Struct never constructed.                                        9 warn
unused_pattern             Unused pattern.                                                 10 warn
partial_match              Partial pattern matching.                                       11 error
unreachable_code           Unreachable code.                                               12 warn
unresolved_type_variable   Unresolved type variable.                                       13 warn
alert or alert_<category>  All alerts or alerts with specific category.                    14 warn
unused_mut                 Unused mutability.                                              15 error
parser_inconsistency       Parser inconsistency check.                                     16 warn
ambiguous_loop_argument    Ambiguous usage of loop argument.                               17 warn
useless_loop               Useless loop expression.                                        18 warn
deprecated                 Deprecated API usage.                                           20 warn
missing_pattern_arguments  Some arguments of constructor are omitted in pattern.           21 warn
ambiguous_block            Ambiguous block.                                                22 warn
unused_try                 Useless try expression.                                         23 warn
unused_error_type          Useless error type.                                             24 warn
test_unqualified_package   Using implicitly imported API in test.                          25 off
unused_catch_all           Useless catch all.                                              26 warn
deprecated_syntax          Deprecated syntax.                                              27 warn
todo                       Todo                                                            28 warn
unused_package             Unused package.                                                 29 warn
missing_package_alias      Empty package alias.                                            30 warn
unused_optional_argument   Optional argument never supplied.                               31 off
unused_default_value       Default value of optional argument never used.                  32 off
text_segment_excceed       Text segment exceed the line or column limits.                  33 warn
implicit_use_builtin       Implicit use of definitions from `moonbitlang/core/builtin`.    34 warn
reserved_keyword           Reserved keyword.                                               35 warn
block_label_shadowing      Block label shadows another label.                              36 warn
unused_block_label         Unused block label.                                             37 warn
missing_invariant          For-loop is missing an invariant.                               38 off
missing_reasoning          For-loop is missing a proof_reasoning.                          39 off
multiline_string_escape    Deprecated escape sequence in multiline string.                 40 error
missing_rest_mark          Missing `..` in map pattern.                                    41 warn
invalid_attribute          Invalid attribute.                                              42 warn
unused_attribute           Unused attribute.                                               43 warn
invalid_inline_wasm        Invalid inline-wasm.                                            44 error
unused_rest_mark           Useless `..` in pattern                                         46 warn
missing_definition         Unused pub definition because it does not exist in mbti file.   49 warn
method_shadowing           Local method shadows upstream method                            50 warn
ambiguous_precedence       Ambiguous operator precedence                                   51 warn
unused_loop_variable       Loop variable not updated in loop                               52 warn
unused_trait_bound         Unused trait bound                                              53 warn
ambiguous_range_direction  Ambiguous looping direction for range e1..=e2                   54 off
unannotated_ffi            Unannotated FFI param type                                      55 error
missing_pattern_field      Missing field in struct pattern                                 56 warn
missing_pattern_payload    Constructor pattern expect payload                              57 warn
unaligned_byte_access      Unaligned byte access in bits pattern                           59 warn
unused_struct_update       Unused struct update                                            60 warn
duplicate_test             Duplicate test name                                             61 warn
invalid_cascade            Calling method with non-unit return type via `..`               62 warn
syntax_lint                Syntax lint warning                                             63 warn
unannotated_toplevel_array Unannotated toplevel array                                      64 warn
prefer_readonly_array      Suggest ReadOnlyArray for read-only array literal               65 off
prefer_fixed_array         Suggest FixedArray for mutated array literal                    66 off
unused_async               Useless `async` annotation                                      67 warn
declaration_unimplemented  Declaration is unimplemented                                    68 warn
declaration_implemented    Declaration is already implemented                              69 off
deprecated_for_in_method   using `iterator()` method for `for .. in` loop.                 70 off
core_package_not_imported  Packages in `moonbitlang/core` need to be explicitly imported.  71 warn
unqualified_local_using    unqualified local using                                         72 off
unnecessary_annotation     unnecessary type annotation                                     73 off
missing_doc                Missing documentation for public definition                     74 off
unnecessary_view_op        Unnecessary `[:]` view operator                                 75 off
result_error_return        Using `Result[T, E]` where `E` is an error type.                78 off
implicit_impl_as_method    `impl` implicitly promoted as method                            79 off
regex_match_missing_before Missing `before` binding in `regex match`.                      80 warn
regex_match_missing_after  Missing `after` binding in `regex match`.                       81 warn
ambiguous_braces           Ambiguous `{}` braces.                                          82 warn
type_param_method          Calling method of type parameter in a deprecated way.           83 warn
unqualified_record         Struct literal in a `let` binding without a type prefix.        84 off
unlabelled_break_in_labelled_loop Unlabelled `break` directly inside a labelled loop.             85 warn
unlabelled_continue_in_labelled_loop Unlabelled `continue` directly inside a labelled loop.          86 warn
guard_inexhaustive         `guard` condition is not exhaustive and may panic.              87 warn
guard_redundant_bang       Redundant `!` on an exhaustive `guard`.                         88 warn
guard_redundant_else       Redundant `else` on an exhaustive `guard`.                      89 warn
all                        all warnings
state: warn = enabled, error = promoted to error, off = disabled
note: default alert exceptions: alert_unsafe=off

备注

使用 moonc check -warn-help 查看预设编译器警告列表。

alert警告#

alert是一种特殊的警告,表示使用了某些被 #internal属性 标记了的 API。

所有alert都附有一个类别,这是由 API 的作者定义的。你可以通过alert_<类别>这样的警告名来启用或者关闭特定的alert类别,或者用alert一次性控制所有alert警告。

例如,以下配置启用除 unsafe 类别以外的所有 alert 警告。在 CI 中,请为 moon checkmoon test 或相应命令添加 --deny-warn,将已启用的警告视为致命错误。

warnings = "+alert-alert_unsafe"
{
  "warn-list": "+alert-alert_unsafe"
}

虚拟包#

一个虚拟包可以作为一个包的接口被实际的实现替换。

声明#

virtual 字段用于将当前包声明为虚拟包。

例如,以下配置声明了一个具有默认实现的虚拟包:

options(
  virtual: {
    "has-default": true,
  },
)
{
  "virtual": {
    "has-default": true
  }
}

实现#

implement 字段用于指定当前包实现的虚拟包。

例如,以下配置实现了一个虚拟包:

options(
  implement: "moonbitlang/core/abort",
)
{
  "implement": "moonbitlang/core/abort"
}

覆盖实现#

overrides 字段用于提供满足导入虚拟包的实现。

例如,以下配置将内置的 abort 包的默认实现替换为另一个包:

options(
  overrides: [ "moonbitlang/dummy_abort/abort_show_msg" ],
)
{
  "overrides": ["moonbitlang/dummy_abort/abort_show_msg"]
}