内容简介:关于WebAssembly (基本的环境搭建可以参考这里用的是win10的环境,在windows上搭环境对(入门级)程序员来说真的是一大噩梦了叭(心累)。加之emscripten也有过不少的更新,网上的博客、StackOverflow等的解答很多已经不适用了,在摸爬滚打下...终于...我放弃了windows(。)
关于WebAssembly ( en zh ) 就不多说了,这是一个可移植、体积小、加载快并且兼容 Web 的全新格式。这里本人尝试了开发环境的搭建,并接入了一个C++编写的计算字符串MD5的自定义方法。
环境搭建
基本的环境搭建可以参考 mdn文档 和 emscripten-site ,将C/C++编译为wasm依赖于emscripten,这里我们需要自行去编译一个Emscripten。
这里用的是win10的环境,在windows上搭环境对(入门级)程序员来说真的是一大噩梦了叭(心累)。加之emscripten也有过不少的更新,网上的博客、StackOverflow等的解答很多已经不适用了,在摸爬滚打下...终于...我放弃了windows(。)
这里记录一下踩过的一些坑吧,虽然最后没有趟出来...
- vs2017不能使用过高的版本(15.8+),会导致编译Emcripten失败。
- 如果编译过程失败后,重装了visual studio,CMakeList上记录的vs版本会与现有版本不一致,(本人是emsdk uninstall了之前编译的模块)
- 尽量不要将emsdk需要的环境变量加到全局,包括node, python等,指向其内置安装的版本。加到全局PATH会覆盖掉原本在使用的版本。
还好,在emscripten的文档看到了这句话:
Instead of running emscripten on Windows directly, you can use the Windows Subsystem for Linux to run it in a Linux environment.
win10下支持安装 Ubuntu子系统 ,去Microsoft Store安装一下,再按照官方文档做简单配置就可以了。(强推这种方式,整个安装编译过程基本没有遇到问题)
在ubuntu子系统中,可以在/mnt目录下访问windows各盘的文件。
hint: emscripten FAQ 上有许多十分有用的常见问题及其解答。推荐先在上面寻找答案,再去动用搜索引擎(毕竟emscripten版本可能有变化)。
入门
可以先按照mdn上的 样例代码 尝试生成一个hello world的例子。
可能遇到的一些问题
- 需要用fetch加载wasm文件,为了方便,可以直接在生成的文件目录下起一个 http-server
- printf的内容要以换行结尾,否则输出的内容不会输出到控制台中。
- 生成wasm及胶水代码的过程中如果链接库出错了,可以先clear cache再重新尝试。
尝试执行用C++编写的函数
如果输出hello world成功了,环境的搭建应该没什么问题。
这里尝试接入一个用C++编写的对 字符串 计算MD5摘要的函数。网上有许多cpp的实现,可以随意找一种进行尝试。
这里打算用emscripten生成 ccall 函数的能力来调用C++函数。ccall可支持js和wasm之间传递number, string和array,其中string对应了js的String和C++的char*。
C++部分
C++中对外暴露一个接收char*,生成char* MD5的函数:
#ifdef __cplusplus extern "C" { #endif // 总之这个函数接收一个char*作为参数,返回一个char*的md5,各人实现不同。 char *getMD5(char *M) { string str = M; MD5 *pMD5 = new MD5(str); char *md5 = (char *)(pMD5->getDigest().c_str()); delete pMD5; return md5; } #ifdef __cplusplus } #endif
编译C++文件
我们在ubuntu子系统下进入到文件目录,编译这个C++文件,执行:
emcc md5.cpp -s "EXPORTED_FUNCTIONS=['_getMD5']" -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']" -o md5.js
【这里使用的emcc版本是1.38.21】
其中md5.cpp为我的C++文件名称
-s后跟的是编译时的选项:
- EXPORTED_FUNCTIONS值需要暴露给js调用的自定义函数,对应Cpp文件中的函数,在其函数名前前加一个下划线
- EXTRA_EXPORTED_RUNTIME_METHODS后跟我们需要调用的运行时方法,这里是'ccall'。
-o后跟的是编译目标,我们生成一个js文件,其中会附带帮助我们运行wasm的“胶水代码”,其中包括了ccall。
引入生成的js
执行成功后,我们新建一个md5.html,引入md5.js。
<!DOCTYPE html> <html> <head> <title>wasm_md5</title> </head> <body> <script type="text/javascript" src="md5.js"></script> <script> console.log(Module.ccall( "getMD5", // C函数的名称,这里不需要下划线 "string", // 返回值的类型 ["string"], // 参数列表的类型 ['123'], // 参数列表 )); </script> </body> </html>
生成的md5.js在全局添加了一个Module对象,其中有ccall方法,我们可以调用这个方法来计算MD5。
(123的MD5是202cb962ac59075b964b07152d234b70,可以检验是否计算成功~)
不太靠谱的比较
尝试使用cdn提供的js计算md5,与wasm计算进行时间比较。
(因为这里双方的算法可能存在一定差别,结果 可能并不可靠 )
为了方便生成不同的字符串,这里通过上传文件并使用FileReader将其转为base64的DataURL来获取字符串。
<!DOCTYPE html> <html> <head> <title>wasm_md5</title> </head> <body> <input type="file" onchange="handleFiles(this.files)" /> <script type="text/javascript" src="md5.js"></script> <!-- 加载一个cdn上计算md5的库 --> <script src="http://cdn.bootcss.com/blueimp-md5/1.1.0/js/md5.min.js"></script> <script> function handleFiles(files) { const file = files[0]; const urlReader = new FileReader(); urlReader.readAsDataURL(file); urlReader.addEventListener( "load", () => { compareMD5(urlReader.result); }, false ); } function compareMD5(str) { console.log("string length:", str.length); let beforeMD5, afterMD5; beforeMD5 = Date.now(); console.log( "wasm", Module.ccall("getMD5", "string", ["string"], [str]) ); afterMD5 = Date.now(); const wasmTime = afterMD5 - beforeMD5; beforeMD5 = Date.now(); console.log("js", md5(str)); afterMD5 = Date.now(); const jsTime = afterMD5 - beforeMD5; console.log("wasm:", wasmTime, "js:", jsTime); } </script> </body> </html>
贴几组不同长度的字符串计算md5的结果和时间比较,可以看见计算出的MD5是 相同 的,而比较之下wasm的计算速度还是 非常可观 的:
md5.html:string length: 743045 md5.html:27 wasm faa60598ea6af673883b2a5d71c3b669 md5.html:34 js faa60598ea6af673883b2a5d71c3b669 md5.html:37 wasm: 9 js: 63 md5.html:24 string length: 1250065 md5.html:27 wasm 0d306793f52ae52392abe86f9f445a0e md5.html:34 js 0d306793f52ae52392abe86f9f445a0e md5.html:37 wasm: 17 js: 135 md5.html:24 string length: 8769 md5.html:27 wasm 769ec5c2a9a0934c864b435878773722 md5.html:34 js 769ec5c2a9a0934c864b435878773722 md5.html:37 wasm: 0 js: 5 md5.html:string length: 144349 md5.html:27 wasm b119c18e331516c3ca6158fd2c5a6d8e md5.html:34 js b119c18e331516c3ca6158fd2c5a6d8e md5.html:37 wasm: 9 js: 29 md5.html:24 string length: 311285 md5.html:27 wasm aad59131791b96dcd8a518bbb1723905 md5.html:34 js aad59131791b96dcd8a518bbb1723905 md5.html:37 wasm: 7 js: 62
至此,我们成功通过wasm接入了一个计算字符串MD5的C++函数。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。