wasm 系列之 WebAssembly 和 emscripten 暴力上手

wasm 是什么?

wasm 是 WebAssembly 的缩写。wasm 不是传统意义上的汇编语言,而是一种编译的中间字节码,可以在浏览器和其他 wasm runtime 上运行非 JavaScript 类型的语言,只要能被编译成 wasm,譬如 kotlin/wasm、Rust/wasm 等。

这是一种高度优化的可执行格式,其运行速度几乎与本机代码一样快,同时具有可移植性和安全性。 Emscripten 通过与 LLVM、 Binaryen、 Closure Compiler 和其他工具的集成,自动为您完成大量优化工作。

耳熟详闻的一个典型成功案例就是 Flutter 编译 Web 端应用,本质就是调用 Skia C++ 库,然后通过 wasm 技术提供了一个 CanvasKit 供 js 端使用。

emscripten 是什么?

Emscripten 是一个完整的 WebAssembly 开源编译器工具链。使用 Emscripten 可以将 C/C++ 代码或使用 LLVM 的任何其他语言编译为 WebAssembly,并在 Web、Node.js 或其他 Wasm 运行时上运行。

实际上,任何可移植的 C/C++ 代码库都可以使用 Emscripten 编译成 WebAssembly,从需要渲染图形、播放声音以及加载和处理文件的高性能游戏,到 Qt 等应用程序框架。 Emscripten 已被用于将一长串现实世界代码库转换为 WebAssembly,其生成小而快速的代码!

emscripten 环境准备

首先我们需要用到 Emscripten。Emscripten 是一个编译器工具链,使用 LLVM 去编译出 wasm。

先通过官网方式安装 Emscripten SDK,不同平台详情参见 https://emscripten.org/docs/getting_started/downloads.html。

# 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# On Windows, run emsdk.bat instead of ./emsdk, and emsdk_env.bat instead of source ./emsdk_env.sh.
# On Windows, if you use the activate command, the step of emsdk_env.bat is optional. If you want to know more, see activate SDK version.

Windows 下执行完emsdk_env.bat后再执行emcc -v有可能提示找不到命令,这时候自己把打印的路径加入环境变量下就行。

编写第一个 wasm 程序

写 wasm 的最流行语言是 Rust 和 C/C++。
C/C++ 的轮子比较丰富,比如 Skia(Canvas 底层调用的库)就是 C++ 写的。可惜的是 C/C++ 没有包管理工具。
而当下最炙手可热的当属 Rust,我不得不说它真的很酷,有包管理工具,工具链也很完善。先选择使用 C/C++ 语言,下一篇再使用 Rust。

在这里插入图片描述
上图可以看到,执行完 emcc 对 c 源代码编译后生成了a.out.jsa.out.wasm两个产物文件。其中 js 文件是胶水代码,用来加载和执行 wasm,因为 wasm 不能直接作为入口文件使用,所以上图 node 命令实际执行的是胶水入口,然后胶水入口调用了 wasm 文件。

我们可以通过 file 命令看下这三个文件类型,如图:

在这里插入图片描述

除过使用 nodejs 环境运行外,我们接下来尝试将上面 wasm 跑在浏览器中。

先确保你本地有 nodejs 环境,并且通过npm -g install http-server安装了方便的 http-server,以便下面启动一个 http 服务器解决无法同源策略加载 wasm 文件的问题。

新建一个 html 文件并引入 wasm 的胶水 js 代码,然后启动服务,如图:

在这里插入图片描述

接着在浏览器打开刚编写的网页可以在控制台看到我们前面在 c 语言中编写的 printf 代码输出,如下:

在这里插入图片描述

我们可以继续看下其网络情况,如下:

在这里插入图片描述

emscripten 用法

上面我们快速使用 emscripten 的 emcc 命令,这里我们可以稍微再看下 emscripten 的其他用法,关于更多 emscripten 用法可以参见官方文档https://emscripten.org/docs/getting_started/Tutorial.html,这里不再赘述。

Generating HTML

我们可以将上面 emcc 编译命令换成emcc test.c -o test.html,然后可以一步到位生成网页,产物如下图:

