不在瀏覽器上執行 wasm
wasm runtime -nodejs 不在瀏覽器上的 javascript 執行環境。
那想不在瀏覽器上的執行 WebAssembly 要怎麼辦?
Why
What
- Wasmtime
 - 
Wasmtime 一個 Bytecode Alliance 項目,用
Rust寫的 wasm runtime。 - WAMR
 - 
WebAssembly Micro Runtime 另一套 Bytecode Alliance 項目,但用
C寫的 wasm runtime。 - Wasm3
 - 
Wasm3 用
C寫的 wasm runtime。 - WasmEdge
 - 
WasmEdge 用
C++寫的 wasm runtime。 - Wasmer
 - 
Wasmer 用
Rust寫的 wasm runtime。 
project  | 
Wasmtime  | 
WAMR  | 
Wasm3  | 
WasmEdge  | 
Wasmer  | 
lang  | 
Rust  | 
C  | 
C  | 
C++  | 
Rust  | 
org  | 
BA  | 
BA  | 
CNCF  | 
||
JIT  | 
V  | 
V  | 
V  | 
||
AOT  | 
V  | 
V  | 
V  | 
||
WASI  | 
V  | 
V  | 
V  | 
V  | 
V  | 
size  | 
~19M  | 
~300K  | 
~180K  | 
~1.4M  | 
~58M  | 
version  | 
v0.38.1  | 
fast-jit-06-29-2022  | 
v0.5.0  | 
v0.10.0  | 
v2.3.0  | 
C 寫的就是小,Rust 就是大。
很計較空間的地方就建議用 Wasm3,夠小夠大,提供的 APE 格式可以跨多種平台執行而不需要重新編譯。
How
wasm 的本體是二進位的。想看得懂,要將他轉成文字格式的 wat。
而一個計算乘階的函式,大概是長下面這樣子的。
(func (param i64) (result i64)
  local.get 0
  i64.eqz
  if (result i64)
      i64.const 1
  else
      local.get 0
      local.get 0
      i64.const 1
      i64.sub
      call 0
      i64.mul
  end)
下面是等效的 C 程式碼。
int factorial(int n) {
  if (n == 0)
    return 1;
  else
    return n * factorial(n-1);
}
這是像S表達式的低階程式語言。用它來寫程式當然不太現實。
用甚麼語言來寫?
因為某種不可告人的原因, rust 和 wasm 目前是好姊妹。
所以先裝 link:/install-rust/ [rust]。
rust 的編譯工具 rustc 不只能將 rust 程式碼編譯為執行檔,也能編成 wasm。
檢查一下目前可以使用編譯目標。
> rustup target list | grep wasm
// wasm32-unknown-emscripten
// wasm32-unknown-unknown
// wasm32-wasi
要編成可獨立運作的故選擇將 wasm32-wasi 加入編譯清單。
> rustup target add wasm32-wasi
先用產生器產生一個 hello world 程式。
> cargo init hello
> cd hello
> cargo run
// Hello, world!
現在我們有一個用 rust 寫的簡單 hello world 程式。
使用 rust 交叉編譯的功能,將他編譯為 wasm。
> cargo build --target wasm32-wasi
在路徑 target/wasm32-wasi/debug/ 中應該能找到 hello.wasm。
最後,可以用上述的各種 wasm runtime 來執行。
Wasmtime
// install
> curl https://wasmtime.dev/install.sh -sSf | bash
// load env
> . ~/.bashrc
// run
> wasmtime target/wasm32-wasi/debug/hello.wasm
WAMR
> git clone  https://github.com/bytecodealliance/wasm-micro-runtime.git
> cd wasm-micro-runtime/product-mini/platforms/linux // (1)
> mkdir build
> sudo apt install -y build-essential cmake g++-multilib libgcc-8-dev lib32gcc-8-dev
> cd build
> cmake ..
> make
// copy iwasm to PATH
> iwasm target/wasm32-wasi/debug/hello.wasm
- 
切換到符合你 OS 的目錄
 
Wasm3
> wget https://github.com/wasm3/wasm3/releases/download/v0.5.0/wasm3-cosmopolitan.com
> mv wasm3-cosmopolitan.com wasm3
> sudo chmod 755 wasm3
> wasm3 target/wasm32-wasi/debug/hello.wasm
WasmEdge
> curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash
> . ~/.wasmedge/env
> wasmedge target/wasm32-wasi/debug/hello.wasm
Wasmer
> curl https://get.wasmer.io -sSfL | sh
// or
> cargo install wasmer-cli
> . ~/.wasmer/wasmer.sh
>  wasmer target/wasm32-wasi/debug/hello.wasm
Shrink Size
rustc 產生的 wasm 有些太大了。可以在正式編譯時加入下面的設定,可以大幅減小最後釋出版本的大小。
利用編譯指示
[profile.release]
lto = true  // (1)
opt-level = 's' // (2)
- 
指示 LLVM 啟用 link-time-optimizations (連結時間優化)
 - 
以 (s)ize 作為優化標準,也可以用
z,但兩者的結果不一定誰比較小,要試試看。 
利用 wasm-opt 工具也能再進一步降低大小
下面指令,主要作用是刪掉 wsam 中的 debuginfo 和 names 區段。
> wasm-opt -Os -o output.wasm input.wasm
覺得手動下指令麻煩,可以安裝 cargo-wasi 來幫忙。
[package.metadata]
wasm-opt = true
wasm-name-section = false
wasm-producers-section = false
> cargo install cargo-wasi
> cargo wasi build