理解WebAssembly中javascript和C交互

原创
2022/12/09 15:57
阅读数 232

WASM和以往的脚本语言调用本地代码方式很不相同。之前脚本语言是虚拟的,本地代码是操作系统原生的。这次js才是主人,C代码是虚拟运行的。

JS和C交互

  1. 不出所料只能调用C,C++接口需要自己封装成C的。
  2. JS和C调用的参数能只能是number类型,指针也当成number类型来处理。
  3. JS可以任意访问C的内存,而C不能访问任何JS内存。这种内存访问是单向的。
  4. C语言ma行后不退出,可以继续调用其他方法。函数名前都需要加下划线,例如Module._my_free(xx);来调用my_free()函数。
  5. C不能调用任何系统接口,只能通过JS来中转。因为C的运行环境是虚拟的,浏览器也只提供标准的JS API。
  6. WASM接口导出函数不支持int64,数据需要内存对齐。
  7. WASM使用的内存默认比较小。可以编译器时使用-s TOTAL_MEMORY=67108864来指定,或者ALLOW_MEMORY_GROWTH=1来动态扩容。

传递数据

  1. JS想传递除数字以外的参数,需要先用statckAlloc或者malloc函数分配内存,然后填充数据,再把指针传过去。
  2. C直接返回内存指针给JS,JS通过访问C的虚拟内存(Module.HEAPX)来获取指针指向的数据。

编译

-sEXPORTED_FUNCTIONS=_main,_other_function或者宏EMSCRIPTEN_KEEPALIVE,来标记函数需要导出。 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap编译选项表示启用ccall和cwrap功能,这两个帮助函数能自动做类型转换。

-sMODULARIZE编译参数可以让模块化导入:

var factory = require('./api_example.js');

factory().then((instance) => {
  instance._sayHi(); // direct calling works
  instance.ccall("sayHi"); // using ccall etc. also work
  console.log(instance._daysInWeek()); // values can be returned, etc.
});

--preload-file test/hello_world_file.txt 预加载文件

JS调用C

1.ccall, 2.cwrap 3.加‘_’直接调用

C调用JS

1.eval调用

emscripten_run_script("alert('hi')");

2.EM_JS和EM_ASM

#include <emscripten.h>

EM_JS(void, call_alert, (), {
  alert('hello world!');
  throw 'all done';
});

int main() {
  call_alert();
  return 0;
}

int main() {
  EM_ASM(
    alert('hello world!');
    throw 'all done';
  );
  return 0;
}

3.JS实现C函数

extern "C" {
  extern void my_js();
}

mergeInto(LibraryManager.library, {
  my_js: function() {
    alert('hi');
  },
});

4.JS添加C回调

addFunction(your_function, 'vi');

其他

环境变量

Module.preRun.push(function() {ENV.MY_FILE_ROOT = "/usr/lib/test"})
展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部