在这里插入图片描述

接着使用浏览器直接打开 html,而不用我们自己再编写 html 引入 wasm 的胶水代码,如下:

在这里插入图片描述

可以看到我们 c 语言打印的 printf 输出已经出现在网页中了。上面网页其实有两部分,下部分是我们控制台输出的显示,上部分其实是一个 Canvas,我们通过下面例子就能在上面绘制彩色立方体的东西,如下:

#include <stdio.h>
#include <SDL/SDL.h>#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endifint main(int argc, char** argv) {printf("hello, world!\n");SDL_Init(SDL_INIT_VIDEO);SDL_Surface *screen = SDL_SetVideoMode(256, 256, 32, SDL_SWSURFACE);#ifdef TEST_SDL_LOCK_OPTSEM_ASM("SDL.defaults.copyOnLock = false; SDL.defaults.discardOnLock = true; SDL.defaults.opaqueFrontBuffer = false;");
#endifif (SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);for (int i = 0; i < 256; i++) {for (int j = 0; j < 256; j++) {
#ifdef TEST_SDL_LOCK_OPTS// Alpha behaves like in the browser, so write proper opaque pixels.int alpha = 255;
#else// To emulate native behavior with blitting to screen, alpha component is ignored. Test that it is so by outputting// data (and testing that it does get discarded)int alpha = (i+j) % 255;
#endif*((Uint32*)screen->pixels + i * 256 + j) = SDL_MapRGBA(screen->format, i, j, 255-i, alpha);}}if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);SDL_Flip(screen);printf("you should see a smoothly-colored square - no sharp lines but the square borders!\n");printf("and here is some text that should be HTML-friendly: amp: |&| double-quote: |\"| quote: |'| less-than, greater-than, html-like tags: |<cheez></cheez>|\nanother line.\n");SDL_Quit();return 0;
}

上面官方例子的代码位于https://github.com/emscripten-core/emscripten/blob/main/test/hello_world_sdl.cpp。

我们通过emcc hello_world_sdl.cpp -o hello.html编译然后浏览器打开产物网页,如下:

在这里插入图片描述

官方还有很多 Canvas 有趣例子,自己可以探索一下。

Using files

先放官方文档这句最重要的话:

Your C/C++ code can access files using the normal libc stdio API (fopen, fclose, etc.)

JavaScript 通常在 web 浏览器的沙盒环境中运行,不直接访问本地文件系统。Emscripten模拟了一个虚拟的文件系统使得我们可以使用普通的 libc stdio API。我们要访问的文件应该预加载或嵌入到这个虚拟文件系统中。

官方文件系统架构机制如下图:

在这里插入图片描述

我们来看一段名叫hello_world_file.cpp的 cpp 代码:

#include <stdio.h>int main() {FILE *file = fopen("hello_world_file.txt", "rb");if (!file) {printf("cannot open file\n");return 1;}while (!feof(file)) {char c = fgetc(file);if (c != EOF) {putchar(c);}}fclose (file);return 0;
}

官方这个例子的源码位于https://github.com/emscripten-core/emscripten/blob/main/test/hello_world_file.cpp。

下面的命令用于指定要在运行编译后的代码之前先预加载到 Emscripten 的虚拟文件系统中的数据文件。这种方法很有用,因为浏览器只能从网络异步加载数据(Web Workers除外),而许多本机代码使用同步文件系统访问。

emcc hello_world_file.cpp -o hello.html --preload-file hello_world_file.txt

在这里插入图片描述

运行效果如下:

在这里插入图片描述

Optimizing code

与gcc和clang一样,Emscripten在默认情况下生成未优化的代码。你可以使用- 01命令行参数生成稍微优化的代码:

emcc -O1 test/hello_world.cpp

还有其他-O2-O3-Og-Os-Oz等都和 clang 等一样的含义,不再赘述。

总结

到此我们算是入门了 wasm(WebAssembly) 和 emscripten,其他高级进阶请关注和作者链接等待更新,欢迎期待~

在这里插入图片描述

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

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

