emscripten
使用 LLVM
編譯器。emscripten 官方文件
環境要求
- python 2.7.12+,3 也可以。
- mime-type 媒體型別,application/wasm,可以通過 http 頭驗證。
安裝
# 下載 emsdk 倉庫
git clone https://github.com/emscripten-core/emsdk.git && cd emsdk
# 下載並安裝 sdk
./emsdk install latest
# 啟用最新 sdk
./emsdk activate latest
# 啟用終端環境變數
source ./emsdk_env.sh
也可以新增到環境變數中
# emsdk
export PATH=$PATH:$YOUR_DIR/emsdk
export PATH=$PATH:$YOUR_DIR/emsdk/node/14.18.2_64bit/bin
export PATH=$PATH:$YOUR_DIR/emsdk/upstream/emscripten
驗證
emsdk list
一個簡單的 wasm 程式
calculate_prime.c
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
#include <stdlib.h>
#include <stdio.h>
int IsPrime(int value) {
int i;
for (i = 2; i < value; i++) {
if (value % i == 0) {
return 0;
}
}
return 1;
}
int main(int argc, char **argv) {
int start = 0;
int end = 100;
printf("prime number between %d and %d\n", start, end);
for (int i = start; i < end; i++) {
if (IsPrime(i)) {
printf("%d is prime\n", i);
}
}
return 0;
}
</div>
</div>
編譯 檢視結果
emcc calculate_prime.c -o html_template.html
形成三個檔案
html_template.html
html_template.js
html_template.wasm
html
主要包含了 wasm
的引用和例項化。通過 web API
以及 emsdk
通過 js
提供的工具進行執行。
當然也可以只生成 js
檔案。
emcc calculate_prime.c -o js_plumbing.js
生成檔案
js_plumbing.js
js_plumbing.wasm
生成的 wasm
檔案是二進位制檔案, 我們可以通過將 wasm
轉化成 wat
來進行閱讀。
# https://github.com/webassembly/wabt
wasm2wat js_plumbing.wasm -o js_plumbing.wat
開啟會看到這樣的程式碼片段。(如何閱讀wasm?)
(module
(type (;0;) (func (param i32 i32 i32) (result i32)))
(type (;1;) (func (param i32) (result i32)))
(type (;2;) (func (result i32)))
(type (;3;) (func (param i32)))
wasm 與 javascript 互動
side_module.c
int Increment(int x) {
return x + 1;
}
編譯
emcc side_module.c -s SIDE_MODULE=2 -O1 -s EXPORTED_FUNCTIONS=\["_Increment"\] -o side_module.wasm
-s SIDE_MODULE=2
: 將程式碼編譯為副模組,並且emcc
不會在生成的模組中包含C
的標準庫- 優化標記
-O1
,預設-O0
。-O0
保留無關函式;-O1
進行了tree sharking
;-O2
壓縮並tree sharking
-s EXPORTED_FUNCTIONS=['_Increment']
指定Increment
為匯出函式,需要前面增加_
,允許多個。*.wasm
字尾代表只生成webAssembly
檔案。
index.js
來載入 wasm
const wasmBinaryFile = 'side_module.wasm'
/**
* WebAssembly.Memory
* 包含記憶體、表、全域性變數、函式引用等
*/
const env = {
'__table_base': 0,
'memory': new WebAssembly.Memory({ initial: 256, maximum: 256 }),
'__memory_base': 1024,
};
WebAssembly.instantiateStreaming(
fetch(wasmBinaryFile),
{env},
).then(result => {
const increment = result.instance.exports.Increment;
console.log('get wasm export function:', increment);
increment && console.log(increment(17).toString())
})