系列文章目录
第一章 WebAssembly概念
第二章 Emscripten详解
第三章 JavaScript调用C\C++
第四章 C\C++调用JavaScript
WebAssembly第三章 JavaScript调用C\C++
前言
本篇是WebAssembly系列文章的第三章,我会在本文介绍在几个常用场景下JavaScript调用C++函数所需要用到的操作步骤,编译命令,和具体的代码。
我的环境
组件 | 版本 |
---|---|
CentOS | 7 |
Docker | 20.10.7 |
emscripten/emsdk | 3.1.14 |
nginx | 1.18.0 |
chrome | 102.0.5005.115 |
一、码代码
JavaScript载入并运行WASM
目标
在Emscripten提供的迷你HTML模板页面上通过运行C++生成的wasm显示helloworld字样。
载入wasm的话,如果源文件有main函数就会自动运行。
先用C++写个hello world
sayhello.cpp
#include <stdio.h>
#include <iostream>
using namespace std;
int main(int argc, char ** argv) {
printf("我是printf: Hello World\n");
cout<<"我是C++的cout "<<"你好,世界"<<endl;
return 0;
}
编译
docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk emcc sayhello.cpp -s WASM=1 --shell-file templates/shell_minimal.html -o helloworld.html
将生成的js,wasm,html文件发布到部署到web服务器。
游览器查看结果
JavaScript调用C++函数
这里我们用C++写一个无参函数和一个有两个参数的函数,来展示下如果在JavaScript端使用它们。
C++代码
代码如下(示例):
sayhello.cpp
#include <stdio.h>
#include <iostream>
#include <emscripten/emscripten.h>
using namespace std;
int main(int argc, char ** argv) {
printf("我是printf: Hello World\n");
cout<<"我是C++的cout "<<"你好,世界"<<endl;
return 0;
}
#ifdef __cplusplus
extern "C" {
#endif
void EMSCRIPTEN_KEEPALIVE myFunc1()
{
printf("我的函数已被调用\n");
return;
}
int EMSCRIPTEN_KEEPALIVE myFunc2(int a, int b)
{
printf("a+b=%d\n", a+b);
return a+b;
}
#ifdef __cplusplus
}
#endif
__cplusplus
用于探测是否C++环境
EMSCRIPTEN_KEEPALIVE
是Emscripten特有的宏,用于告知编译器后续函数在优化时必须保留,并且该函数将被导出至JavaScript
编译sayhello.cpp
docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk emcc --std=c++11 sayhello.cpp -s WASM=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']" --shell-file templates/shell_minimal.html -o helloworld2.html
编辑helloworld2.html
给页面增加个按钮来手动触发调用函数。
在body标签内加入
<button class="mybutton">运行我的函数</button>
在script段加入按钮click事件监听。
document.querySelector('.mybutton').addEventListener('click', function(){
alert('检查控制台');
var result = Module.ccall('myFunc1', // name of C function
null, // return type
null, // argument types
null); // arguments
let myfuncResult = Module.ccall('myFunc2', 'number', ['number', 'number'],
[1,2]);
console.log('myFunc2 result = '+myfuncResult);
});
ccall函数签名
var result = Module.ccall(ident, returnType, argTypes, args);
参数:
ident
:C导出函数的函数名(不含“_”下划线前缀);
returnType
:C导出函数的返回值类型,可以为’boolean’、‘number’、‘string’、‘null’,分别表示函数返回值为布尔值、数值、字符串、无返回值;
argTypes
:C导出函数的参数类型的数组。参数类型可以为’number’、‘string’、‘array’,分别代表数值、字符串、数组;
args
:参数数组。
运行结果
总结
以上就是今天要讲的内容,本文仅仅简单介绍了JavaScript调用C++ WASM的使用,而关于Emscripten一些更详细的内容在系列文章其它章节提供(例如:module,编译命令详解,C++调用web api等)。