简介
Dependent类型的WASM应用与Standalone类型有所不同,在该类型应用中一般都包含着大量与浏览器特定功能相关的方法调用。比如在对应c/c++源代码中使用了IO标准库,OpenGL等需要与宿主环境本身进行交互的相关技术。另外,由于Wasm模块本身无法直接与浏览器进行交互,因此,Emscripten 便需要通过某种具有类似“胶水”功能的JavaScript代t码,来将Wasm模块与Web浏览器在功能交互和数据资源传输层面连接起来。
1.c++源码
#include <emscripten.h>
#include <iostream>
using namespace std;
#ifdef __cplusplus
extern "C" {
#endif
void EMSCRIPTEN_KEEPALIVE echo (int x){
cout<<"this number you input is:"<<x<<endl;
return;
}
#ifdef __cplusplus
}
#endif
2.自己写一个辅助js文件来调用.cc暴露的函数
__ATPOSTRUN__.push(() =>{
Module.ccall('echo',null,['number'],[10]);
});
语法:
var result = Module.ccall(ident, returnType, argTypes, args);
参数:
ident :C导出函数的函数名(不含“_”下划线前缀);
returnType :C导出函数的返回值类型,可以为'boolean'、'number'、'string'、'null',
分别表示函数返回值为布尔值、数值、字符串、无返回值;
argTypes :C导出函数的参数类型的数组。参数类型可以为'number'、'string'、'array',分别代表数值、字符串、数组;
args :参数数组。
__
开头和结尾的标识符为Emscripten在JavaScript运行时环境中提供的钩子队列数组。比如__ATPOSTRUN__
队列,在整个Wasm应用的生命周期中,当对应C/C++源代码中主函数的代码逻辑执行完毕后,被放入该队列数组内的函数会开始执行;__ATPRERUN__
队列中的函数,会在应用开始运行前被执行,这里一般会进行虚拟文件系统的初始化工作;__ATINIT__
队列中的函数,会在Emscripten运行时环境开始初始化时被执行;__ATMAIN__
队列中的函数,会在C/C++源代码中的主函数将被调用前被执行;__ATEXIT__
队列中的函数,会在整个应用/ERE运行时环境退出时被执行,在这里可以对之前分配的系统和内存资源进行回收处理。
3.编译命令
emcc dependent.cc -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS=["ccall"] --post-js post-script.js -o dependent.js
ccall/cwrap
辅助函数默认没有导出,在编译时需要通过-s EXTRA_EXPORTED_RUNTIME_METHODS=["ccall", "cwrap"]
选项显式导出。
查看"胶水"js文件的尾部
--post-js
参数则用于指定需要追加到“胶水”脚本文件末尾的js代码,同理:--pre-js
是文件头部
4.运行该wasm模块
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>我的wasm学习</title>
</head>
<body>
<script>
//初始化Module全局对象,由Emscripten工具链自动完成内容填充
var Module = {};
fetch("/cctest/dependent.wasm").then(
response => response.arrayBuffer()
).then((bytes) => {
//填充模板数据
Module.wasmBinary = bytes;
//动态异步的载入由Emscripten生成的“胶水”脚本文件
var script = document.createElement('script');
script.src = "/cctest/dependent.js";
document.body.appendChild(script);
})
</script>
</body>
</html>
参考:《深入浅出WebAssembly》 于航
网友评论