1、简单的C/C++ 编写
我们可以将C 代码 编译成wasm 文件供js 调用,C 文件的写法和我们普通的C写法并没有太大区别,不需要太多的封装,连main 入口都可以丢弃。例如C实现一个简单的加法计算
#include <stdio.h>
int add(int a, int b)
{
int sum = a + b;
printf("计算结果 %d\n", sum);
return sum;
}
编写脚本,编译C 文件成wasm 文件
rm *.js *.wasm
export EXPORTED_FUNCTIONS="['_add']"
emcc add.c \
-s EXPORTED_FUNCTIONS="${EXPORTED_FUNCTIONS}" \
-o add.js
-o 后缀名是js,指示编译器只生成wasm 以及js, 不生成默认的html 文件。
EXPORTED_FUNCTIONS ,将函数导出
编写html 文件调用wasm。
<html>
<head>
<meta charset="utf-8">
<title>Test</title>
</head>
<body>
<script>
Module = {};
Module.onRuntimeInitialized = function() {
console.log("计算结果:" + Module._add(12, 5));
}
</script>
<script src="add.js"></script>
</body>
</html>
Module是一个封装器对象,实现了C语言方法的导出,调用C 方法只需要Module._方法名即可。
2、数据交互
在实际的使用中,C语言经常使用malloc,free 等内存操作函数,而且一般传参都会传指针。这次在js端传入一个数组,C端完成计算并返回。
修改index.html,添加以下方法
function addBatch()
{
var num = 5;
var inputPtr = Module._malloc(4 * 5);
for(i = 0;i<num;i++)
{
Module.HEAP32[(inputPtr)>>2 + i] = i;
}
var sum = Module._addArry(inputPtr, num);
console.log("数组计算结果:" + sum);
Module._free(inputPtr);
}
JavaScript中的ArrayBuffer无法直接访问,必须通过某种类型的TypedArray方可对其进行读写,这里是将js 的数据写如一个Module.HEAP32 中,然后再传入C 中。Module._alloc /Module._free 对应于C 中的malloc/free ,需要在编译脚本中导出,不然会出现找不到
函数的错误。
rm *.js *.wasm
export TOTAL_MEMORY=10485760
export EXPORTED_FUNCTIONS="['_add', '_addArry', '_malloc', '_free']"
emcc add.c \
-s EXPORTED_FUNCTIONS="${EXPORTED_FUNCTIONS}" \
-s TOTAL_MEMORY=${TOTAL_MEMORY} \
-o add.js
echo "编译完成"
-s TOTAL_MEMORY 这个选项要加上,不然无法分配内存,报alloc memory error 错误。
对象 | TypedArray | 对应C数据类型 |
---|---|---|
Module.HEAP8 | Int8Array | int8 |
Module.HEAP16 | Int16Array | int16 |
Module.HEAP32 | Int32Array | int32 |
Module.HEAPU8 | Uint8Array | uint8 |
Module.HEAPU16 | Uint16Array | uint16 |
Module.HEAPU32 | Uint32Array | uint32 |
Module.HEAPF32 | Float32Array | float |
Module.HEAPF64 | Float64Array | double |
最后启动一个npm 安装http-server,启动服务器,搞定收工!
npm install http-server -g
http-server
参考资料
https://www.cntofu.com/book/150/zh/ch2-c-js/ch2-03-mem-model.md