【备忘干货】c/c++ (wasm)和js互相调用记录

news2025/1/12 11:58:45

c/c++(wasm)和js互相调用记录

  • 废话 :)
  • 准备工作:安装Emscripten
  • 初探:C++(wasm)之hello world
  • 进一步探究:接口调用
    • 1.js调用c++,一些基本类型的传递(char*,int,float)以及返回值
    • 2.js向c++注入函数,c++调用js方法
    • 3.wasm大工程代码如何管理和编译
  • 结语


废话 😃

WebAssembly(缩写 Wasm)是基于堆栈虚拟机的二进制指令格式。Wasm为了一个可移植的目标而设计的,可用于编译C/C++/rust/go等语言,使客户端和服务器应用程序能够在Web上部署。
wasm的一些优势:
1.可以使用 C/C++、rust、go等语言编写代码,性能优越;
2.二进制文件,文本占用的存储空间更小;
3.安全 和 JS 有相同的沙盒环境和安全策略,比如同源策略;
4.绝大多数主流浏览器支持。


准备工作:安装Emscripten

要把C/C++代码编译成wasm,就需要一个工具链,这里使用的是比较主流的Emscripten。(本文测试环境是winows11环境
1.安装Emscripten工具链:
官网连接:https://emscripten.org

# Get the emsdk repo
git clone https://github.com/emscripten-core/emsdk.git

# Enter that directory
cd emsdk
# Fetch the latest version of the emsdk (not needed the first time you clone)
git pull

# Download and install the latest SDK tools.
./emsdk install latest

# Make the "latest" SDK "active" for the current user. (writes .emscripten file)
./emsdk activate latest

# Activate PATH and other environment variables in the current terminal
source ./emsdk_env.sh

注意:如果是Windows系统 用 emsdk.bat 代替 ./emsdk, and emsdk_env.bat 代替source ./emsdk_env.sh

安装过程会自动下载python,nodejs,java和clang编译器。如果碰到卡住或者报错就是网络问题,可能要采取“科学上网”才能安装完成。

执行完emsdk_env.bat后,就可以进行安装完成验证:emcc -v
需要注意的是emsdk_env.bat只对本终端生效,如果不想每次执行,可以把emsdk相关的路径声明到系统环境变量,不过系统之前若安装过python,nodejs也有可能产生冲突。具体看自己环境情况而定。

在这里插入图片描述


初探:C++(wasm)之hello world

严格来说以下实例是C接口的函数导出调用, 然后借助c接口调用c++方法。事实上能导出c接口了那么意味着我们就可以在c接口里面去实例化C++类和结构,然后再通过导出的C接口调用C++类里面的方法。

当然Emscripten其实还提供了另外2种绑定方式embind和WebIDL Binder,可以直接将c++类绑定到js进行调用,这里就不再做详细探讨。

1.首先需要编写C++代码,并确保代码可以在本地进行编译和测试

#include <iostream>

int main(int argc, char ** argv)
{
    std::cout << "Hello World, hello WASM!\n";
	return 0;
}
  1. 使用Emscripten编译C++代码,将代码编译成WebAssembly二进制文件,具体文件路径根据自己而定。
em++ C:\Users\003\Desktop\wasm\wasmdemo.cpp -s WASM=1 -o C:\Users\003\Desktop\wasm\wasmdemo.html

在这里插入图片描述
成功的生成了3个文件:html,js,wasm
在这里插入图片描述
这里-o是指定输出文件,指定不同输出得到文件不一样:

参数输出
-o xx.htmlxx.html, xx.js, xx.wasm
-o xx.jsxx.js, xx.wasm
-o xx.wasmxx.wasm

3.测试一下html加载wasm的运行效果
首先先开启http代理服务,不能直接去打开这个html:

emrun --no_browser --port 8080 C:\Users\003\Desktop\wasm\wasmdemo.html

然后再浏览器输入:http://localhost:8080/wasmdemo.html
毫无意外的成功显示出c++代码中的打印。。。Hello World, hello WASM
在这里插入图片描述

进一步探究:接口调用

1.js调用c++,一些基本类型的传递(char*,int,float)以及返回值

wasmdemo.h头文件

#ifndef __WASM_DEMO__
#define __WASM_DEMO__
#include <emscripten.h>

#if defined(__cplusplus)
#define WASM_API(rettype) extern "C" rettype EMSCRIPTEN_KEEPALIVE
#else
#define WASM_API(rettype) rettype EMSCRIPTEN_KEEPALIVE
#endif

WASM_API(int) mathAdd(int a, int b);

WASM_API(int) str2Num(char* str1);

WASM_API(float) mathMulti(float a, float b);

#endif

wasmdemo.cpp源文件

#include "wasmdemo.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>

int mathAdd(int a, int b)
{
    return (a+b);
}

//假定是int范围数字
int str2Num(char* str1)
{
    if(str1 == NULL)
        return -INT_MAX;
        
    int num = atoi(str1);
    return num;
}

float mathMulti(float a, float b)
{
    return (a*b);
}

然后编译代码,这里把c标准库里面的malloc和free导出提给给js调用,后续字符串操作需要用到

em++ C:\Users\003\Desktop\wasm\wasmdemo.cpp -s WASM=1 -s EXPORTED_FUNCTIONS="['_malloc','_free']" -o C:\Users\003\Desktop\wasm\wasmdemo.js

新建一个wasmdemo.html

<!doctype html>

<html>
  <head>
    <meta charset="utf-8">
    <title>Wasm:demo</title>
  </head>
  <body>
    <script>
    Module = {};
    Module.onRuntimeInitialized = function() {
		var str = '31415';
        var strBuff = new TextEncoder().encode(str);
        var strPtr = Module._malloc(strBuff.length + 1);
        Module.HEAPU8.set(strBuff, strPtr);
        Module.HEAPU8[strPtr + strBuff.length] = 0;
        console.log('str2Num:', Module._str2Num(strPtr));
        Module._free(strPtr);

		console.log('mathAdd:', Module._mathAdd(250, 250));
		console.log('mathMulti:', Module._mathMulti(3.14, 3.0));
    }
    </script>
    <script src="wasmdemo.js"></script>
  </body>
</html>

这个html调用了cpp文件里面的三个函数并输出运行结果,需要注意的是字符串传递需要在js层预先申请内存,然后传递到cpp
浏览器html执行结果如下:
在这里插入图片描述
既然可以传递char*了,那么其他类型数组的传递也是不在话下了,都是要预先在js申请好内存,然后传递指针,这里就不再进行探究了。

2.js向c++注入函数,c++调用js方法

新建一个js模块wasmapi.js,然后添加函数如下图所示, 并在c++侧加入此函数声明。这样编译之后即可调用jsLogPrint函数。

em++ C:\Users\003\Desktop\wasm\wasmdemo.cpp --js-library C:\Users\003\Desktop\wasm\wasmapi.js -s WASM=1 -s EXPORTED_FUNCTIONS="['_malloc','_free']" -o C:\Users\003\Desktop\wasm\wasmdemo.js

在这里插入图片描述
浏览器执行访问html结果:
在这里插入图片描述

3.wasm大工程代码如何管理和编译

简单的 c++ 项目,可以直接调用 em++将 c++ 编译为 wasm,但是对于大型项目,都是使用 cmake 等构建工具进行构建的。 好消息是 emscripten 很好的和 cmake 进行了集成,我们只需要进行如下替换:

cmake => 替换为 emcmake cmake
make => 替换为 emmake make

编译步骤:

cd build && emcmake ..    
emmake make // 生成xx.a
emcc xx.a -o xx.js // 生成 xx.wasm和lxx.js  

再仔细研究下的话其实直接使用cmake构建也是可以的,通过官方cmake文件可知,只需要加入
-DCMAKE_TOOLCHAIN_FILE=yourpath/cmake/Modules/Platform/Emscripten.cmake

还有一点需注意的是,Unix系cmake集成编译会简单些,如果是windows那么需要额外安装MinGW编译器,笔者尝试过使用VC++编译失败,Emscripten官方cmake文件提示也只有Unix Makefiles和MinGW Makefiles俩种。
在这里插入图片描述

结语

通过本文可对wasm使用过程有一个初步的了解, 但还有很多功能尚未尝试。例如:前面提到的
embind和WebIDL Binder, ccall, cwrap等等。还有一个有趣的东东Qt for WebAssembly,可以把Qt的东西在浏览器上跑包括GUI程序。
好了剩下的交给时间咯 !😃


作者:费码程序猿
欢迎技术交流:QQ:255895056
转载请注明出处,如有不当欢迎指正

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1281864.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

博客访问量到达2万了!

博客访问量到达2万了&#xff01;这也发生的太快了吧&#xff0c;前两天才1万7千访问量&#xff0c;用了平台送的1500的流量券&#xff0c;粉丝从1个&#xff08;N年前的&#xff09;&#xff0c;蹭蹭的往上涨&#xff0c;这也太“假”了吧。关键我也是个菜鸟自学者&#xff0c…

前端组件库开发

通常我们会使用很多组件库&#xff0c;有时候我们会去看源码比如element&#xff0c;antd&#xff0c;然后发现多少是按需导出&#xff0c;和vue.use全局注册&#xff0c;依赖于框架的拓展。 组件库的开发依赖框架的版本和node的版本&#xff0c;这个是需要说明的&#xff0c;然…

Redis--15--缓存穿透 击穿 雪崩

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 缓存穿透 击穿 雪崩运行速度:1 缓存穿透问题描述:如何解决: 2 缓存击穿问题描述:如何解决: 3 缓存雪崩说明:解决方案: 缓存穿透 击穿 雪崩 问题描述: 由于海量的用…

BurpSuite 请求/响应解密插件开发

BurpSuite 请求/响应解密插件开发 本文主要记录如何利用burp官方的新版API即MontoyaApi 写一个请求/响应的解密插件。背景下面是主要的操作步骤&#xff1a;根据上述操作做完之后&#xff0c;生成&#xff0c;然后在burp中加载插件&#xff0c;然后通关抓包看效果&#xff0c;具…

VSCode 中将头文件和头文件函数分离,编译主函数跳出 undefined reference to 的问题解决

VSCode 编写 C &#xff08;.h&#xff0c;.cpp 文件分离&#xff09;代码&#xff0c;编写完成后&#xff0c;编译遇到了编译错误 undefined reference to xxx。 开始还以为使用了 -stdc20 而不能使用 #include “xxx.h" 方式头文件&#xff0c;但仔细一想虽然引入了 im…

Java 不要在父类的构造方法里面调用可以被子类重写的方法

不要在父类的构造方法(代码块)里面调用可以被子类重写的方法 我们从第一天学习Java开始&#xff0c;就对Java的类初始化顺序牢记于心。但是在实际开发过程中&#xff0c;似乎很难能接触这一部分的应用。在这之前&#xff0c;我也认为它只是面试中八股文而已&#xff0c;直到最…

版本依赖冲突问题排查过程记录

问题 开发平台在集成minio时&#xff0c;pom引入了sdk。 <dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.7</version> </dependency>在调用上传文件API时&#xff0c;控制台报错&…

JDK1.8_X64在LINUX下安装

JDK1.8在LINUX下安装步骤&#xff1a; 在/usr/lib/目录下新建jvm文件夹&#xff0c;如果已有jvm文件夹&#xff0c;则将之前的JDK版本删除&#xff0c;即在jvm目录下执行命令&#xff1a;rm–rf *将JDK文件jdk-8u40-linux-x64.gz拷贝到/home/目录下&#xff1b;在/home/目录下…

探索JavaScript BOM:了解浏览器的内部机制和强大的API

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;JavaScript篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来JavaScript篇专栏内容:JavaScript-BOM的概念和常用API BOM的概念和常用API BOM BOM&#xff08;Browser O…

免费网站快速收录工具,2023最新网站收录方法

在当今数字化时代&#xff0c;拥有一个被搜索引擎快速收录的网站对于个人、企业或机构而言至关重要。网站的快速收录意味着更广泛的曝光和更多的访问流量&#xff0c;这对于网络存在的任何实体都是非常有价值的。 网站快速收录的重要性 在庞大的互联网世界中&#xff0c;一切…

精神衰弱怎么办?如何改变精神衰弱?

精神衰弱也叫神经衰弱&#xff0c;跟个人体质有一定的关系&#xff0c;更多是因为环境因素的长期作用所致&#xff0c;比如长期处于紧张和压力之下&#xff0c;这容易产生精神衰弱。当下有个流行词叫“精神内耗”&#xff0c;这个严重的精神内耗其实同样会导致精神衰弱。 精神…

使用Prometheus监控Padavan路由器

Prometheus监控Padavan路由器 1、背景 近期在Synology&#xff08;群辉&#xff09;中安装一套Prometheus监控程序&#xff0c;目前已经监控Synology&#xff0c;然后家中有有路由器&#xff08;Padavan&#xff09;型号&#xff0c;也准备使用PrometheusGrafan进行监控。 ‍…

计算机网络扫盲(4)——时延

一、概述 在这里&#xff0c;我们考虑分组交换网的情况&#xff0c;因特网可以被看成是一种基础设施&#xff0c;该基础设施为运行在端系统上的分布式应用提供服务。在理想情况下&#xff0c;我们希望因特网服务能够在任意两个端系统之间随心所欲地移动数据而没有任何数据地丢失…

智能优化算法应用:基于海洋捕食者算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于海洋捕食者算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于海洋捕食者算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.海洋捕食者算法4.实验参数设定5.算法结果…

已解决:虚拟机集群xsehll连接不上

问题描述&#xff1a; hadoop102能连上&#xff0c;hadoop103、hadoop104无法连接&#xff0c;以前都能连上&#xff0c;今天突然就连不上了 解决方案&#xff1a; 使用ifconfig命令查看有没有ens33 如果没有的话那就证明你的问题和我一样 依次使用以下命令&#xff1a; sys…

Docker 简介,Docker 安装——3

目录&#xff1a; Docker 简介 什么是虚拟化、容器化&#xff1f;为什么要虚拟化、容器化&#xff1f;虚拟化实现方式 应用程序执行环境分层虚拟化常见类别 虚拟机容器JVM 之类的虚拟机常见虚拟化实现 主机虚拟化(虚拟机)实现容器虚拟化实现 容器虚拟化实现原理容器虚拟化基础…

SSM新闻发布管理系统

SSM毕设分享 序号1&#xff1a;SSM新闻发布管理系统 1 项目简介 Hi&#xff0c;各位同学好&#xff0c;这里是郑师兄&#xff01; 今天向大家分享一个毕业设计项目作品【SSM新闻发布管理系统】 师兄根据实现的难度和等级对项目进行评分(最低0分&#xff0c;满分5分) 难度系数…

人工智能发展史

人工智能&#xff08;AI&#xff09;的发展史是一段跨越数十年的旅程&#xff0c;涵盖了从早期理论探索到现代技术革新的广泛内容。人工智能的发展历程展示了从最初的概念探索到现代技术突破的演变。尽管经历了多次起伏&#xff0c;但AI领域持续进步&#xff0c;不断拓展其应用…

unordered_map与unordered_set的实现(含迭代器)

unordered_map与unordered_set的实现 文章目录 unordered_map与unordered_set的实现前言一、问题一HashTable.h 二、问题二&问题三1.封装时如何取出key2.不同类型key如何建立对应关系 三、问题四&问题五问题四问题五 四、实现代码MyUnorderedSet.hMyUnorderedMap.hHash…

C 语言实现TCP 通信,以及地址复用

服务端 #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <arpa/inet.h>int main() {//监听套接字文件描述符int listenFd -1;//连接套接字的文件描述符int connFd -1;//服务器的地址结构st…