• c# wasi.sdk 定义 import 函数
  • 发布于 1个月前
  • 72 热度
    0 评论
前言
在 wasm 中存在两个关键字:export 和 import,它们用于在模块间进行导入和导出,以实现模块间的交互。顾名思义,export 用于导出 wasm 模块中的函数以便于在其他模块或宿主环境中使用,import 则用于在 wasm 使用来着其他模块或者是宿主环境中的函数。

在之前,我记录了如何自定义导出函数,实际上编译为 wasm 后就是一个 export 函数。我们可以使用 wabt 这个项目中的 wasm2wat 命令将 wasm 文件转为文本文件:
wasm2wat.exe ./WasmLib.wasm -o WasmLib.wat
然后用记事本打开 wat 文件,可以在最后找到 export 的定义:

环境
.Wasi.Sdk Preview
import 宿主环境函数
声明导入函数
在 wasm 模块 WasmLib 中声明了一个 HelloFromEnv 函数,通过 extern 关键字表明改函数是一个外部函数,_MethodImpl_ 表示该函数的实现方式是在 CLR 中。
public class WasmImport
{
    [MethodImpl(MethodImplOptions.InternalCall)]
    public static extern void HelloFromEnv();
}
当然,记得在 main 中使用 import 的函数:
WasmImport.HelloFromEnv();

声明 c 语言存根
首先在 c 语言中声明一个来着外部实现的函数 __wasm_import_env_hello,该函数存在于外部的 env 模块中,对应的函数名为 _hello_from_env_,并使用 mono_add_internal_call 函数将 __wasm_import_env_hello 注册为 WasmLib.WasmImport::HelloFromEnv 的外部实现。
__attribute__((__import_module__("env"), __import_name__("hello_from_env")))
extern void __wasm_import_env_hello();
// 堆代码 duidaima.com
void attach_internal_calls() {
    mono_add_internal_call("WasmLib.WasmImport::HelloFromEnv", __wasm_import_env_hello);
}
需要注意的是,此时需要再 csproj 文件中添加一行配置,使得注册函数能够自动执行。
<ItemGroup>
 <WasiAfterRuntimeLoaded Include="attach_internal_calls" />
</ItemGroup>
宿主环境定义函数
现在,我们在 wasm 宿主环境中使用 main 函数之前,必须要先定义一个 hello_from_env 函数:
linker.DefineFunction("env", "hello_from_env", () =>
{
    Console.WriteLine("Hello from the Dotnet Host!");
});

var instance = linker.Instantiate(Store, Module);
var mainFunc = Instance.GetFunction("_start")!;
mainFunc.Invoke();
如果在 WasmLib 的 Main 函数使用了 WasmImport.HelloFromEnv,则运行 wasm 宿主,则可以观察到相关输出:

import 其他模块函数
在其他模块 export 一个函数
使用 go 语言导出一个 add 函数。这里使用 tinygo 进行编译,而在 tinygo 中,wasm 函数的导出,是通过 //export <函数名> 这种注释来声明的。
package main

//export add
func add(x, y int32) int32 {
  return x + y
}

// 对于 wasi 编译,main 函数无论是否使用,都必须要有
func main() {}
接下来,通过 tinygo 进行编译即可:
tinygo build -o go-wasm-module.wasm -target=wasi -no-debug main.go

声明导入函数和存根
这里和之前 import 宿主环境函数 相同:
public class WasmImport
{
 [MethodImpl(MethodImplOptions.InternalCall)]
 public static extern int GoWasmAdd(int x, int y);
}

__attribute__((__import_module__("go-wasm-module"), __import_name__("add")))
extern int __wasm_import_go_add(int x, int y);

void attach_internal_calls() {
    mono_add_internal_call("WasmLib.WasmImport::GoWasmAdd", __wasm_import_go_add);
}
当然,import 后还要记得在 main 中使用:
int res = WasmImport.GoWasmAdd(10,1);
Console.WriteLine($"GoWasmAdd 10+1={res}");
加载其他模块
var goWasmFile = "../../../../wasm-module/go-wasm-module/go-wasm-module.wasm";
using var goWasmModule = Module.FromFile(engine, goWasmFile);
linker.DefineModule(store, goWasmModule);
OK,现在运行程序,就能在控制台看到 add 函数的输出了。
用户评论