包配置#
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? "}"
名称#
包名称不可配置;它由包的文件夹目录名称确定。
格式化#
formatter 字段用于为此包配置 moon fmt。目前它支持 ignore,即格式化器应跳过的文件名列表。
这对于生成文件或你有意保持为不同格式的文件很有用。由 pre-build 生成的文件已经会被自动跳过,因此 formatter.ignore 主要用于额外排除你想忽略的文件。
options(
formatter: {
ignore: [ "generated.mbt", "snapshot.mbt" ],
},
)
{
"formatter": {
"ignore": ["generated.mbt", "snapshot.mbt"]
}
}
is-main#
is-main 字段用于指定包是否需要链接为一个可执行文件。
链接过程的输出取决于后端。当此字段设置为 true 时:
对于 Wasm 和
wasm-gc后端,将生成一个独立的 WebAssembly 模块。对于
js后端,将生成一个独立的 JavaScript 文件。
options(
"is-main": true,
)
{
"is-main": true
}
导入依赖#
导入#
import 字段用于指定包依赖的其他包。
例如,以下导入 pkgA 和 pkgC,将 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
}
条件编译#
条件编译的最小单元是一个文件。
在条件编译表达式中,支持三种逻辑运算符:and、or 和 not,其中 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 选项用于声明一个包打算支持哪些后端。它使用的是目标集合表达式,而不是数组:
options(
"supported-targets": "js",
)
{
"supported-targets": "js"
}
示例:
js表示单个后端+js+wasm-gc表示显式指定一组后端+all-js表示除js之外的所有后端
为了兼容,旧的数组语法仍然可以使用:
{
"supported-targets": ["js", "native"]
}
这是包级元数据,不是条件编译规则:
使用
supported-targets声明该包支持的后端集合使用
targets为不同后端包含或排除单独的文件在
moon.mod.json中使用preferred-target为moon check、moon run、moon build等命令选择默认后端
当模块和包都声明了 supported-targets 时,实际生效的后端集合就是它们的交集。
命令行为取决于所选择的后端:
moon check、moon build、moon test和moon bench只保留支持所选后端的包moon run要求被选中的包支持所选后端moon info会跳过不支持的选中包,并给出警告moon bundle会跳过不支持所选后端的包目标
在根包选择完成后,Moon 还会检查可达的必需依赖。如果某个必需依赖不支持所选后端,命令会以正常的面向用户的错误信息失败。
注意:
省略
supported-targets表示支持所有后端--target all会展开为wasm、wasm-gc、js和native,但不包括llvmllvm仍然是合法的supported-targets值旧的数组语法已被弃用,但为了兼容仍然接受
一种常见的配置方式是:
把仅支持 native 的包标记为
"supported-targets": "native"在
moon.mod.json中设置"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"]
}
链接选项#
默认情况下,moon 仅链接 is-main 设置为 true 的包。如果需要链接其他包,可以使用 link 选项指定。
link 选项用于指定链接选项,其值可以是布尔值或对象。
目前,link 对 native 后端不起作用。本节描述的行为适用于 wasm、wasm-gc 和 js 后端。
当
link值为true时,表示应链接包。输出将根据构建时指定的后端而有所不同。options( link: true )
{ "link": true }
当
link值为对象时,表示应链接包,您可以指定链接选项。有关详细配置,请参阅相应后端的子页面。
Wasm 后端链接选项#
共有选项#
exports选项用于指定 Wasm 后端导出的函数名称。例如,在以下配置中,当前包中的
hello函数被导出为wasm模块中的hello函数,foo函数被导出为 Wasm 模块中的bar函数。在 Wasm 宿主中,可以调用hello和bar函数来调用当前包中的hello和foo函数。options( link: { "wasm": { "exports": [ "hello", "foo:bar" ], }, "wasm-gc": { "exports": [ "hello", "foo:bar" ], } } )
{ "link": { "wasm": { "exports": [ "hello", "foo:bar" ] }, "wasm-gc": { "exports": [ "hello", "foo:bar" ] } } }
import-memory选项用于指定 Wasm 模块导入的线性内存。例如,以下配置指定 Wasm 模块导入的线性内存是
env模块的memory变量。options( link: { "wasm": { "import-memory": { "module": "env", "name": "memory", }, }, "wasm-gc": { "import-memory": { "module": "env", "name": "memory", }, }, }, )
{ "link": { "wasm": { "import-memory": { "module": "env", "name": "memory" } }, "wasm-gc": { "import-memory": { "module": "env", "name": "memory" } } } }
memory-limits选项用于指定 Wasm 模块所使用线性内存的最小和最大大小。shared-memory选项用于启用共享线性内存。例如,以下配置为
wasm和wasm-gc后端同时设置了内存限制并启用了共享内存。options( link: { "wasm": { "memory-limits": { "min": 1, "max": 65536, }, "shared-memory": true, }, "wasm-gc": { "memory-limits": { "min": 1, "max": 65535, }, "shared-memory": true, }, }, )
{ "link": { "wasm": { "memory-limits": { "min": 1, "max": 65536 }, "shared-memory": true }, "wasm-gc": { "memory-limits": { "min": 1, "max": 65535 }, "shared-memory": true } } }
export-memory-name选项用于指定 Wasm 模块导出的线性内存的名称。options( link: { "wasm": { "export-memory-name": "memory", }, "wasm-gc": { "export-memory-name": "memory", }, }, )
{ "link": { "wasm": { "export-memory-name": "memory" }, "wasm-gc": { "export-memory-name": "memory" } } }
Wasm 线性内存后端链接选项#
heap-start-address选项用于指定编译到 Wasm 后端时可以使用的线性内存的起始地址。例如,以下配置将线性内存的起始地址设置为 1024。
options( link: { "wasm": { "heap-start-address": 1024, }, }, )
{ "link": { "wasm": { "heap-start-address": 1024 } } }
Wasm GC 后端链接选项#
use-js-builtin-string选项用于指定在编译到 Wasm GC 后端时是否应启用 内建 JS String 提案。它将使 MoonBit 中的String等效于 JavaScript 宿主运行时中的String。例如,以下配置将启用内建 JS String 提案。
options( link: { "wasm-gc": { "use-js-builtin-string": true, }, }, )
{ "link": { "wasm-gc": { "use-js-builtin-string": true } } }
imported-string-constants选项用于指定内建 JS String 提案使用的导入字符串命名空间,默认为_。它应符合 JS 宿主运行时中的配置。例如,以下配置与 JS 初始化配置了导入字符串命名空间。
options( link: { "wasm-gc": { "use-js-builtin-string": true, "imported-string-constants": "_", }, }, )
{ "link": { "wasm-gc": { "use-js-builtin-string": true, "imported-string-constants": "_" } } }
const { instance } = await WebAssembly.instantiate(bytes, {}, { importedStringConstants: "strings" });
JS 后端链接选项#
exports选项用于指定要在 JavaScript 模块中导出的函数名称。例如,在以下配置中,当前包中的
hello函数被导出为 JavaScript 模块中的hello函数。在 JavaScript 宿主中,可以调用hello函数来调用当前包中的hello函数。options( link: { "js": { "exports": [ "hello" ], }, }, )
{ "link": { "js": { "exports": [ "hello" ] } } }
format选项用于指定 JavaScript 模块的输出格式。目前支持的格式有:
esm(默认)cjsiife
例如,以下配置将当前包的输出格式设置为 ES 模块。
options( link: { "js": { "format": "esm", }, }, )
{ "link": { "js": { "format": "esm" } } }
原生后端链接选项#
cc选项用于指定用于编译moonc生成的 C 源文件的编译器。它可以是编译器的完整路径,也可以是通过 PATH 环境变量可访问的简单名称。options( link: { "native": { "cc": "/usr/bin/gcc13", }, }, )
{ "link": { "native": { "cc": "/usr/bin/gcc13" } } }
cc-flags选项用于覆盖传递给编译器的默认标志。例如,您可以使用以下标志来定义一个名为 MOONBIT 的宏。options( link: { "native": { "cc-flags": "-DMOONBIT", }, }, )
{ "link": { "native": { "cc-flags": "-DMOONBIT" } } }
cc-link-flags选项用于覆盖传递给链接器的默认标志。由于链接器是通过编译器驱动程序调用的(例如,通过cc而不是ld,通过cl而不是link),因此在传递特定选项时,应该使用-Wl,或/link前缀。以下示例从生成的二进制文件中剥离符号信息。
options( link: { "native": { "cc-link-flags": "-s", }, }, )
{ "link": { "native": { "cc-link-flags": "-s" } } }
stub-cc选项与cc类似,但控制用于编译存根的编译器。虽然它可以与cc不同,但不建议这样做,应仅用于调试目的。因此,我们强烈建议同时指定cc和stub-cc并使它们保持一致,以避免潜在冲突。stub-cc-flags选项类似于cc-flags。它仅对存根编译有效。stub-cc-link-flags与cc-link-flags类似,但有微妙的区别。通常,存根被编译为目标文件,并与从moonc生成的 C 源文件的目标文件链接。这种链接仅由前面提到的cc-flags和cc-link-flags控制。然而,在特定模式下,存根目标文件将有一个单独的链接过程,在该过程中,stub-cc-link-flags将生效。
原生后端的默认 C 编译器和编译器标志#
以下是对 compiler_flags.rs 的简要总结。
C 编译器#
在 PATH 中从上到下搜索以下项目。
cl
gcc
clang
cc
内部的 tcc
对于类似 GCC 的编译器,默认的编译和链接命令如下。[] 用于指示某些模式下可能不存在的标志。
cc -o $target -I$MOON_HOME/include -L$MOON_HOME/lib [-g] [-shared -fPIC] \
-fwrapv -fno-strict-aliasing (-O2|-Og) [$MOON_HOME/lib/libmoonbitrun.o] \
$sources -lm $cc_flags $cc_link_flags
对于 MSVC,默认的编译和链接命令如下。
cl (/Fo|/Fe)$target -I$MOON_HOME/include [/LD] /utf-8 /wd4819 /nologo (/O2|/Od) \
/link /LIBPATH:$MOON_HOME/lib
预构建#
pre-build 字段用于指定预构建命令,这些命令将在构建命令(如 moon check|build|test)之前执行。
"pre-build" 是一个数组,其中每个元素是一个包含 input、output 和 command 字段的对象。input 和 output 字段可以是字符串或字符串数组,而 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
#|
警告列表#
用于关闭警告,启用警告,或者把一个启用的警告视为错误。警告列表是由多个警告名组成的字符串,每个警告名前有一个符号前缀:
-用于关闭警告+用于启用警告@用于把一个已经启用的警告视为错误
例如,在以下配置中,-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"
}
You can also use warning numbers in warn-list. In the output below, mnemonic
is the symbolic warning name used in warning lists, while id is the numeric
form of the same warning.
The current list from moonc check -warn-help is:
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
loop_label_shadowing Loop label shadows another label. 36 warn
unused_loop_label Unused loop 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
invalid_mbti Invalid mbti file 47 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
A all warnings
state: warn = enabled, error = promoted to error, off = disabled
note: default alert exceptions: alert_unsafe=off
备注
Use moonc check -warn-help to see the list of preset compiler warnings.
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"]
}