在typescript浏览器端中调用C++编写的函数,WebAssembly传递指针类型的参数,以及处理指针类型的返回值。

首先要在Cmake工程中的cmakelists.txt文件中引入Emscripten工具链:

set(CMAKE_TOOLCHAIN_FILE "D:/CppPkg/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake")

直接看C++代码:

#include <emscripten/emscripten.h>
#include <cstdlib>


extern "C" {
	struct DataResult {
		double* dArr;
		int propCount;
	};

	EMSCRIPTEN_KEEPALIVE
	double sumArray(double* fArr, int arrLen) {
		double sum = 0.0;
		for (int i = 0; i < arrLen; i++) {
			sum += fArr[i];
		}
		return sum;
	}
	EMSCRIPTEN_KEEPALIVE
	double* vectorSum(double* vectorA, double* vectorB, int vecLen) {
		double* resArr = (double*)malloc(vecLen * sizeof(double));
		for (int i = 0; i < vecLen; i++) {
			resArr[i] = vectorA[i] + vectorB[i];
		}
		return resArr;
	}
	EMSCRIPTEN_KEEPALIVE
	DataResult* createDataResult(double* dArr, int propCount) {
		DataResult* dtRes = (DataResult*)malloc(sizeof(DataResult));
		dtRes->dArr = dArr;
		dtRes->propCount = propCount;
		return dtRes;
	}

	EMSCRIPTEN_KEEPALIVE
	double* allocateDoubleMemory(int size) {
		return (double*)malloc(size * sizeof(double));
	}
	EMSCRIPTEN_KEEPALIVE
	void freeMemory(void* dataPtr) {
		free(dataPtr);
	}
}

通过em++命令,生成MyLib.js和MyLib.wasm文件

em++ MyLib.cpp -O2 -o MyLib.js -s WASM=1 -s MODULARIZE=1 -s EXPORT_NAME="MyLibModule" -s "EXPORTED_FUNCTIONS=['_sumArray']" -s "EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap']"

在WASMTest.ts中编写代码:

type ImportObject = WebAssembly.Imports;
 interface MyLibModule{
    sumArray: (fArr: number, arrLen: number) => number;
    allocateDoubleMemory: (size: number) => number;
    freeMemory: (dataPtr: number) => void;
    vectorSum: (vectorA: number, vectorB: number, vecLen: number) => number;
    createDataResult: (dArrPtr: number, propCount: number) => number;
    memory: WebAssembly.Memory;
 }

 async function loadWasmModule(memory: WebAssembly.Memory): Promise<MyLibModule>{
    const importObject: WebAssembly.Imports = {
        env: {
            memory: memory,
            emscripten_resize_heap: () => {
                console.log("emscripten_resize_heap called");
                return true;  // 这里可以返回 true 或者处理扩展内存的逻辑
            },
        }
    };
    const response = await fetch('src/lib/wasm/MyLib.wasm');
    const buffer = await response.arrayBuffer();
    const module = await WebAssembly.instantiate(buffer, importObject);
    return module.instance.exports as unknown as MyLibModule;
 }

 async function useModule(){
    const memory = new WebAssembly.Memory({ initial: 20, maximum: 1000 });
    const wasmModule = await loadWasmModule(memory);
    const pageSize = 64 * 1024;
    const totalMemory = memory.buffer.byteLength;
    const totalPages = totalMemory/pageSize;
    console.log(`Total memory: ${totalMemory} bytes (${totalPages} pages)`)
    memory.grow(100);
    console.log(`New total memory size: ${memory.buffer.byteLength} bytes`);

        const vecA = new Float64Array([1,2,3,4,5,6,9,12]);
        const vecB = new Float64Array([1,2,3,4,5,6,6,14]);
        const vecAptr = wasmModule.allocateDoubleMemory(vecA.length * 8);
        const vecBptr = wasmModule.allocateDoubleMemory(vecB.length * 8);
        const memoryBuffer = wasmModule.memory.buffer;
        const wasmVecA = new Float64Array(memoryBuffer, vecAptr, vecA.length);
        const wasmVecB = new Float64Array(memoryBuffer, vecBptr, vecB.length);
        wasmVecA.set(vecA);
        wasmVecB.set(vecB);
        const resultPtr = wasmModule.vectorSum(vecAptr, vecBptr, vecA.length);
        const wasmRes = new Float64Array(memoryBuffer, resultPtr, vecA.length);
        console.log(wasmRes)
        wasmModule.freeMemory(vecAptr);
        wasmModule.freeMemory(vecBptr);
        wasmModule.freeMemory(resultPtr);
    
        // 传递数组,返回结构体指针,从结构体指针中取数据。
        const dArr = new Float64Array([5,4,7,1,9,3,5]);
        const dArrPtr = wasmModule.allocateDoubleMemory(dArr.length * 8);
        const wasmdArr = new Float64Array(memoryBuffer, dArrPtr, dArr.length);
        wasmdArr.set(dArr);
        const resPtr = wasmModule.createDataResult(dArrPtr, dArr.length);
        const dataView = new DataView(memoryBuffer);
        const dArrResPtr =  Number(dataView.getUint32(resPtr, true));
        const propCount = dataView.getInt32(resPtr+4, true);
        const resdArr = new Float64Array(memoryBuffer, dArrResPtr, propCount);
        console.log(`return struct DataResult dArr Pointer is ${dArrResPtr}`);
        console.log(`the struct DataResult dArr value is: `);
        console.log(resdArr);
        wasmModule.freeMemory(dArrPtr);
        wasmModule.freeMemory(resPtr);
    
}
useModule();

查看浏览器打印结果:

在这里插入图片描述

第一个例子:在这里,我们传递了2个双精度浮点的数组,传递进入C++函数,然后给两个数组求和,返回的是double*类型的指针。
第二个例子:
最后是返回一个C++结构体指针,在TypeScript中通过DataView来获取内存中的地址偏移量来取得结构体中的数据,因为em++编译器是以32位来编译.cpp文件的,所以指针占4个字节。DataResult结构体第一个属性dArr是一个指针,那么就是地址偏移量0,然后以32位无符号整型取得dArr指针,通过这个指针去读取wasm中memoryBuffer中的数据,就可以得到dArr属性对应的值了。同理,通过地址偏移量+4来得到propCount属性,以32位整数读取数据即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值