- 编写程序c_call_js.c
为了方便函数导出,我们需要先定义一个函数导出宏,该宏需要完成以下功能:
- 使用C风格符号修饰。我们知道,由于引入了多态、重载、模板等特性,C语言环境下的符号修饰策略(既函数、变量在最终编译成果中的名字的生成规则)非常复杂,并且不同的C编译器有着各自的符号修饰策略,如果不做额外处理,我们在C中创建函数的时候,很难预知它在最终编译成果中的名字——这与C语言环境完全不同。因此当我们试图将
main()
函数之外的全局函数导出至JavaScript时,必须强制使用C风格的符号修饰,以保持函数名称在C/C环境以及JavaScript环境中有统一的对应规则。 - 避免函数因为缺乏引用而导致在编译时被优化器删除。如果某个导出函数仅供JavaScript调用,而在C/C++环境中从未被使用,开启某些优化选项(比如
-O2
以上)时,函数有可能被编译器优化删除,因此需要提前告知编译器:该函数必须保留,不能删除,不能改名。 - 为了保持足够的兼容性,宏需要根据不同的环境——原生NativeCode环境与Emscripten环境、纯C环境与C++环境等——自动切换合适的行为。
#ifndef EM_PORT_API//定义EM_PORT_API宏
# if defined(__EMSCRIPTEN__)//探测是否是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)//探测是否是C++环境
# 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()
{
return 42;
}
EM_PORT_API(float) add(float a, float b)
{
return a + b;
}
- 通过命令
emcc c_call_js.c -o c_call_js.js
将c程序编译为wasm - 创建页面c_call_js.html,并在页面中添加调用c程序代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Emscripten:Export1</title>
</head>
<body>
<script>
Module = {};
Module.onRuntimeInitialized = function() {
console.log(Module._show_me_the_answer());
console.log(Module._add(12, 1.0));
}
</script>
<script src="c_call_js.js"></script>
</body>
</html>
- 通过命令
emrun --no_browser --port 8080 文件路径\c_call_js.html
,在开发者页面的控制台查看函数调用结果