虽然 WebAssembly 还处在发展中阶段,但是已经可以提前玩起来了。把 C++ 编译成 WASM 需要
Emscripten
编译器。
Embind
来绑定 C++ 的函数和类到 JavaScript 对象,写起来更自然,类似 Node.js 的 NAPI。
使用这个特性时必须加上链接器选项
--bind
。
原生代码:
1 2 3 4 5 6 7 8 9 10
|
#include <emscripten/bind.h>
int add(int a, int b) { return a + b; }
EMSCRIPTEN_BINDINGS(my_module) { emscripten::function("add", add); }
|
编译链接生成 js 和 wasm 文件:
1
|
$ em++ -std=c++11 -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1 -O3 --bind -o add.js add.cpp
|
gcc 的参数基本都可以用,这里的
-s
是 Emscripten 额外的选项,
DISABLE_EXCEPTION_CATCHING=0
可以正常 catch 到 C++ 异常,
ALLOW_MEMORY_GROWTH=1
可以让 WebAssembly 内存超出初始化的大小时自动开辟新内存。
文档在
这里
。
JS 调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
<!doctype html> <html> <script>
var Module = { onRuntimeInitialized: function () { console.log(Module.add(1, 2)); } }; </script> <script src="add.js"></script> <script>
</script> </html>
|
默认输出的 JS 也支持 Node.js 运行环境,但是最好不要直接用在 Webpack 里,因为它里面用到了很多 Node.js 变量,Webpack 会自动导入 Node Polyfill 导致生成的包体积超大。
1 2 3 4 5
|
const Module = require('./add.js')
Module.onRuntimeInitialized = function () { console.log(Module.add(1, 2)) }
|
如果需要输出 ES6 模块格式的 JS,需要指定
-o add.mjs
,然后这样用
1 2 3 4 5 6 7 8 9
|
import main from './add.mjs'
const Module = { onRuntimeInitialized () { console.log(Module.add(1, 2)) } }
main(Module)
|
ES6 模块可以用在 Webpack 里,但是要注意
import.meta.url
的处理。
Make for Windows
跑 CMake 生成的 Makefile。
1 2 3 4 5 6
|
> mkdir build > cd build > cmake -DCMAKE_TOOLCHAIN_FILE=<EmscriptenRoot>\cmake\Modules\Platform\Emscripten.cmake -DCMAKE_BUILD_TYPE=<Debug|RelWithDebInfo|Release|MinSizeRel> -G "MinGW Makefiles" -DCMAKE_MAKE_PROGRAM=make .. > cmake --build .
|