不在瀏覽器上執行 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