WebAssembly之js与c++交互

1,339 阅读1分钟

参考文档:www.cntofu.com/book/150/in…

记录自己写的几个测试的函数,用来实现c++与js交互。主要包括指针类型的数据的传递。

main.cpp

#ifndef EM_PORT_API
#	if defined(__EMSCRIPTEN__)
#		include <emscripten.h>
#       include <emscripten/val.h>
#       include <emscripten/bind.h>
        using namespace emscripten;
#		if defined(__cplusplus)
#			define EM_PORT_API(rettype) extern "C" rettype EMSCRIPTEN_KEEPALIVE
#		else
#			define EM_PORT_API(rettype) rettype EMSCRIPTEN_KEEPALIVE
#		endif
#	else
#		if defined(__cplusplus)
#			define EM_PORT_API(rettype) extern "C" rettype
#		else
#			define EM_PORT_API(rettype) rettype
#		endif
#	endif
#endif
#include <iostream>
#include <string.h>
#include "Student.h"



/**
 * recv int,return void
 */
EM_PORT_API(void) test(int a) {
    cout << "test called, a=" << a << endl;
}

/**
 * recv byte*, return int
 */
EM_PORT_API(int) sum(uint8_t* ptr, int count) {
    int total = 0, temp;
    for (int i = 0; i < count; i++){
        memcpy(&temp, ptr + i * 4, 4);
        cout << "[" << i << "], num = " << temp << endl;
        total += temp;
    }
    return total;
}

/**
 * recv int*,return int
 */
EM_PORT_API(int) sumInt(int* ptr, int count) {
    int total = 0;
    for (int i = 0; i < count; i++){
        cout << "[" << i << "], num = " << ptr[i] << endl;
        total += ptr[i];
    }
    return total;
}

/**
 * recv float*,return float
 */
EM_PORT_API(float) sumFloat(float* ptr, int count) {
    float total = 0;
    for (int i = 0; i < count; i++){
        cout << "[" << i << "], num = " << ptr[i] << endl;
        total += ptr[i];
    }
    return total;
}

/**
 * recv float*,return float*
 */
EM_PORT_API(float*) getFloats(float* ptr, int count) {
    float* total = new float[count];
    for (int i = 0; i < count; i++){
        cout << "[" << i << "], num = " << ptr[i] << endl;
        total[i] = ptr[i] + 1;
        cout << "[" << i << "], num + 1= " << total[i] << endl;
    }
    return total;
}

/**
 * recv float*, js callback
 */
EM_PORT_API(void) call(float* ptr, int count) {
    float* total = new float[count];
    for (int i = 0; i < count; i++){
        cout << "[" << i << "], num = " << ptr[i] << endl;
        total[i] = ptr[i] + 1;
    }
    for (int i = 0; i < 2; ++i) {
        EM_ASM_(
                {
                        callback_btn6($0);
                },
                total
        );

    }
}

/**
 * recv int*,return float*
 */
EM_PORT_API(float*) merge(int *ptr, int count)
{
    float* total = new float[count + 3];
    total[0] = 0.1f;
    total[1] = 0.2f;
    total[2] = 0.3f;
    memcpy(total+3,ptr,sizeof(int) * count);
    return total;
}

/**
 * recv float*,return void
 */
EM_PORT_API(void) cpp_recv(float *ptr, int count)
{
    int* tmp = new int[count - 3];
    for (int i = 0; i < 3; ++i) {
        cout << *(ptr+i)<< endl;
    }
    tmp = (int *)(ptr + 3);
    for (int i = 0; i < count - 3; ++i) {
        cout << *(tmp+i)<< endl;
    }
}

Makefile

TAG=main.js main.wasm
OBJ=Student.o main.o
CC:=emcc
RM:=rm -rf

$(TAG):$(OBJ)
	$(CC) -std=c++11  $^  -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap']" -o $@
%.o:%.cpp
	$(CC) -std=c++11 -c $^ -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap']" -o $@
.PHONY: clean cleanall
clean:
	$(RM) $(OBJ)
cleanall:
	$(RM) $(OBJ) $(TAG)

make完成之后会生成main.js和main.wasm。就成功了

