包配置#

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

新格式(moon.pkg#

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

moon fmt -C <module_dir>

示例:

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

options(
  "is-main": true,
  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(...) 块中。 键名和值的形状保持不变;包含 - 的旧配置键需要加引号。

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? "}"

名称#

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

is-main#

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

链接过程的输出取决于后端。当此字段设置为 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"
    ]
}

核心包在这里没有特殊处理:如果你使用 @json@test 或其他核心别名,请将对应的 moonbitlang/core/... 包加入 import,以避免 core_package_not_imported 警告。

测试导入#

测试导入于指定此包的黑盒测试包依赖的其他包,配置语法与 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"
    }
  }
}

条件编译#

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

在条件编译表达式中,支持三种逻辑运算符: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"]]
  }
}

预构建#

pre-build 字段用于指定预构建命令,这些命令将在构建命令(如 moon check|build|test)之前执行。

"pre-build" 是一个数组,其中每个元素是一个包含 inputoutputcommand 字段的对象。inputoutput 字段可以是字符串或字符串数组,而 command 字段是一个字符串。在 command 中,可以使用任何 shell 命令,以及分别表示输入和输出文件的 $input$output 变量。如果这些字段是数组,它们将默认使用空格连接。

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

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

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

hello,
world

那么在 moon.pkg.json 所在目录中运行 moon build 后,将生成以下 a.mbt 文件:

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

Warnings List#

用于关闭警告,启用警告,或者把一个启用的警告视为错误。警告列表是由多个警告名组成的字符串,每个警告名前有一个符号前缀:

  • -用于关闭警告

  • +用于启用警告

  • @用于把一个已经启用的警告视为错误

例如,在以下配置中,-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"
}

要把一个警告视为错误,使用@

warnings = "@deprecated"
{
  "warn-list": "@deprecated"
}

你也可以在警告列表中使用警告编号。这里是完整的警告名和编号:

可用警告:
    名称                           描述
  1 unused_value                   未使用的变量或函数。
  2 unused_value                   未使用的变量。
  3 unused_type_declaration        未使用的类型声明。
  4 missing_priv                   未使用的抽象类型。
  5 unused_type_variable           未使用的类型变量。
  6 unused_constructor             未使用的构造器。
  7 unused_field                   未使用的字段或构造器参数。
  8 redundant_modifier             冗余的修饰符。
  9 struct_never_constructed       结构体从未被构造。
 10 unused_pattern                 未使用的模式。
 11 partial_match                  部分模式匹配。
 12 unreachable_code               不可达代码。
 13 unresolved_type_variable       未解析的类型变量。
 14 alert or alert_<category>      所有 alert 或指定类别的 alert。
 15 unused_mut                     未使用的可变性。
 16 parser_inconsistency           解析器一致性检查。
 17 ambiguous_loop_argument        循环参数使用含糊不清。
 18 useless_loop                   无用的循环表达式。
 19 toplevel_not_left_aligned      顶层声明未左对齐。
 20 deprecated                     使用了已弃用的 API。
 21 missing_pattern_arguments      模式中省略了构造器的某些参数。
 22 ambiguous_block                块含义不明确。
 23 unused_try                     无用的 try 表达式。
 24 unused_error_type              无用的错误类型。
 25 test_unqualified_package       在测试中使用了隐式导入的 API。
 26 unused_catch_all               无用的 catch all。
 27 deprecated_syntax              已弃用的语法。
 28 todo                           Todo
 29 unused_package                 未使用的包。
 30 missing_package_alias          空的包别名。
 31 unused_optional_argument       可选参数从未被提供。
 32 unused_default_value           可选参数的默认值从未被使用。
 33 text_segment_excceed           文本片段超出行或列限制。
 34 implicit_use_builtin           隐式使用了 `moonbitlang/core/builtin` 中的定义。
 35 reserved_keyword               保留关键字。
 36 loop_label_shadowing           循环标签遮蔽了另一个标签。
 37 unused_loop_label              未使用的循环标签。
 38 missing_invariant              for 循环缺少不变式。
 39 missing_reasoning              for 循环缺少推理说明。
 41 missing_rest_mark              map 模式中缺少 `..`。
 42 invalid_attribute              无效的属性。
 43 unused_attribute               未使用的属性。
 44 invalid_inline_wasm            无效的内联 wasm。
 46 unused_rest_mark               模式中无用的 `..`
 47 invalid_mbti                   无效的 mbti 文件
 48 missing_default_impl_mark      带默认实现的 trait 方法未标记 `= _`
 49 missing_definition             mbti 文件中不存在导致未使用的 pub 定义。
 50 method_shadowing               本地方法遮蔽了上游方法
 51 ambiguous_precedence           运算符优先级含糊不清
 52 unused_loop_variable           循环变量未在循环中更新
 53 unused_trait_bound             未使用的 trait 约束
 55 unannotated_ffi                未标注的 FFI 参数类型
 56 missing_pattern_field          结构体模式中缺少字段
 57 missing_pattern_payload        构造器模式期望负载
 58 unused_non_capturing           正则中不必要的非捕获组
 59 unaligned_byte_access          位模式中未对齐的字节访问
 60 unused_struct_update           未使用的结构体更新
 61 duplicate_test                 重复的测试名称
 62 invalid_cascade                通过 `..` 调用返回非 unit 的方法
 63 syntax_lint                    语法 lint 警告
 64 unannotated_toplevel_array     未标注的顶层数组
 65 prefer_readonly_array          对只读数组字面量建议使用 ReadOnlyArray
 66 prefer_fixed_array             对被修改的数组字面量建议使用 FixedArray
 67 unused_async                   无用的 `async` 标注
 68 declaration_unimplemented      声明尚未实现
 69 declaration_implemented        声明已实现
 70 deprecated_for_in_method       `for .. in` 循环中使用了 `iterator()` 方法
  A                                所有警告

备注

你可以使用 moonc build-package -warn-help 来查看预设编译器警告编号列表。

alert警告#

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

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

例如,在下面的配置中,所有alert警告都被视为错误,除了unsafe类别——只有它被关闭。

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"]
}