最近在做 WebAssembly 相关的事情,边做边总结吧
Glossary
- WebAssembly: WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.
 - emscripten: Emscripten is an Open Source LLVM to JavaScript compiler.
 - emsdk: The Emscripten SDK (emsdk) is used to perform all SDK maintenance and can install, update, add, remove and activate SDKs and tools.
 - emcc: The Emscripten Compiler Frontend (emcc). Emscripten’s drop-in replacement for a compiler like 
gcc. 
我做的事情是希望在Web环境中用到C++的一个库,所以套用上面的术语,就是我会用利用emsdk提供的环境,使用emcc将C++编译成WebAssembly格式, 然后在Web环境中使用.
image source: https://kripken.github.io/emscripten-site/docs/introducing_emscripten/about_emscripten.html
Browser compatibility
实践中我们比较关心的关于Thread的兼容性:
| Tables | Available version | Conditions | 
|---|---|---|
| Google chrome | Chrome 70 | Turn on experimental “WebAssembly threads support” flag | 
| Mozilla firefox | Firefox nightly channel | Turn on “javascript.options.shared_memory” flag | 
Emscripten has support for multithreading using the new SharedArrayBuffer capability in browsers. Note that SharedArrayBuffer was disabled by default in all major browsers on 5 January, 2018 in response to Spectre. Chrome re-enabled it in v67 on platforms where its site-isolation feature is enabled to protect against Spectre-style vulnerabilities.
Setup
1  | # Get the emsdk repo  | 
Sample JavaScript-C++ interoperability code
hello.cc
#include <pthread.h> #include <iostream> extern "C" { extern int js_func(); void* test(void*) { std::cout << "Background thread" << std::endl; std::cout << js_func() << std::endl; return NULL; } void cpp_func() { pthread_t t; pthread_create(&t, NULL, &test, NULL); std::cout << "Main thread" << std::endl; } }hello.js
Module.onRuntimeInitialized = () => { const cpp_func = Module.cwrap('cpp_func', null); cpp_func(); };hello.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <script src="wasm.js"></script> <script src="hello.js"></script> </body> </html>export.js
mergeInto(LibraryManager.library, { js_func: function () { return 10; }, });Build
emcc hello.cc -o wasm.js -s EXPORTED_FUNCTIONS='["_cpp_func"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' --js-library export.js -std=c++14 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2 -g4Build完之后会生成
wasm.js和wasm.wasm,其中wasm.js已经在hello.html中被引用,wasm.wasm会在wasm.js中被fetch,compileandinstantiate直接打开
hello.html看到输出
坑
目前踩到的一些比较棘手的坑(嗯小坑不断)
- Calling derived JavaScript object inside another thread causes binding error
- 这个是我遇到的一个比较严重的问题,简单来说就是在
embind和webidl的环境下,JavaScript能够实现C++中定义的interface,但却无法在C++的multi-thread环境中被调用 - 错误信息是JavaScript的Web workder环境无法识别
Module中JavaScript中实现的Object - debug过程中发现,multi-thread环境下生成的
pthread-main.js(worker)中,Module并不包含JavaScript实现的Object,具体的重现过程可以参考我在上面链接中的提出的issue - 绕过这个坑的方法:目前使用纯C的接口可以绕过这个,当然不可避免的损失了C++ class的一些便利性
 
 - 这个是我遇到的一个比较严重的问题,简单来说就是在
 - embind not maintained?
 
Reference
- Glossary
 - Emscripten issues
 - WebIDL
 - Embind
 - Test suite:
 - WebAssembly + Web worker
 - WebWorker
 - Big projects: