c#如何使用WASM跨语言调用?
介绍Wasm(WebAssembly)
WebAssembly(简称Wasm)是一种用于基于堆栈的虚拟机的二进制指令格式。Wasm被设计为编程语言的可移植编译目标,支持在web上部署客户端和服务器应用程序。
什么是wasmtime (WebAssembly Time)?它和WASM(WebAssembly)是什么关系?
wasmtime 是一个独立的、轻量级的 WebAssembly (WASM) 运行时,它支持 WASI (WebAssembly System Interface)。 wasmtime 由 Bytecode Alliance 开发,该联盟致力于创建新的软件基础设施,使得模块化、可组合、安全和高效的软件成为可能。
wasmtime 和 WASM (WebAssembly) 的关系如下:
WebAssembly 运行时: wasmtime 是一个运行时,它允许你在本地环境中执行 WebAssembly 代码,而不需要浏览器。这意味着你可以使用 wasmtime 运行任何编译为 WASM 的代码,无论是从 C、Rust、Go 还是其他语言编译的。
支持 WASI: wasmtime 是 WASI 的一个主要实现,这意味着它可以运行那些使用 WASI 接口的 WebAssembly 程序,从而让这些程序可以访问文件、网络和其他系统资源。
安全性: 与 WebAssembly 一样, wasmtime 也提供了一个沙盒环境,确保 WASM 代码在受限制的环境中运行,从而提供了一定的安全性。
跨平台: wasmtime 可以在多种操作系统和平台上运行,包括 Windows、Linux 和 macOS。
高效: wasmtime 使用了先进的即时编译 (JIT) 技术,确保 WebAssembly 代码能够高效地执行。
总之, wasmtime 是一个与 WebAssembly 紧密相关的运行时,它允许开发者在非浏览器环境中执行 WASM 代码,并提供了对 WASI 的支持,从而扩展了 WebAssembly 的能力和应用范围。
准备工作 环境
请先安装 wasi 在 https://github.com/bytecodealliance/wasmtime/releases 中找到适合的操作系统下载wsmi
安装完成以后在 cmd 中执行即可查看是否安装成功
wasmtime
效果如图。
创建一个控制台项目
创建一个 ConsoleApp2 的控制台项目
添加NuGet包。
< ItemGroup>
< PackageReferenceInclude= "Wasi.Sdk"Version= "0.1.4-preview.10020"/>
</ ItemGroup>
Wasi.Sdk 是用于生成 .wasm 文件的sdk,仓库地址:https://github.com/dotnet/dotnet-wasi-sdk
当我们右键项目的适合点击生成则会在当前项目的 bin/Debug|Release 文件夹下面生成一个 {项目名称}.wasm 的文件,当然还包括了 .dll 文件。
生成 .wasm 文件
选中我们的项目,右键 重新生成 。
然后右键项目,在文件资源管理器中打开文件夹。
依次打开 bin => Release|Debug => net7.0(看选择的SDK)
在当前路径打开 控制台 。然后使用 wasmtim 执行wasm文件。
wasmtime ConsoleApp2.wasm
就这样完成了简单的wasm使用。使用c#编译成wasm的格式,然后执行。
执行 wat 什么是 wat
WAT (WebAssembly Text Format) 是 WebAssembly 的文本表示形式。当我们谈论 WebAssembly (WASM),我们通常指的是其二进制格式,这是一种为浏览器和其他宿主环境设计的低级虚拟机代码。然而,为了方便人类阅读和编写,WASM 也有一个等效的文本格式,即 WAT。
以下是一些关于 WAT 的关键点:
可读性: 虽然 WASM 二进制格式是为机器设计的,但 WAT 格式是为人类设计的。它提供了一种更加可读和可编辑的方式来表示 WebAssembly 代码。
结构: WAT 代码通常包含一系列的指令、函数定义和其他模块级声明。它的语法是 S-expression,这是一种用于表示嵌套结构的简单文本格式。
转换: 你可以使用工具,如 wasm2wat 和 wat2wasm ,来在 WAT 和 WASM 之间进行转换。这意味着你可以手动编写或修改 WAT 代码,然后将其编译为 WASM 二进制格式,或者从现有的 WASM 代码反编译为 WAT 格式。
示例: 下面是一个简单的 WAT 示例,该示例定义了一个函数,该函数接受两个整数参数并返回它们的和:
(module
(func $add (param $a i32) (param $b i32) (result i32)
get_local $a
get_local $b
i32.add)
(export "add" (func $add))
)
总的来说,WAT 是 WebAssembly 的文本表示形式,它为开发者提供了一种更加直观和可读的方式来查看、编写或修改 WebAssembly 代码。
在当前解决方案中在创建一个项目
创建一个 ConsoleApp1 的控制台项目
在项目中添加一下nuget包
< ItemGroup>
< PackageReferenceInclude= "wasmtime"Version= "11.0.1"/>
</ ItemGroup>
官方仓库:https://github.com/bytecodealliance/wasmtime-dotnet
然后新增 test.wat 文件,写入一下代码,以下代码则是 WAT 代码。
(module
(import "" "table" (table $t 4 funcref))
(func (export "call_indirect") (param i32 i32 i32) (result i32)
(call_indirect $t (param i32 i32) (result i32) (local.get 1) (local.get 2) (local.get 0))
)
)
设置 test.wat 文件属性
打开 Program.cs 文件,修改代码
usingWasmtime;
usingvarengine = newEngine;
usingvarmodule = Module.FromTextFile(engine, "test.wat");
usingvarlinker = newLinker(engine);
usingvarstore = newStore(engine);
vartable = newTable(store, TableKind.FuncRef, null, 4);
table.SetElement( 0, Function.FromCallback(store, ( inta, intb) => a + b));
table.SetElement( 1, Function.FromCallback(store, ( inta, intb) => a - b));
table.SetElement( 2, Function.FromCallback(store, ( inta, intb) => a * b));
table.SetElement( 3, Function.FromCallback(store, ( inta, intb) => a / b));
linker.Define( "", "table", table);
varinstance = linker.Instantiate(store, module);
varcall_indirect = instance.GetFunction< int, int, int, int>( "call_indirect");
if(call_indirect isnull)
{
Console.WriteLine( "error: `call_indirect` export is missing");
return;
}
Console.WriteLine( $"100 + 25 = {call_indirect( 0, 100, 25)} " );
Console.WriteLine( $"100 - 25 = {call_indirect( 1, 100, 25)} " );
Console.WriteLine( $"100 * 25 = {call_indirect( 2, 100, 25)} " );
Console.WriteLine( $"100 / 25 = {call_indirect( 3, 100, 25)} " );
这里提供了一个使用c#调用 test.wat 的案例。
执行项目
如何执行其他语言的wasm?
Rust 编译 WebAssembly 指南 - 知乎 (zhihu.com)
可以参考这个博客,使用将rust编译成wasm,然后在编译成wat格式。
感动 | 同情 | 无聊 | 愤怒 | 搞笑 | 难过 | 高兴 | 路过 |
- 上一篇:用Rust开发wasm组件实战
- 下一篇:kaspa节点调用问题
相关文章
-
没有相关内容