Javascript 长久以来是浏览器能运行到唯一编程语言,随着
wasm
技术出现,c、c++、rust、go等语言也可以运行在浏览器上,而且接近本地程序运行到速度。
本文用两个事例实践,介绍wasm
中C
与JavaScript
的相互调用。
简介
什么是wasm
wasm
是Web的汇编,是为Web浏览器定制的汇编语言。从高级语言编译器角度看,wasm
是目标代码。从浏览器觉度来看,wasm
最终会被编译成平台相关的机器码。说人话:wasm
能被浏览器解释并执行。
高级语言 > IR > 汇编 > 机器码
兼容性
不考虑IE情况下,主流浏览器都支持
事例实践
emscripten/emsdk 使用
需要使用emsdk
把,.cc
/.cpp
代码编译成.wasm
后缀与.js
后缀的文件。
emsdk
自v1.38.1
版本后编译目标默认为wasm
(.wasm
与.js
)
.wasm
为源文件编译后形成的WebAssembly汇编文件.js
是emsdk
生成的胶水代码,包含emscripten
运行环境和.wasm
文件的封装,.html
文件导入.js
后可自动完成.wasm
文件的载入/编译/实例化、运行时初始化等工作。
方法一 emsdk系统环境安装
webassembly.org.cn/getting-sta…
方法二 使用docker容器编译
JavaScript调用C函数
c代码如下,代码中声明并定义了print_int
,print_float
,print_double
三个方法。
//type_conv.cc
#ifndef EM_PORT_API
# if defined(__EMSCRIPTEN__)
# include <emscripten.h>
# 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<stdio.h>
EM_PORT_API(void) print_int(int a) {
printf("C{print_int*( a:%d)}\n", a);
}
EM_PORT_API(void) print_float(float a) {
printf("C{print_int*( a:%f)}\n", a);
}
EM_PORT_API(void) print_double(double a) {
printf("C{print_int*( a:%lf)}\n", a);
}
__EMSCRIPTEN__
用于探测是否 emscripten环境;
__cplusplus
用于探测是否是C++环境;
EMSCRIPTEN_KEEPALIVE
是emscripten
特有宏,用于告知编辑器后续函数在优化时是否保留,并且该函数将被导出至JavaScript环境。
使用emsdk
对.cc
文件进行编译
控制台执行以下指令,生成type_conv.js
文件。
emcc type_conv.cc -o type_conv.js
手动创建type_conv.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>type conv</title>
</head>
<body>
<script> Module = {} Module.onRuntimeInitialized = function() { Module._print_int(3.4) Module._print_int(4.6) Module._print_int(-3.4) Module._print_int(-4.6) Module._print_float(2000000.03125) Module._print_double(2000000.03125) } </script>
<script src="type_conv.js"></script>
</body>
</html>
Module.onRuntimeInitialized
为emscripten
运行时准备就绪时的回调。
此时文件目录如下:
|--"/"
|--"type_conv.cc" // 手动创建
|--"type_conv.js" // emcc 工具生成
|--"type_conv.html" // 手动创建
此时启动静态资源服务并使用浏览器访问type_conv.html
,并查看控制台:
JavaScript
调用c
的函数成功!
JavaScript函数注入C环境
c代码如下,代码中声明了show_me_the_answer
方法,但并没有去定义。
// closure.cc
#ifndef EM_PORT_API
# if defined(__EMSCRIPTEN__)
# include <emscripten.h>
# 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 <stdio.h>
EM_PORT_API(int) show_me_the_answer();
EM_PORT_API(void) func() {
printf("%d\n", show_me_the_answer());
}
创建pkg.js
mergeInto(LibraryManager.library,{
show_me_the_answer: function(){
return jsShowMeTheAnswer();
}
})
LibraryManager.library
可以简单理解为JavaScript
注入C
环境的库。 控制台执行以下指令,生成closure.js
文件与closure.wasm
文件。
emcc closure.cc -—js-library pkg.js -o closure.js
-—js-library pkg.js
表示把pkg.js作为附加库参与链接 手动创建closure.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>hello world</title>
</head>
<body>
<script> function f1(){ var answer = 42; function f2() { return answer; } return f2; } var jsShowMeTheAnswer = f1(); Module = {} Module.onRuntimeInitialized = function() { console.log(`onRuntimeInitialized`) Module._func(); console.log(`onRuntimeInitialized after`) } </script>
<script src="closure.js"></script>
</body>
</html>
此时文件目录如下:
|--"/"
|--"closure.cc" // 手动创建
|--"pkg.js" // 手动创建
|--"closure.js" // emcc 工具生成
|--"closure.wasm" // emcc 工具生成
|--"closure.html" // 手动创建
此时启动静态资源服务并使用浏览器访问closure.html
,并查看控制台:
至此,实现了在C
环境中调用JavaScript
方法show_me_the_answer
总结
使用emscripten/emsdk
- 在
c
中定义EM_PORT_API
宏,用来声明方法,可让JavaScript
去调用对应的方法。 - 在
JavaScript
中可以使用mergeInto
方法,结合emcc -—js-library
参数,把JavaScript
定义的方法注入到c
环境库。
参考书籍
《面向WebAssembly编程 应用开发方法与实践》
《WebAssembly 原理与核心技术》
今天的文章WebAssembly(wasm)中C与JavaScript的相互调用分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/20377.html