前提事項
検証用のOSはUbuntu 20.04
Elixirはインストール済みであること
https://elixir-lang.org/install.html
WasmExを使える環境を作ろう
下記のサイトを見よう
https://github.com/tessi/wasmex
Developmentの項目を見る
a) Rustのインストール
b) Rustの関連ツールイントール
下準備
$ sudo apt install git
$ sudo apt install curl
a) Rustをインストール
下記を実行
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
下記の画面が表示するので1を入力してEnter
Current installation options:
default host triple: x86_64-unknown-linux-gnu
default toolchain: stable (default)
profile: default
modify PATH variable: yes
1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>1
その後ターミナルを再起動
※Rustのツールのパスを有効にするため
ネイティブのUbuntuならCtrl + Alt + t
でターミナルを新規でひらけます
b) Rustの関連ツールイントール
$ rustup component add rustfmt
$ rustup component add clippy
$ rustup target add wasm32-unknown-unknown
$ rustup target add wasm32-wasi
動作確認
git clone 〜 mix test
git clone https://github.com/tessi/wasmex.git
cd wasmex
mix deps.get
mix compile --force
mix rustler_precompiled.download Wasmex.Native --only-local
mix test
iexを起動
$ iex -S mix
README.mdのExampleを参考に動作確認
Erlang/OTP 25 [erts-13.0.4] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]
Compiling 7 files (.ex)
17:48:30.529 [debug] Copying NIF from cache and extracting to /home/user/wasmex/_build/dev/lib/wasmex/priv/native/libwasmex-v0.7.1-nif-2.16-x86_64-unknown-linux-gnu.so
Generated wasmex app
Interactive Elixir (1.13.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {:ok, bytes } = File.read("test/wasm_test/target/wasm32-unknown-unknown/debug/wasmex_test.wasm")
{:ok,
<<0, 97, 115, 109, 1, 0, 0, 0, 1, 118, 19, 96, 2, 127, 127, 0, 96, 3, 127, 127,
127, 1, 127, 96, 2, 127, 127, 1, 127, 96, 3, 127, 127, 127, 0, 96, 1, 127, 1,
127, 96, 0, 1, 127, 96, 1, 126, 1, ...>>}
iex(2)> {:ok, module} = Wasmex.Module.compile(bytes)
{:ok, #Wasmex.Module<#Reference<0.1531479610.3425435661.13361>>}
iex(3)> {:ok, instance } = Wasmex.start_link(%{module: module})
{:ok, #PID<0.346.0>}
iex(4)> {:ok, [42]} == Wasmex.call_function(instance, "sum", [50, -8])
true
iex(5)>
Rustで実験用のWebAssemblyを作ってみよう
$ cargo new hoge_wasm --lib
$ cd hoge_wasm
Cargo.toml
に追加
[package]
name = "hoge_wasm"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+ [lib]
+ crate-type =["cdylib"]
src/lib.rs
を下記に上書き
#[no_mangle]
pub extern "C" fn hoge(a: i32) -> i32 {
a * 777
}
ビルドする
$ cargo build --target=wasm32-unknown-unknown
hoge_wasm.wasm
が生成されていることを確認
$ ls target/wasm32-unknown-unknown/debug/
build deps examples hoge_wasm.d hoge_wasm.wasm incremental
Elixirのプロジェクトを作成
プロジェクト作成
$ mix new hoge
$ cd hoge
mix.exs
を編集
wasmexを追加
defmodule Hoge.MixProject do
use Mix.Project
def project do
[
app: :hoge,
version: "0.1.0",
elixir: "~> 1.13",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
+ {:wasmex, "~> 0.7.1"}
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end
mix deps.getをする
$ mix deps.get
lib/hoge.ex
を編集
defmodule Hoge do
@moduledoc """
Documentation for `Hoge`.
"""
@doc """
Hello world.
## Examples
iex> Hoge.hello()
:world
"""
def hello do
:world
end
+ def test do
+ {:ok, bytes } = File.read("hoge_wasm.wasm")
+ {:ok, module} = Wasmex.Module.compile(bytes)
+ {:ok, instance } = Wasmex.start_link(%{module: module})
+ Wasmex.call_function(instance, "hoge", [10])
+ end
end
hoge_wasm.wasm
をelixirのプロジェクトの直下にコピーしておく
$ cp ../hoge_wasm/target/wasm32-unknown-unknown/debug/hoge_wasm.wasm ./
iex で検証
iex -S mix
iex(1)> Hoge.test()
{:ok, [7770]}
10 * 777 = 7770で正しく動いている事が確認できました
その他のOSで動作確認できたもの
・Windows 10 WSL2(Ubuntu 20.04)
・macOS Monterey 12.3 Mac mini(M1, 2020)
Rustの関数を呼び出している事を検証する
2147483647 + 1をした場合、-214483648になると思いきや…
rustがpanicを起こしました