WebAssembly standalone模块示例
WebAssembly还是个很新鲜的玩意儿,ABI都还没稳定。
通常emscripten/emcc会产生厚厚的胶水代码来连接Javascript和wasm模块,通过import/export,Javascript和原生代码可以相互访问、调用,
除了简单数据类型,还可以通过memory和table来模拟指针、函数指针运算。
当前,emscripten/emcc已经支持生成standalone单独的wasm模块,无需胶水代码就可以简单使用标准的JS来访问wasm数据和代码,下面是一个简单的栗子:
C代码
1 | double buf\[1024\]; |
add函数计算buf缓冲区中前count个浮点数之和,注意这里整个C代码没有任何其他库的依赖。
编译成wasm
1 | $ emcc add.c -Os -s WASM=1 -s "EXPORTED_FUNCTIONS=\['_add', '_getOffset'\]" -s SIDE_MODULE=1 -o add.wasm |
-Os 编译优化选项会将所有用不到的代码去除掉,也不会包括任何标准库
-s WASM=1 指示生成wasm文件
-s “EXPORTED_FUNCTIONS=[‘_add’, ‘_getOffset’]“ 指示导出add和getOffset这个两个函数,导出标识符要用C的方式,C++语言的时候要注意名字碾压,导出的函数需要使用extern “C”修饰
-s SIDE_MODULE=1 指示生成wasm动态库
生成的add.wasm可以使用wabt(The WebAssembly Binary Toolkit)工具集中的命令wasm2wat转换为WebAssembly的wat/wast文本S-Express格式
1 | $ wasm2wat add.wasm |
可以看到add.wasm的import和export的各种东西global、func、memory,如果使用了函数指针还会有table
如果没用到memory,可以用wasm2wat将其转为wat/wast文本格式,将import memory相关去掉,
然后使用wat2wasm再编译回wasm格式就无需导入任何东西了。
调用wasm
写一个简单的页面来调用wasm代码:
[html]
其实获取C代码缓冲区起始地址的getOffset并没有必要,因为wasm模块直接导出了缓冲器的标识符_buf,其实就是缓冲区的首地址
除了基本类型,JS和原生代码通过memory的buffer来交换大块的数据。
访问
需要起一个web server
1 | $ python3 -m http.server 8081 |
然后访问http://127.0.0.1:8081/add.html,点击按钮可以看到JS调用WASM中的routine然后返回了计算结果。
最后
如果WASM模块依赖于其他库代码,目前还无法生成standalone模块,需要生成胶水js代码来访问。
另外,tableBase和memoryBase已经更名为__table_base和__memory_base
References:
[1]WebAssembly Standalone
[2]Disable linking libc in emscripten
[3]Rename tableBase/memoryBase to __table_base/__memory_base
[4]WebAssembly Dynamic Linking
[5]How to access WebAssembly linear memory from C/C++