test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
    <button id="btn1">call</button>
    <br>
    <button id="btn2">pass int array</button>
    <br>
    <button id="btn3">pass int array</button>
    <br>
    <button id="btn4">pass float array</button>
    <br>
    <button id="btn5">pass float array return float array</button>
    <br>
    <button id="btn6">c++ callback js return float array</button>
    <br>
    <button id="btn7">merge float* and int*, c++ return float*</button>
    <br>
    <button id="btn8">get data from btn7,trans data to float*</button>
    <script>
    Module = {};

    function callback_btn6(data) {
        alert(Module.HEAPF32[data >> 2]);
        alert(Module.HEAPF32[(data + 4) >> 2]);
        alert(Module.HEAPF32[(data + 8) >> 2]);
        alert(Module.HEAPF32[(data + 12) >> 2]);
        alert(Module.HEAPF32[(data + 16) >> 2]);
    }
    var str_pass = "";
    Module.onRuntimeInitialized = function() {
        var btn1 = document.getElementById('btn1');
        btn1.onclick = function() {
            Module.ccall('test', 'null', ['number'], [10]);
        }
        var btn2 = document.getElementById('btn2');
        btn2.onclick = function() {
            var count = 50;
            var buf = new ArrayBuffer(count * 4);
            var i8 = new Uint8Array(buf);
            var i32 = new Int32Array(buf);
            for (var i = 0; i < count; i++){
                i8[i] = i + 1;
            }
            result = Module.ccall('sum', 'number', ['array', 'number'], [i8, count]);
            alert(result);
        }
        var btn3 = document.getElementById('btn3');
        btn3.onclick = function() {
            var count = 5;
            var ptr = Module._malloc(4 * count);
            for (var i = 0; i < count; i++){
                Module.HEAP32[ptr / 4 + i] = i + 1;
            }
            console.log(Module._sumInt(ptr, count));
            Module._free(ptr);
        }

        var btn4 = document.getElementById('btn4');
        btn4.onclick = function() {
            var count = 5;
            var ptr = Module._malloc(4 * count);
            for (var i = 0; i < count; i++){
                Module.HEAPF32[ptr / 4 + i] = i + 1.1;
            }
            alert(Module._sumFloat(ptr, count));
            Module._free(ptr);
        }

        var btn5 = document.getElementById('btn5');
        btn5.onclick = function() {
            var count = 5;
            var ptr = Module._malloc(4 * count);
            for (var i = 0; i < count; i++){
                Module.HEAPF32[ptr / 4 + i] = i + 1.1;
            }
            var float_ptr = Module._getFloats(ptr, count);
            // alert(int_ptr);
            alert(Module.HEAPF32[float_ptr >> 2]);
            alert(Module.HEAPF32[(float_ptr + 4) >> 2]);
            alert(Module.HEAPF32[(float_ptr + 8) >> 2]);
            alert(Module.HEAPF32[(float_ptr + 12) >> 2]);
            alert(Module.HEAPF32[(float_ptr + 16) >> 2]);
            // alert(Module.HEAP32[int_ptr >> 2]);
            Module._free(ptr);
            Module._free(float_ptr);
        }

        var btn6 = document.getElementById('btn6');
        btn6.onclick = function() {
            var count = 5;
            var ptr = Module._malloc(4 * count);
            for (var i = 0; i < count; i++){
                Module.HEAPF32[ptr / 4 + i] = i + 1.1;
            }
            Module._call(ptr, count)
            //alert(Module._sumFloat(ptr, count));
            Module._free(ptr);
        }

        var btn7 = document.getElementById('btn7');
        btn7.onclick = function() {
            var count = 5;
            var ptr = Module._malloc(4 * count);
            for (var i = 0; i < count; i++){
                Module.HEAP32[ptr / 4 + i] = i + 1;
            }
            var res = Module._merge(ptr, count);
            var str = '';
            for (var i = 0; i < 3; i++){
                str += Module.HEAPF32[(res >> 2) + i];
                str += '|';
            }
            for (var i = 3; i < 3 + count; i++){
                str += Module.HEAP32[(res >> 2) + i];
                str += '|';
            }
            console.log(str);
            str_pass = str;
            //alert(Module._sumFloat(ptr, count));
            Module._free(ptr);
            Module._free(res);
            var array = str.split("|");
            // for (var j = 0; j<array.length; j++) {
            //     alert(array[j]);
            // }
        }

        var btn8 = document.getElementById('btn8');
        btn8.onclick = function() {
            var array = str_pass.split("|");
            var ptr = Module._malloc(4 * (array.length -1));
            for (var j = 0; j<3; j++) {
                Module.HEAPF32[ptr / 4 + j] = array[j];
            }
            for (var j = 3; j<array.length-1; j++) {
                console.log(">>>"+array[j]);
                Module.HEAP32[ptr / 4 + j] = array[j];
            }
            Module._cpp_recv(ptr,array.length -1);
            Module._free(ptr);
        }
    }

</script>
    <script src="main.js"></script>
</body>
</html>