相关文章

IOS恢复

1、实验目的 通过本实验可以掌握&#xff1a; copy方式恢复IOS的步骤。TFTPDNLD方式恢复IOS的步骤。Xmodem方式恢复IOS的步骤。 2、实验拓扑 路由器IOS恢复的实验拓扑如下图所示。 3、实验步骤 如果工作中不慎误删除路由器IOS&#xff0c;或者升级了错误版本的IOS&#xff…

Https协议原理剖析【计算机网络】【三种加密方法 | CA证书 】

目录 一&#xff0c;fidler工具 前提知识 二&#xff0c;Https原理解析 1. 中间人攻击 2. 常见的加密方式 1&#xff09;. 对称加密 2&#xff09;. 非对称加密 对称加密 4&#xff09;. CA证书 1. 数据摘要 3. 数字签名 CA证书 理解数据签名 存在的安全疑问&am…

js基础知识(2)

一、事件的含义 JavaScript事件是指在文档或者浏览器中发生的一些特定交互瞬间&#xff0c;比如打开某一个网页&#xff0c;浏览器加载完成后会触发load事件&#xff0c;当鼠标悬浮于某一个元素上时会触发hover事件&#xff0c;当鼠标点击某一个元素时会触发click事件等等。 三…

在PostgreSQL中如何处理跨表的级联删除和更新?

文章目录 解决方案1. 使用外键约束和级联操作创建外键约束并指定级联删除创建外键约束并指定级联更新 2. 使用触发器&#xff08;Triggers&#xff09;创建触发器实现级联删除 示例代码示例1&#xff1a;使用外键约束和级联删除示例2&#xff1a;使用触发器实现级联删除 在Post…

Golang | Leetcode Golang题解之第44题通配符匹配

题目&#xff1a; 题解&#xff1a; func isMatch(s string, p string) bool {for len(s) > 0 && len(p) > 0 && p[len(p)-1] ! * {if charMatch(s[len(s)-1], p[len(p)-1]) {s s[:len(s)-1]p p[:len(p)-1]} else {return false}}if len(p) 0 {retur…

输入influx但是无法进入influxdb

问题描述&#xff1a; 博主想通过DockerJmeterInfluxDBGrafana搭建性能测试可视化平台&#xff0c;但是按照别的教程输入influx却无法进入inluxdb&#xff0c;输入输出如下&#xff1a; NAME:influx - Influx ClientUSAGE:influx [command]HINT: If you are looking for the I…

Linux下的进程管理:创建、终止、切换与等待

文章目录 一、引言二、进程创建1、进程创建的概念与场景2、进程创建的方式a、fork() 系统调用b、fork() 后的执行流程 3、进程创建的过程a、进程创建过程b、子进程创建过程 4、父子进程关系与属性继承 三、进程终止1、进程终止的原因2、进程的错误码和退出码a、错误码b、退出码…

LeetCode:51. N 皇后

