如何将C/C++代码转成webassembly
创始人
2024-03-16 05:03:42
0

 概述

   WebAssembly/wasm WebAssembly 或者 wasm 是一个可移植、体积小、加载快并且兼容 Web 的全新格式

    官网 : WebAssembly

    快速上手: I want to… - WebAssemblyhttps://webassembly.org/getting-started/developers-guide/

      其实官网写的很详细,直接按照步骤学习应该是没有问题,以下是笔者经过实际操作总结下来可以跑通的经验,分享给读者。

   笔者的环境:win10 + VSCode

   把C/C++代码编译成WASM从而可以在浏览器或Nodejs运行时里跑,能解决性能瓶颈问题,特别是CPU密集型运算可以放在C/C++代码里实现。

 

安装Emscripten SDK (简称emsdk)   

   (笔者安装时版本为v3.1.22)

git clone https://gitee.com/openeuler-graphics/emsdk.git

   注:官方github的代码下载太慢,我用了国内的一个克隆镜像 

 命令行窗口进入下载好的目录emsdk

git checkout main.\emsdk install latest

 执行后会出现如下提示,会自动安装node,python,java等工具 

 .\emsdk install latest
Resolving SDK alias 'latest' to '3.1.22'
Resolving SDK version '3.1.22' to 'sdk-releases-upstream-990cee04a21caafc75955d736fb45791a7f2aeee-64bit'
Installing SDK 'sdk-releases-upstream-990cee04a21caafc75955d736fb45791a7f2aeee-64bit'..
Installing tool 'node-14.18.2-64bit'..
Downloading: C:/data/develop/emsdk/zips/node-v14.18.2-win-x64.zip from https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/node-v14.18.2-win-x64.zip, 30570907 Bytes
 [----------------------------------------------------------------------------]
Unpacking 'C:/data/develop/emsdk/zips/node-v14.18.2-win-x64.zip' to 'C:/data/develop/emsdk/node/14.18.2_64bit'
Done installing tool 'node-14.18.2-64bit'.
Installing tool 'python-3.9.2-nuget-64bit'..
Downloading: C:/data/develop/emsdk/zips/python-3.9.2-4-amd64+pywin32.zip from https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/python-3.9.2-4-amd64+pywin32.zip, 14413267 Bytes
 [----------------------------------------------------------------------------]
Unpacking 'C:/data/develop/emsdk/zips/python-3.9.2-4-amd64+pywin32.zip' to 'C:/data/develop/emsdk/python/3.9.2-nuget_64bit'
Done installing tool 'python-3.9.2-nuget-64bit'.
Installing tool 'java-8.152-64bit'..
Downloading: C:/data/develop/emsdk/zips/portable_jre_8_update_152_64bit.zip from https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/portable_jre_8_update_152_64bit.zip, 69241499 Bytes
 [----------------------------------------------------------------------------]
Unpacking 'C:/data/develop/emsdk/zips/portable_jre_8_update_152_64bit.zip' to 'C:/data/develop/emsdk/java/8.152_64bit'
Done installing tool 'java-8.152-64bit'.
Installing tool 'releases-upstream-990cee04a21caafc75955d736fb45791a7f2aeee-64bit'..
Downloading: C:/data/develop/emsdk/zips/990cee04a21caafc75955d736fb45791a7f2aeee-wasm-binaries.zip from https://storage.googleapis.com/webassembly/emscripten-releases-builds/win/990cee04a21caafc75955d736fb45791a7f2aeee/wasm-binaries.zip, 422789188 Bytes
 [----------------------------------------------------------------------------]
Unpacking 'C:/data/develop/emsdk/zips/990cee04a21caafc75955d736fb45791a7f2aeee-wasm-binaries.zip' to 'C:/data/develop/emsdk/upstream'
Done installing tool 'releases-upstream-990cee04a21caafc75955d736fb45791a7f2aeee-64bit'.
Done installing SDK 'sdk-releases-upstream-990cee04a21caafc75955d736fb45791a7f2aeee-64bit'.

