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

也能够增加到环境变量中

# emsdkexport PATH=$PATH:$YOUR_DIR/emsdkexport PATH=$PATH:$YOUR_DIR/emsdk/node/14.18.2_64bit/binexport 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.htmlhtml_template.jshtml_template.wasm

html 次要蕴含了 wasm 的援用和实例化。通过 web API 以及 emsdk 通过 js 提供的工具进行运行。

当然也能够只生成 js 文件。

emcc calculate_prime.c -o js_plumbing.js

生成文件

js_plumbing.jsjs_plumbing.wasm

生成的 wasm 文件是二进制文件, 咱们能够通过将 wasm 转化成 wat 来进行浏览。

# https://github.com/webassembly/wabtwasm2wat 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())})