0x00 WebAssembly 基礎
詳情參考《WebAssembly | MDN》
(1)概述
- WebAssembly 簡稱 WASM 或 WA,是一種新的編碼方式,可以在現代的 Web 瀏覽器中執行
- 可以透過編譯器,把多種程式語言(如 C/C++、C#、Go、Python、Rust、TypeScript 等)編寫的程式碼轉化為 WA,並在瀏覽器中使用
- 特點:
- 靈活度高:是一種低階的類組合語言
- 體積較小:具有緊湊的二進位制格式
- 效能提升:接近原生的效能執行
- WA 可以與 JavaScript 共存,允許兩者一起工作
- WA 關鍵概念:
- 模組:表示一個已經被瀏覽器編譯為可執行機器碼的 WA 二進位制程式碼
- 記憶體:一個可變長的
ArrayBuffer
- 表格:一個可變長的型別化陣列
- 例項:一個模組及其在執行時使用的所有狀態(包括記憶體、表格和一系列匯入值)
- 使用 WA 編寫的相關應用:Figma 等
(2)載入與執行
-
通常,編譯器將其他語言的程式碼編譯成 .wasm 檔案,以便在 WA 環境中使用
-
在瀏覽器環境中,可以透過 AJAX 匯入外部檔案,如匯入 .wasm 檔案
fetch("main.wasm");
-
JavaScript 中的
WebAssembly
物件是所有 WA 相關功能的名稱空間,其中WebAssembly.compile
/WebAssembly.instantiate
或WebAssembly.compileStreaming
/WebAssembly.instantiateStreaming
方法組合可以用於載入和執行 WA 程式碼fetch("main.wasm") .then((response) => response.arrayBuffer()) .then((bytes) => WebAssembly.compile(bytes)) .then((module) => { const instance = new WebAssembly.Instance(module); console.log(instance.exports); });
或
WebAssembly.instantiateStreaming(fetch("main.wasm")).then( (results) => { const instance = results.instance; console.log(instance.exports); }, );
(3)相關 JavaScript API
WebAssembly
:所有 WA 相關功能的名稱空間
a. 物件
WebAssembly.Module
:包含已經由瀏覽器編譯的無狀態 WebAssembly 程式碼WebAssembly.Global
:一個全域性變數例項,可以被 JavaScript 和 importable/exportable 訪問WebAssembly.Instance
:有狀態,是WebAssembly.Module
的一個可執行例項WebAssembly.Table
:代表 WA 表格概念的 JavaScript 包裝物件,具有類陣列結構,儲存了多個函式引用WebAssembly.Tag
:定義了一種 WA 異常的型別,該異常可以從 WA 程式碼丟擲或丟擲WebAssembly.Exception
:表示從 WA 丟擲到 JavaScript 的執行時異常,或者從 JavaScript 丟擲到 WA 異常處理程式的執行時異常WebAssembly.LinkError
:表示在模組例項化期間發生錯誤
b. 方法
WebAssembly.Memory()
:用於建立一個新的Memory
記憶體物件WebAssembly.CompileError()
:建立一個新的 WA 編譯錯誤物件WebAssembly.RuntimeError()
:建立一個新的 WA 執行時錯誤物件
0x01 結合 C/C++
-
使用 C 或 C++ 編寫一段程式碼(以 C 為例)
// filename: main.c #include<stdio.h> int main(){ printf("Hello, WebAssembly!"); return 0; }
執行測試無誤後繼續
-
下載並安裝用於編譯 C/C++ 到 WA 的 Emscripten
詳細操作參考官方下載與安裝文件:https://emscripten.org/docs/getting_started/downloads.html
-
使用命令
emcc main.c -s WASM=1 -o main.html
編譯emcc
:Emscripten 提供的工具main.c
:基於 C 語言的程式碼-s WASM=1
:指定輸出 WA-o main.html
:輸出 main.wasm、main.js 和 main.html 檔案,按需使用
0x02 結合 C#
-
使用 C# 編寫一段程式碼
// filename: main.cs public class Example { public static void Main() { System.Console.WriteLine("Hello, WebAssembly!"); } }
-
安裝 .NET Core SDK、mono
-
使用命令
mcs --out:main.dll -t:library main.cs
將 C# 程式碼編譯為 DLL -
使用命令
mono --runtime=mono --aot=llvm main.dll
將 DLL 編譯為 WA
0x03 結合 Go
-
使用 Go 編寫一段程式碼:
// filename: main.go package main import "fmt" func main() { fmt.Println("Hello, WebAssembly!") }
-
使用命令
GOOS=js GOARCH=wasm go build -o main.wasm main.go
透過 GOCC 將 main.go 編譯為 main.wasm
0x04 結合 Python
- 可以透過 py2wasm 工具將 Python 編譯為 WA,或使用 pyodide 直接在 JavaScript 中執行 Python
a. py2wasm
-
使用 Python 編寫一段程式碼:
# filename: main.py if __name__ == '__main__': print("Hello, WebAssembly!")
-
使用命令
pip install py2wasm
安裝 py2wasm 工具 -
使用命令
py2wasm main.py -o main.wasm
將 main.py 編譯為 main.wasm
b. pyodide
在 HTML 頭中匯入 pyodide.js 並編寫 Python 程式碼
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/pyodide/v0.26.0/full/pyodide.js"></script>
</head>
<body>
<script>
async function main() {
let pyodide = await loadPyodide();
await pyodide.loadPackage("numpy"); // 載入一個 Python 庫
let result = await pyodide.runPythonAsync(`
import numpy as np
np.sum([1, 2, 3, 4])
`);
console.log(result);
}
main();
</script>
</body>
</html>
如果在 NodeJS 環境中,可以使用命令 npm install pyodide
匯入
0x05 結合 Rust
參考自《將 Rust 程式碼編譯為 WASM | 部落格園-_zhiqiu》
-
使用命令
cargo add wasm-bindgen
新增依賴項 -
使用命令
rustup target add wasm32-unknown-unknown
安裝目標 -
使用 Rust 編寫一段程式碼:
// filename: main.rs use wasm_bindgen::prelude::*; // 使用 #[wasm_bindgen] 宏來匯出函式到 JavaScript #[wasm_bindgen] pub fn greet(name: &str) -> String { format!("Hello, {}!", name) }
-
使用命令
cargo build --target wasm32-unknown-unknown --release
將 main.rs 編譯為 main.wasm 等檔案 -
使用命令
wasm-bindgen --out-dir ./out --target web target/wasm32-unknown-unknown/release/lib_wasm.wasm
生成 JavaScript 繫結檔案,並設定輸出目錄為 ./out
0x06 結合 TypeScript
- AssemblyScript 簡稱 AS,可以將 TypeScript 的嚴格變體編譯為 WA
- 具體操作方法參考 AS 官方文件
-End-