UbuntuでWasmExを動かそう

## 前提事項
検証用のOSはUbuntu 20.04
Elixirはインストール済みであること
https://elixir-lang.org/install.html

## WasmExを使える環境を作ろう

下記のサイトを見よう
https://github.com/tessi/wasmex
Developmentの項目を見る
　a) Rustのインストール
　b) Rustの関連ツールイントール

![e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/a757da4b-82cd-eb99-b5b7-68a92f9ec0ea.png)

## 下準備
```
$ sudo apt install git
$ sudo apt install curl
```

## a) Rustをインストール
https://www.rust-lang.org/tools/install

下記を実行
```
$ 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を参考に動作確認

```Elixir
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``に追加
```diff_yaml 
[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`` を下記に上書き
```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を追加

```diff_elixir
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`を編集
```diff_elixir
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の関数を呼び出している事を検証する
![aaa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/adc51f47-672a-cb91-25dc-ca1559ecb17f.png)
2147483647　+ 0 はOK

2147483647 + 1をした場合、-214483648になると思いきや…
rustがpanicを起こしました