Learning WASM #3

Rustでライブラリを作成して、dotnetからそれを呼び出すのを試した。

https://github.com/iwate/learn-wasm-with-dotnet/tree/main/challenge02


まずは、簡単なとこから、ただの2値の足し算をする`add関数をrust -> wasm -> dotnetで実行する


rust + wasm で検索したら、wasm-packばっかりで、なかなかただのwasmの生成方法がわからなかったけど、wasiとかwasmtimeでググったら何とか知見が得られた。


まずは、rustでwasmをターゲットにしてコンパイルできるように、ターゲットを足す。


rustup target add wasm32-unknown-unknown


次に、普通にrustのプロジェクトを作る。add関数を外から使いたいからプロジェクトタイプはlibで。


Cargo.tomlはこんな感じでまっさらでいい。


[package]
name = "challenge02"
version = "0.1.0"
authors = ["iwate <github@iwate.me>"]
edition = "2018"

[dependencies]


wasmにするために唯一やらなくちゃいけないことは`#[no_mangle]`をつけるってこと。こういうのrustだとなんていうんだろ?dotnet的にattributeって言うのかな?それともjavaみたいにannotation?


#[no_mangle]
fn add(a: i32, b: i32) -> i32 {
    return a + b;
}

調べた。 attributeらしい。`#`がouter attributeで`#!`がinnter attributeだって。

https://doc.rust-lang.org/book/appendix-02-operators.html



あとは、ビルドするときにターゲットを指定する。 releaseビルドにしないと、wasmがデバッグ用のコードか何かですごく膨らむ。


cargo build --target=wasm32-unknown-unknown --release


あとは生成されたwasmをdotnetから使うだけ。


using System;
using Wasmtime;

using var engine = new Engine();
using var module = Module.FromFile(engine, "challenge02.wasm");
using var host = new Host(engine);

using dynamic instance = host.Instantiate(module);
var result = instance.add(1, 2);

Console.WriteLine(result);


コンパイルが面倒なので、ビルドイベントでrustのビルドとwasmのコピーもしちゃう。


<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net5.0</TargetFramework>
		<Nullable>enable</Nullable>
	</PropertyGroup>

	<ItemGroup>
		<PackageReference Include="Wasmtime" Version="0.27.0-preview1" />
	</ItemGroup>

	<ItemGroup>
	  <None Update="challenge02.wasm">
	    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
	  </None>
	</ItemGroup>

	<Target Name="RustBuild" BeforeTargets="Build">
		<Exec WorkingDirectory="../rust" Command="cargo build --target=wasm32-unknown-unknown --release" />
		<Copy SourceFiles="../rust/target/wasm32-unknown-unknown/release/challenge02.wasm" DestinationFiles="./challenge02.wasm" />
	</Target>

</Project>


基本はできたので、次はwasm + protocol bufferを返してdotnetからrustを呼び出すコードを書く。