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を呼び出すコードを書く。