WebAssembly实践细节
编译成WebAssembly需要使用Emscripten作为编译器,官方网站为emscripten.org
推荐实践路线
- application: 推荐手动建立工程,给出sdk文件位置
- sdk: 使用cmake生成,编译完成后拷贝至application应用文件夹
- c++: 使用cmake管理,并通过sdk层引用
下载emsdk
官方文档Emscripten Toolchain Requirements指出Emscripten依赖的库包括
- Node.js、Python、Java、Git client、LLVM、Binaryen
你可以手动安装这些库,但是更加推荐的用法是根据官方文档Download and install直接下载SDK,其内部包含完整的工具链。
emsdk使用CMake
如果想让CMake使用emcc命令作为Compiler和LinkTool, 需要使用官方提供的工具链文件Emscripten.cmake
1 | # To use this toolchain file with CMake, invoke CMake with the following command line parameters |
根据官方文档提示,只需要在cmake generate的过程中指定CMAKE_TOOLCHAIN_FILE即可
映射C++方法的方式
映射C++的方式分为两种 Embind 和 WebIDL Binder,参考博客使用WebAssembly编译C++到JS更加推荐 Embind的方式因为其丰富的数据结构映射
C++ type | JavaScript type |
---|---|
void | undefined |
bool | true or false |
char | Number |
signed char | Number |
unsigned char | Number |
short | Number |
unsigned short | Number |
int | Number |
unsigned int | Number |
long | Number |
unsigned long | Number |
float | Number |
double | Number |
std::string | ArrayBuffer, Uint8Array, Uint8ClampedArray, Int8Array, or String |
std::wstring | String (UTF-16 code units) |
emscripten::val | anything |
其中最重要的是 emscripten::val 可以映射任何东西
自然也包括了std::function,可以将C++的lambda转化为js的callback, 详见StackOverflow的回答
编译同步版本
根据官方文档Building to WebAssembly的章节 .wasm files and compilation 提出
- WebAssembly默认编译结果是异步加载
- 可以在onRuntimeInitialized中确定何时加载完毕
- 加载完毕后才能访问C++代码
1 |
|
如果想要同步加载C++ Port的结果,可以选择在编译时设置 WASM_ASYNC_COMPILATION=0
需要注意的是这个参数并没有在编译配置的源代码中出现,应该是文档不够严谨导致的
常见的错误
- CMake中 target_compile_options 和 COMPILE_FLAGS 无效
在编译WebAssembly的过程中使用 –bind 参数无法通过以下两个CMake指令传入
- target_compile_options
- set_target_properties(<target> PROPERTIES COMPILE_FLAGS “–bind”)
而只能使用对应Link属性,可以通过 cmake –build path –verbose 查看调用的指令区别
具体原因不详,猜测和Emscripten的Compiler与Link为同一个指令相关
- Electron报错unsafe-eval
因为Electron内部的Content-Security-Policy的安全策略问题,使用WASM可能会报错
1 | 'unsafe-eval' is required because of a Chrome bug(?) that disallows loading WASM from 'self'. |
参考开源工程electron-wasm-rust-example修改策略
1 | <!-- |