leetCode51.N皇后 题解分析 代码 class Solution { public:int n;vector<vector<string>> ans;vector<string> path;vector<bool> col, dg,udg;vector<vector<string>> solveNQueens(int _n) {n _n;col vector<bool> (n);dg …

《QT实用小工具·四十二》圆形发光图像

1、概述 源码放在文章末尾 该项目实现了图像的发光效果&#xff0c;特别适合做头像&#xff0c;项目demo演示如下所示&#xff1a; 项目部分代码如下所示&#xff1a; import QtQuick 2.7 import QtGraphicalEffects 1.12Item {id: rootwidth: 80height: 80property int ra…

浓眉大眼的Apple开源OpenELM模型;IDM-VTON试衣抱抱脸免费使用;先进的语音技术,能够轻松克隆任何人的声音

✨ 1: openelm OpenELM是苹果机器学习研究团队发布的高效开源语言模型家族 OpenELM是苹果机器学习研究团队开发的一种高效的语言模型&#xff0c;旨在推动开放研究、确保结果的可信赖性、允许对数据和模型偏见以及潜在风险进行调查。其特色在于采用了一种分层缩放策略&#x…

spring基本使用

文章目录 1. ioc(Inversion of Control) | DI(Dependency Injection)(1) maven坐标导包(2) 编写配置文件bean.xml(3) 配置bean(4) 配置文件注入属性 2. DI(dependency injection) 依赖注入(setter)其他属性(1) 对象属性注入(2) 数组属性输入(3) 集合属性注入(4) map集合注入(5)…

如何提交已暂存的更改到本地仓库?

文章目录 如何提交已暂存的更改到本地Git仓库&#xff1f;步骤1&#xff1a;确认并暂存更改步骤2&#xff1a;提交暂存的更改到本地仓库 如何提交已暂存的更改到本地Git仓库&#xff1f; 在Git版本控制系统中&#xff0c;当你对项目文件进行修改后&#xff0c;首先需要将这些更…

TCP协议数据传输过程及报文分析

目录 TCP数据的传输过程 建立连接&#xff08;三次握手&#xff09; 第一次握手 第二次握手 第三次握手 总结 数据传输 断开连接&#xff08;四次挥手&#xff09; 第一次挥手 第二次挥手 第三次挥手 第四次挥手 总结 最后 TCP数据的传输过程 TCP&#xff08;Tra…

SL3043耐压120V降压恒压 降48V 降24V 降12V 降5V 大电流10V芯片

SL3043是一款外驱MOSFET管可设定输出电流的降压型开关稳压器&#xff0c;具有以下特点&#xff1a; 1. 宽工作电压范围&#xff1a;SL3043可以在10V至120V的宽输入电压范围内工作&#xff0c;这使得它适用于多种不同的电源环境。 2. 大输出电流&#xff1a;该芯片能够提供最大…

五年Python从业者,谈谈Python的一些优缺点

前言 Python它是作为年轻的血液&#xff0c;融入到编程语言这个大家庭里面&#xff0c;作为具有年轻人的蓬勃朝气的python&#xff0c;那它同时就会有年轻人的桀骜焦躁。 今天就来谈谈Python的一些优缺点。 先从优点说起&#xff0c;我是把它分为5部分。 1.简单————Pyth…

Win11和WinRAR取消折叠菜单恢复经典菜单

这里写目录标题 前言1. Win11恢复经典右键菜单1.1 修改前1.2 恢复成经典右键菜单1.3 修改后1.4 想恢复怎么办&#xff1f; 2. WinRAR取消折叠菜单恢复经典菜单2.1 修改前2.2 修改恢复为经典菜单2.3 修改后2.4 想恢复怎么办&#xff1f; 前言 最近换回了Windows电脑&#xff0c…

大模型微调之 使用 LLaMA-Factory 微调 Llama3

大模型微调之 使用 LLaMA-Factory 微调 Llama3 使用 LLaMA Factory 微调 Llama-3 中文对话模型 安装 LLaMA Factory 依赖 %cd /content/ %rm -rf LLaMA-Factory !git clone https://github.com/hiyouga/LLaMA-Factory.git %cd LLaMA-Factory %ls !pip install "unsloth…

在Spring Boot应用中实现阿里云短信功能的整合

1.程序员必备程序网站 天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 2.导入坐标 <dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>4.5.0</version></dependency><…

Redis面试题二(数据存储)

目录 1.redis 的数据过期策略 1. 惰性删除&#xff08;Lazy Expiration&#xff09; 2. 定期删除&#xff08;Periodic Expiration&#xff09; 3. 定时删除&#xff08;Timing-Based Expiration&#xff09; 实际应用中的组合策略 2.redis 有哪些内存淘汰机制 volatile&…

GhostNetV3:探索紧凑模型的训练策略

文章目录 摘要1、引言2、相关工作2.1、紧凑模型2.2、训练CNN的技巧包 3、预备知识4、训练策略4.1、重参数化4.2、知识蒸馏4.3、学习调度4.4、数据增强 5、实验结果5.1、重参数化5.2、知识蒸馏5.3、学习策略5.4、数据增强5.5、与其他紧凑模型的比较5.6、扩展到目标检测 6、结论 …