Hello, WebAssembly

82 阅读2分钟

按照 MDN 给的教程跑一个 Hello World。

安装环境

安装 CMake:

sudo apt-get install cmake
cmake --version

CMake 可看作 C++ 项目的构建工具。

安装 GCC:

sudo apt-get install gcc
sudo apt-get install g++

也可以按照 VS Code 官网给的教程配置 C++ 开发环境。

安装 Emscripten SDK:

git clone https://github.com/juj/emsdk.git
cd emsdk

./emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
./emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit

# 如果报错 Error: No tool or SDK found by name 'sdk-incoming-64bit',就执行下面两行
./emsdk install latest
./emsdk activate latest

# 按照提示执行相应命令以配置环境变量

使用 Emscripten 时,可以先拉取 Emscripten 最新代码。如果有更新,需要重新执行 install、activate。

Hello World

hello.cpp 内容如下:

#include <iostream>

using namespace std;

int main() {
  cout << "Hello World!" << endl;
  cout << "It's a WebAssembly demo." << endl;
}

如果终端重启,需要先切到 emsdk 目录下,执行:

source ./emsdk_env.sh

然后再切回 hello.cpp 所在目录,执行:

emcc hello.cpp -sWASM=1 -o hello.html
  • -sWASM=1 输出 Wasm。
  • -o
    • -o hello.html 在当前目录下生成 HTML、JS、Wasm;
    • -o hello.js 生成 JS、Wasm;
    • -o hello.mjs 生成 ES6 模块和 Wasm 文件。
  • MJS 文件导出一个函数,它接受的是 Wasm 模块初始化参数(HTML 模板中有初始化参数相关示例),并以 Promise 的形式将初始化完成后的模块 Module resolve 出来,Module 上绑定了 JS 中可以调用的所有 API。

成功运行后可以在控制台看到:

hello_world.png

从 Wasm 导出函数

fibonacci.cpp 内容如下:

#include <emscripten/emscripten.h>

// 避免 C++ name mangling
#ifdef __cplusplus
extern "C" {
#endif

// EMSCRIPTEN_KEEPALIVE 避免无用代码删除(dead code elimination)
int EMSCRIPTEN_KEEPALIVE fibonacci(int n) {
  if (n <= 1) return 1;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

#ifdef __cplusplus
}
#endif

编译 Wasm 和 JS:

emcc fibonacci.cpp -O3 -sWASM=1 -sEXPORTED_RUNTIME_METHODS=cwrap -o fibonacci.mjs
  • -O3:指定优化等级。
  • -sEXPORTED_RUNTIME_METHODS=cwrap:在 Module 上暴露 cwrap
  1. EXTRA_EXPORTED_RUNTIME_METHODS 已废弃。
  2. 对于 fibonacci,如果不开 -O3 优化,可能还没 JS 快;有些计算,比如前 n 个数的立方和,开了 -O3,可能也还没 JS 快;具体原因还没搞清楚。

在 JS 中使用 cwrap 包装后即可使用:

const fibonacci = Module.cwrap("fibonacci", "number", ["number"]);
console.log(fibonacci(38));