为了方便从外部调用 MoonBit 生成的 WASM 函数,可否新增下面这样的语法:
pub fn on_complete "on_message_complete" (ptr: Int) -> Int { ... }
输出如下 WAT:
(export "fantix/mmhttp/http1::on_complete" (func $236))
(export "on_message_complete" (func $236))
...
当该模块被作为依赖关系嵌入其他 MoonBit 工程中时,编译生成的结果不会包含 on_complete
的导出,但是会包含 on_message_complete
的导出:
(export "on_message_complete" (func $236))
...
其中参数和返回值类型的限制,同 FFI import 的限制一致:
fn llhttp_resume(ptr: Int) = "llhttp" "llhttp_resume"
使用场景是在用 wasm-merge
来合并两个 wasm 文件,一个是 MoonBit 生成的,另一个是用 C(WASI)写的(llhttp 是一个 HTTP 1.1 协议解析器)。二者之间互有调用,从 mbt 调 C 因为有上述 FFI import 的语法支持就很容易,而从 C 调 mbt 则需额外用 WAT 写一段桥接的代码,如下:
(import "mmhttp" "fantix/mmhttp/http1::on_complete" (func $on_message_complete (param i32) (result i32)))
(func (export "on_message_complete") (param i32) (result i32) (local.get 0) (call $on_message_complete))
(llhttp 导入了 on_message_complete
函数)
更有甚者,如果用户的工程只是把 mmhttp 作为一个依赖关系的话,用户还需要自行编写所有桥接代码,维护十分不易。如果能有像一开始提议的功能,那么即使是在底层依赖中,也可以顺利将函数 export 到外部(不管是 host 系统,还是 wasm-merge 进来的第三方 wasm 模块)。
我自己分析这种语法可能带来的坏处就是,不同依赖关系可能会在同一个项目中,尝试 export 同一个名称。这种情况在早期应该十分罕见(同质化的 FFI 库),报错即可;后期可在 moon.mod.json
中允许用户关闭某个模块的 FFI export。个人意见仅供参考。