激活sdk 

emsdk activate latest

The changes made to environment variables only apply to the currently running shell instance. Use the 'emsdk_env.bat' to re-enter this environment later, or if you'd like to register this environment permanently, rerun this command with the option --permanent.
Resolving SDK alias 'latest' to '3.1.22'
Resolving SDK version '3.1.22' to 'sdk-releases-upstream-990cee04a21caafc75955d736fb45791a7f2aeee-64bit'
Setting the following tools as active:
   node-14.18.2-64bit
   python-3.9.2-nuget-64bit
   java-8.152-64bit
   releases-upstream-990cee04a21caafc75955d736fb45791a7f2aeee-64bit

设置环境变量 

emsdk_env.bat

 双击脚本“emcmdprompt.bat" 建立emsdk运行环境

Setting up EMSDK environment (suppress these messages with EMSDK_QUIET=1)
Adding directories to PATH:
PATH += C:\data\private\develop\emsdk
PATH += C:\data\private\develop\emsdk\upstream\emscripten
PATH += C:\data\private\develop\emsdk\node\14.18.2_64bit\bin

Setting environment variables:
PATH = C:\data\develop\emsdk;C:\data\private\develop\emsdk\upstream\emscripten;C:\data\private\develop\emsdk\node\14.18.2_64bit\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Git\cmd;C:\Program Files\TortoiseGit\bin;C:\Users\DELL\AppData\Local\Programs\Python\Python311\Scripts\;C:\Users\DELL\AppData\Local\Programs\Python\Python311\;C:\Users\DELL\AppData\Local\Microsoft\WindowsApps;C:\Program Files\Nodejs\node-v16.18.1-win-x64;;C:\Users\DELL\AppData\Local\Programs\Microsoft VS Code\bin
EMSDK = C:/data/develop/emsdk
EM_CONFIG = C:\data\develop\emsdk\.emscripten
EMSDK_NODE = C:\data\develop\emsdk\node\14.18.2_64bit\bin\node.exe
EMSDK_PYTHON = C:\data\develop\emsdk\python\3.9.2-nuget_64bit\python.exe
JAVA_HOME = C:\data\develop\emsdk\java\8.152_64bit
Clearing existing environment variable: EMSDK_PY

输入

emcc -v

出现如下提示表示emscripten环境已经安装好了 

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.22 (a9981ae2a7dc3c45f833d0b2202f739d87ac05c8)
clang version 16.0.0 (https://github.com/llvm/llvm-project 8491d01cc385d08b8b4f5dd097239ea0009ddc63)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: C:\data\develop\emsdk\upstream\bin

编译C/C++代码为WASM

新建一个C代码文件hello.c, 代码如下

#include int main() {printf("Hello World\n");return 0;
}

 双击脚本“emcmdprompt.bat" 进入emsdk运行环境命令行,目录切换到C代码路径下,运行命令如下:

emcc hello.c -o hello.html

 执行成功后,生成如下文件

为了测试这个wasm,我们需要部署到一个web服务里,笔者使用nodejs和koa作为web框架来发布,新建代码文件index.js,代码如下:

const Koa = require("koa");
const static = require("koa-static");
const path = require('path');
const app = new Koa();//static file
app.use(static(path.join(__dirname, "/static/"), {maxage: 10080000,})
);app.use((ctx) => {console.log(`Not Found:${ctx.URL}`);ctx.throw(404);
});const port = 3000;
app.listen(port, () => {console.log(`web app started, listening at ${port}`);
});

将刚才hello.wasm,hello.html,hello.js三个文件复制到static目录下,运行node index.js

在浏览器里输入地址: http://127.0.0.1:3000/hello.html,可看到如下页面

实际上hello.js做了一层代码封装,使用了变量Module作为wasm的对象代理,具体细节读者不妨自行研究其代码。

 

