#include <emscripten.h>
#include <emscripten/bind.h>//EMSCRIPTEN_BINDINGS 的头文件
#include <iostream>
#include <string>
#include <math.h>
#include <stdio.h>
//#include <SDL.h>
using namespace emscripten;//EMSCRIPTEN_BINDINGS 中的 function
using namespace std;
// 注意extern “C” 中的C要大写
extern "C" int EMSCRIPTEN_KEEPALIVE myFunction(int argc, char **argv)
{
cout<<"这是一个测试函数"<<endl;
return 0;
}
extern "C" char* EMSCRIPTEN_KEEPALIVE outName(char *n)
{
char xhName[] = "xuanhun";
strcat(n, xhName);
cout<<"outName = "<<n<<endl;
return n;
}
// 在浏览器控制台 可以执行 Module._myFunction() 函数,注意是extern "C"
// 函数名只会在前面加一个下划线,否则名称就比较繁琐
// main函数也是默认导出的函数 可以使用 Module._main() 来执行
EM_JS(void, call_alert, (), {
alert('hello world!');
console.log("EM_JS,nihao!");
//throw 'all done';
});
EM_JS(int, call_add, (int a,int b), {
console.log("EM_JS,add!");
return a + b;
});
//Null-terminated C strings can also be passed into EM_JS functions,
//but to operate on them, they need to be copied out from the heap to convert to high-level JavaScript strings.
// use connsole.log('hello ' + UTF8ToString(str));
EM_JS(char*, call_add_string, (char* a,char* b), {
console.log("EM_JS,add_string!");
console.log(UTF8ToString(a));
var s = "hello,jsStr";
//return a;//也可以
var returnStr = "Hello C#!";
var bufferSize = lengthBytesUTF8(returnStr) + 1;
var buffer = _malloc(bufferSize);
stringToUTF8(returnStr, buffer, bufferSize);
return buffer;
//由于这里直接return了,本来buffer是要_free(buffer)释放的,因此在实际场景中最好用智能指针包裹起来
});
// 上面的EM_JS执行的是C风格代码,不允许C++的类型 例如 std::string
// stackoverflow的解释:If you use extern "C" with a function, you cannot use C++ types in it's signature.
// So if you want to use std::string, then you can use "Embind" or "WebIDL Binder". Refer here
/* 下面通过 Embind 的方法处理
// This is your routine C++ code
size_t MyStrLen(std::string inStr) {
return inStr.length();
}
// This is the extra code you need to write to expose your function to JS
EMSCRIPTEN_BINDINGS(my_module) {
function("MyStrLen", &MyStrLen);
}
Now in JS all you need to do is:
var myStr = "TestString";
Module.MyStrLen(myStr);
Make sure you pass the flag
--bind
when calling emcc.
There is another approach where you can do a Malloc on the C++ heap from JS and then do manipulations, but the above approach should be easier.
*/
// This is your routine C++ code
size_t MyStrLen(std::string inStr) {
return inStr.length();
}
// This is the extra code you need to write to expose your function to JS
EMSCRIPTEN_BINDINGS(my_module) {
emscripten::function("MyStrLen", &MyStrLen);
}
EM_JS(void, read_data, (int* data), {
console.log('Data: ' + HEAP32[data>>2] + ', ' + HEAP32[(data+4)>>2]);
});
EM_JS(void, call_myFunc, (const int argc, const char** argv), {
var arr = [];
for (let i = 0; i < argc; i++) {
const mem = HEAP32[(argv + (i * 4)) >> 2];
const str = UTF8ToString(mem);
arr.push(str);
}
console.log(arr);
});
extern "C" {
int int_sqrt(int x) {
return sqrt(x);
}
}
int main() {
cout<<"hello,world"<<endl;
EM_ASM({
window.onload = function () {
cout<<"onload"<<endl;
// 初始化模块后的调用
Module.onRuntimeInitialized = function () {
_myFunction();
}
}
});
int value = 10;
EM_ASM({
console.log("xxxxx");
alert("xxx");
console.log("value = ",$0);
Module._myFunction();
},value);
int x = EM_ASM_INT({
return 11;
});
cout<<"x = "<<x<<endl;
call_alert();
// 需要增加编译标识 -s EXTRA_EXPORTED_RUNTIME_METHODS=["ccall","cwrap"]
int rSqrt = EM_ASM_INT({
int_sqrt = Module.cwrap('int_sqrt', 'number', ['number']);
var s = int_sqrt(12);
console.log('s = ',s);
return int_sqrt(28);
},x);
cout<<"rSqrt = "<<rSqrt<<endl;
int result = call_add(20,10);
cout<<"result = "<<result<<endl;
char* str = call_add_string("123+","456");
cout<<"str = "<<str<<endl;
int arr[2] = { 30, 45 };
read_data(arr);
const int argc = 4;
const char* argv[] = { "ab", "cd", "ef", "gh" };
call_myFunc(argc, argv);
EM_ASM({
var myStr = "TestString";
console.log(myStr);
var len = Module.MyStrLen(myStr);
console.log("len = ",len);
});
// emcc src/main.cpp -o bin/function.html -s EXPORTED_FUNCTIONS="['_int_sqrt','_main']" --bind
EM_ASM({
var returnStr = "玄魂";
var bufferSize = lengthBytesUTF8(returnStr) + 1;
var buffer = _malloc(bufferSize);
stringToUTF8(returnStr, buffer, bufferSize);
var retPtr = Module._outName(buffer);
console.log(UTF8ToString(retPtr));
_free(buffer);
});
}
// emcc编译命令:emcc src/main.cpp -o bin/function.html -s EXPORTED_FUNCTIONS="['_int_sqrt','_main']"
// Embind启用 : --bind
// ccall 和 cwrap 启用:-s EXTRA_EXPORTED_RUNTIME_METHODS=["ccall","cwrap"]
//emcc: warning: EXTRA_EXPORTED_RUNTIME_METHODS is deprecated, please use EXPORTED_RUNTIME_METHODS instead [-Wdeprecated]
// 启用Pointer_stringify -s EXPORTED_RUNTIME_METHODS=["Pointer_stringify"] 这个没用 最后换成了stringToUTF8 + _malloc + _free
// 最终的emcc编译命令:emcc src/main.cpp -o bin/function.html -s EXPORTED_FUNCTIONS="['_int_sqrt','_main']" -s EXPORTED_RUNTIME_METHODS=["ccall","cwrap"]
本文详细介绍了如何使用Emscripten将C++代码编译为WebAssembly,并与JavaScript进行交互。通过示例展示了EM_JS、EMSCRIPTEN_BINDINGS和Emscripten的API,如ccall、cwrap等,实现C++函数在浏览器中的调用,以及数据的传递和处理。同时,还讨论了如何处理C++和JavaScript之间的字符串操作及内存管理。
197

被折叠的 条评论
为什么被折叠?



