Vue调用wasm
因现有的前后端交互大多是依赖c++的计算,想把后台的c++库的部分计算移到浏览器当中实现,因为受制于沙盒的缘故前端无法直接调用C++的dll。所以使用一种新的解决方案,使用WebAssembly把C++源码编译成wasm文件,前端可以调用wasm中封装好的方法...
Vue调用wasm使用说明
一、需求及背景描述
因现有的前后端交互大多是依赖c++的计算,想把后台的c++库的部分计算移到浏览器当中实现,因为受制于沙盒的缘故前端无法直接调用C++的dll。所以使用一种新的解决方案,使用WebAssembly把C++源码编译成wasm文件,前端可以调用wasm中封装好的方法。
WebAssembly:WebAssembly/wasm WebAssembly 或者 wasm 是一个可移植、体积小、加载快并且兼容 Web 的全新格式。也 是由主流浏览器厂商组成的 W3C 社区团体 制定的一个新的规范
官网链接:http://webassembly.org.cn/
二、环境搭建
C/C++主要依赖于Emscripten环境来编译到WebAssembly。windows下配置Emscripten环境易错且繁杂,所以社区比较推荐linux下安装,或者win环境下通过Docker快速搭建WebAssembly编译环境。
(C++开发人员转好wasm后发送给前端,前端可不配置本机的Emscripten环境,或者前端使用在线转换也不需配置emscripten环境)
Emscripten 环境安装:
你需要将下列工具安装在您的电脑上,首先让我们确认下都有哪些。
- Git — Linux 和 macOS 的机器一般已经预装了,在 Windows 下您可以从这里下载 Git for Windows installer。
- CMake — 在 Linux 或者 macOS 上,使用类似 apt-get 或 brew 这样的包管理器来安装它,请确保依赖以及路径是否正确。在 Windows 上,使用 CMake installer。
- 主系统编译器 — 在 Linux 下,安装 GCC。在 macOS 下,安装 Xcode。在 Windows 下,安装 Visual Studio Community 2015 with Update 3 or newer。
- Python 2.7.x — On Linux and macOS, this is most likely provided out of the box. 从 初学者指南 获取帮助。在 Windows 上,从 Python 主页获取安装包。
**注意:**在 Windows 下您可能需要pywin32,为了降低安装 pywin32 可能遇到的错误,请使用管理员权限在 cmd 内运行安装程序。
安装完毕后,确认 git
,cmake
和 python
已经在你的环境变量里,可以使用。
接下来,您需要通过源码自己编译一个 Emscripten。运行下列命令来自动化地使用 Emscripten SDK。(在你想保存 Emscripten 的文件夹下运行)。
- #从GitHub仓库下载编译器项目文件,选择一个英文目录,打开git命令行
git clone https://github.com/juj/emsdk.git
- 下载成功后,当前目录下会出现一个emsdk目录,进入到该目录下。
cd emsdk
- 安装最新的SDK并激活,在当前命令行继续输入命令。 注: 安装要一点时间,需要耐心等待,具体速度看网络情况。
# 在 Linux 或者 Mac macOS 上
./emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
./emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit
# 如果在你的 macos 上获得以下错误
Error: No tool or SDK found by name 'sdk-incoming-64bit'
# 请执行
./emsdk install latest
# 按照提示配置环境变量即可
./emsdk activate latest
# 在 Windows 上
emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit
- 在命令行输入em++ -v测试编译器是否安装成功。
此时环境安装已完成
安装文档可参考:https://emscripten.org/docs/getting_started/downloads.html
Win10使用Docker搭建环境可参考:https://www.jianshu.com/p/a35aa4e26831
开发者引导文档:http://webassembly.org.cn/getting-started/developers-guide/
三、C/C++转换wasm
- emcc转换
- C++在编写代码时,需要对外进行函数暴露
#ifdef __cplusplus
extern "C"
{
#endif
int fun(int x) {
if (x <= 0)
return 0;
if (x <= 2)
return 1;
return fun(x - 1) + fun(x - 2);
}
#ifdef __cplusplus
}
#endif
- 转换wasm
//进入到Cpp文件所在目录,打开终端执行
emcc fun.cpp -s "EXPORTED_FUNCTIONS=['_fun']" -o fibtest.js
其中fun.cpp
为我的C++文件名称
-s
后跟的是编译时的选项:
- EXPORTED_FUNCTIONS值需要暴露给js调用的自定义函数,对应Cpp文件中的函数,在其函数名前前加一个下划线
-o
后跟的是编译目标,我们生成一个js文件,其中会附带帮助我们运行wasm的“胶水代码”
**注意:**在执行emcc命令时,在暴露的函数名称fun前加下划线,如“_fun
"
若暴露多个函数,只需在EXPORTED_FUNCTIONS增加
emcc fun.cpp -s "EXPORTED_FUNCTIONS=['_fun','_fun2','_fun3']" -o fibtest.js
-
在线转换
emcc转换后的wasm文件比较大,如果源码不太复杂的话,也可以在线转换。在线转换网站https://mbebenita.github.io/WasmExplorer/。
转换流程请看下图,转换后的wasm大小为1kb
注意:转换后接口函数名已发生变化,前端需要调用新的函数名,或者手动进行更改。
C语言的在线转换网站:https://wasdk.github.io/WasmFiddle/
四、Vue中调用wasm
为了打包后wasm也能被找到,建议将wasm放到public目录下,并在目录下创建js/wasm目录,将wasm文件都保存在此。(或者有更好的方式)
如果控制台报如下错误,是因为wasm文件未被找到。
Failed to load resource: the server responded with a status of 404 (Not Found)
Uncaught (in promise) CompileError: WebAssembly.compile(): expected magic word 00 61 73 6d, found 3c 21 44 4f @+0
vue调用wasm实现代码
fetch('js/wasm/fib.wasm').then(response=>
response.arrayBuffer()).then(bytes =>WebAssembly.compile(bytes)).then(mod=>{
const instance = new WebAssembly.Instance(mod)
const a= instance.exports
//_Z3fibi(3)为函数。
console.log(a._Z3fibi(3))
});
也可封装一个通用的加载函数
loadWebAssembly(path, imports = {}) {
return fetch(path) // 加载文件
.then(response => response.arrayBuffer()) // 转成 ArrayBuffer
.then(buffer => WebAssembly.compile(buffer))
.then(module => {
imports.env = imports.env || {}
// 开辟内存空间
imports.env.memoryBase = imports.env.memoryBase || 0
if (!imports.env.memory) {
imports.env.memory = new WebAssembly.Memory({ initial: 256 })
}
// 创建变量映射表
imports.env.tableBase = imports.env.tableBase || 0
if (!imports.env.table) {
// 在 MVP 版本中 element 只能是 "anyfunc"
imports.env.table = new WebAssembly.Table({ initial: 0, element: 'anyfunc' })
}
// 创建 WebAssembly 实例
return new WebAssembly.Instance(module, imports)
})
}
#函数调用
this.loadWebAssembly ('js/wasm/math.wasm')
.then(instance => {
const square = instance.exports.square//取出cpp里面的方法
this.result=square(this.num)
})
更多推荐
所有评论(0)