Emscripten——C++ 调用 Js 回调函数

WASM 调用 js 代码 Emscripten 提供了两种方式,用于从 C/C++ 调用 JavaScript 的方法: 使用 emscripten_run_script() 运行脚本 编写 inline JavaScript。 最直接但稍微慢的方式是使用 emscripten_run_script()。这有效地使用 eval() 在 C/C++ 中运行指定的 JavaScript 代码。例如,调用浏览器的 alert() 函数,例如下面的代码: int EMSCRIPTEN_KEEPALIVE runScript(){ emscripten_run_script("alert('hi')"); emscripten_run_script("console.log('hello world!')"); return 0; } 从 C 中调用 JavaScript 接口的一种更快的方法是编写 inline JavaScript,使用 EM_JS() 或 EM_ASM() (以及其它相关的宏)。 EM_JS 是在 C 文件中声明一个 JavaScript 函数,使用方法参考这里。 #include <emscripten.h> EM_JS(void, myAlert, (), { alert('hello world!'); throw 'all done'; // exception }); EM_JS(void, take_args, (int x, float y), { console....

March 26, 2022 · 2 min · Rick Cui

Emscripten——js 调用 C++ 接口

Emscripten 提供了许多方法来在 JavaScript 和编译后的 C 或 c++ 之间连接和交互,我们先来看看 js 调用 WASM 的情况。 一、使用 ccall 或 cwrap callall() 调用带有指定参数的编译过的 C 函数 并返回结果,而 cwrap() 封装了编译过的 C 函数并返回一个可以正常调用的 JavaScript 函数。因此,如果计划多次调用一个编译后的函数,cwrap() 会更有用。 例如下面的 C main.cpp 文件: #include <math.h> extern "C" { int int_sqrt(int x) { return sqrt(x); } } 使用下面的命令进行编译: emcc main.cpp -o function.html -s EXPORTED_FUNCTIONS=_int_sqrt -s EXPORTED_RUNTIME_METHODS=ccall,cwrap EXPORTED_FUNCTIONS 告诉编译器哪些函数我们想要导出(不指定的函数会被删掉),EXPORTED_RUNTIME_METHODS 告诉编译器我们需要用到的运行时方法 ccall 和 cwrap,否则这些方法也会被优化掉 编译后就可以在 js 中通过 cwrap 使用了: int_sqrt = Module.cwrap('int_sqrt', 'number', ['number']) int_sqrt(12) // return 3 int_sqrt(28) // return 5 第一个参数是被 wrap 的 C 函数的名字(没有下划线),第二个参数是函数返回值在类型(如果没有返回值,使用 JavaScript 的 null 类型),第三个参数是一个参数数组(如果没有参数,可以省略)。...

March 25, 2022 · 2 min · Rick Cui

Emscripten——使用 CMake 构建并用 Make 编译

使用 CMake 构建 在源文件目录添加 CMakeList.txt 文件 # 设置CMake版本最低要求 cmake_minimum_required(VERSION 3.10)# 设置项目名称和版本 set(MyTarget hello)project(${MyTarget} VERSION 1.0)# 指定 C++ 标准 set(CMAKE_CXX_STANDARD 11)set(CMAKE_CXX_STANDARD_REQUIRED True)# 编译生成.html文件 set(CMAKE_EXECUTABLE_SUFFIX ".html")# 添加源码文件和生成的目标文件的名称 # file(GLOB_RECURSE SRC_MAIN ./*.cpp) aux_source_directory(./ SRC_MAIN)aux_source_directory(./thirdParty/ SRC_MAIN)add_executable(${MyTarget} ${SRC_MAIN})# add_executable(${MyTarget} main.cpp) # 设置Emscripten的编译链接参数 set_target_properties(${MyTarget} PROPERTIES LINK_FLAGS " \ -s EXIT_RUNTIME=0 \ -gsource-map \ -s EXPORTED_FUNCTIONS=_main,_sayHello1,_jsonParse,_jsonParse1 \ -s EXPORTED_RUNTIME_METHODS=ccall,cwrap,addFunction \ -s NO_DISABLE_EXCEPTION_CATCHING \ ")# 添加第三方库路径 # target_link_directories(${MyTarget} # PUBLIC "${PROJECT_BINARY_DIR}" # ) # 将第三方库与主程序进行链接 # set(LIBS cjson) # target_link_libraries(sample ${LIBS}) # 添加头文件查找路径 target_include_directories(${MyTarget} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" ) 创建 build 文件夹,并在 build 文件夹内执行命令 emcmake cmake ....

March 24, 2022 · 1 min · Rick Cui

Emscripten——C++ 函数导出

导出 C++ 函数到 js 有多种方式: 方式一:在编译的时候指定 在编译命令中添加 -sEXPORTED_FUNCTIONS 参数,例如:-s EXPORTED_FUNCTIONS=_myFunction,_sayHello1 方式二:修改 C++ 函数 在 C++ 代码中需要导出的函数声明前添加 EMSCRIPTEN_KEEPALIVE 宏定义 #include <emscripten.h> extern "C" int EMSCRIPTEN_KEEPALIVE myFunction(int argc, char ** argv) { printf("我的函数已被调用\n"); return 0; } #ifdef __cplusplus extern "C" { #endif int EMSCRIPTEN_KEEPALIVE sayHello(){ cout << "hello from sayHello!" << endl; return 0; } int sayHello1() { Person p; cout << p.printInfo() << endl; return 0; } #ifdef __cplusplus } #endif 方式三:WebIDL Binder...

March 24, 2022 · 1 min · Rick Cui

Emscripten——Hello World

编译 新建 main.cpp 文件 #include <iostream>using namespace std; int main(){ cout << "hello world!" << endl; return 0; } 使用 emcc 或 em++ 编译 C++ 文件 执行命令 em++ main.cpp,会在同级目录下生成 a.out.js 和 a.out.wasm 两个文件。 使用 node 测试 测试命令 node a.out.js,会在控制台输出 cout 的内容 使用 html 页面 测试 执行命令 em++ main.cpp -o hello.html,会在同级目录下生成三个文件: hello.html:测试网页 hello.js:相关的胶水代码,包括加载 WASM 文件并执行调用等相关逻辑 hello.wasm:编译得到的核心 WebAssembly执行文件 在本地启动一个静态网站服务器,就可以在浏览器中访问生成的网页了 编译带有 调试 信息的测试页面...

March 24, 2022 · 1 min · Rick Cui