JS调用C函数

新建hello2.c文件,内容如下

#include 
#include int main() {printf("Hello World\n");return 0;
}#ifdef __cplusplus
#define EXTERN extern "C"
#else
#define EXTERN
#endifEXTERN EMSCRIPTEN_KEEPALIVE void myFunction(int argc, char ** argv) {printf("MyFunction Called\n");
}

  双击脚本“emcmdprompt.bat" 进入emsdk运行环境命令行,目录切换到C代码路径下,运行命令如下:

emcc hello2.c -o hello2.html -s "EXPORTED_RUNTIME_METHODS=['ccall']"

 此处第一次编译会消耗较长时间,需耐心等待。

 编译成功后,将hello2.html,hello2.js,hello2.wasm文件拷贝nodejs代码的static目录下

 将hello2.html文件做下修改,修改如下

      ............Module.setStatus('Downloading...');window.onerror = function(event) {// TODO: do not warn on ok events like simulating an infinite loop or exitStatusModule.setStatus('Exception thrown, see JavaScript console');spinnerElement.style.display = 'none';Module.setStatus = function(text) {if (text) console.error('[post-exception status] ' + text);};};var myFunc = () => {alert("check console");const result = Module.ccall("myFunction", // name of C functionnull, // return typenull, // argument typesnull // arguments);};Module.postRun.push(myFunc);

 启动nodejs, 在浏览器输入地址:http://127.0.0.1:3000/hello2.html

打开控制台,可以看到C函数MyFunction被调用了。

 为方便读者学习,示例代码放到了下面链接

wasm_cpp_demo: 将C/C++转成webassembly的示例

参考:

Compiling a New C/C++ Module to WebAssembly - WebAssembly | MDNWhen you've written a new code module in a language like C/C++, you can compile it into WebAssembly using a tool like Emscripten. Let's look at how it works.https://developer.mozilla.org/en-US/docs/WebAssembly/C_to_wasm

 

 

相关内容

热门资讯

美专家:美军若向北京上海扔核弹... 美国向北京、上海扔核武器,中国也不会报复美国本土?这番呓语出自美国国务卿办公室前主任劳伦斯·威尔克森...
泰山队近况:瓦科降薪100万欧... 泰山队的更衣室最近可谓是风起云涌,并非因为大牌球星的加入,而是51岁的西班牙老教练阿韦尔·莫雷诺的到...
泽连斯基:若普京同意停火60天... 当地时间26日,总台记者获悉,乌克兰总统泽连斯基表示,若俄罗斯总统普京同意为期60天的停火,他将把整...
换帅无用!杰克逊25分王俊杰1... 【搜狐体育战报】北京时间12月26日CBA常规赛第6轮,主场作战的宁波町渥以88-79击败浙江稠州金...
原创 保... 演员保剑锋这次没在戏里“黑化”,却在现实中拿起了法律武器。12月26日,其工作室一纸律师声明,宣布已...
塔里-伊森领跑火箭队交易预测!... 随着NBA交易截止日的临近,各支球队的交易传闻如火如荼,而在休斯顿火箭队,塔里-伊森成为了最受关注的...
8分钟进五环、11分钟达四环!... 我市交通基础设施持续扩容升级:京密高速新国展段天北路至安华街主路,及远通桥立交节点改造工程新建南向西...
普京表示“除了顿巴斯其他可以谈... 【文/观察者网 王一】乌克兰总统泽连斯基日前抛出“20点和平计划”草案后,外界议论纷纷,普遍认为该方...
多国考虑效仿澳大利亚!德国数字... 德国媒体26日报道,德国数字化和国家现代化部长卡斯滕·维尔德贝格尔对本国效仿澳大利亚实施未成年人社交...
金证股份(600446)披露拟... 截至2025年12月26日收盘,金证股份(600446)报收于15.75元,较前一交易日下跌0.19...