WebAssembly技术_在Web端运行C与C++程序(ubuntu18.04)

2022-05-27 08:49:06 浏览数 (1)

1. 前言

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

WebAssembly(缩写为 wasm)是一种使用非 JavaScript 代码,并使其在浏览器中运行的方法。这些代码可以是 C、C 或 Rust 等。它们会被编译进你的浏览器,在你的 CPU 上以接近原生的速度运行。这些代码的形式是二进制文件,你可以直接在 JavaScript 中将它们当作模块来用。

WebAssembly不能替代 Javascript,相反,这两种技术是相辅相成的。通过 JavaScript API,你可以将 WebAssembly模块加载到你的页面中。也就是说,你可以通过 WebAssembly来充分利用编译代码的性能,同时保持 JavaScript 的灵活性。

官网介绍: https://www.wasm.com.cn/

2. ubuntu 18.04安装编译器

进行下面步骤前,需要先安装git,cmake 和 python工具。

安装完毕后,确认 git,cmake 和 python 已经在你的环境变量里,可以使用再继续。

ubuntu系统安装比较容易:

代码语言:javascript复制
wbyq@wbyq:~/work_pc/WebAssembly/emsdk$ sudo apt  install cmake
wbyq@wbyq:~/work_pc/WebAssembly/emsdk$ sudo apt  install python
wbyq@wbyq:~/work_pc/WebAssembly/emsdk$ sudo apt  install git

(1)创建工作目录,存放接下来下载的相关文件

代码语言:javascript复制
wbyq@wbyq:~/work_pc$ mkdir WebAssembly
wbyq@wbyq:~/work_pc$ cd WebAssembly/

(2)从仓库克隆项目

代码语言:javascript复制
wbyq@wbyq:~/work_pc/WebAssembly$ git clone https://github.com/emscripten-core/emsdk.git 
正克隆到 'emsdk'...
remote: Enumerating objects: 3138, done.
remote: Total 3138 (delta 0), reused 0 (delta 0), pack-reused 3138
接收对象中: 100% (3138/3138), 1.66 MiB | 174.00 KiB/s, 完成.
处理 delta 中: 100% (2043/2043), 完成.
wbyq@wbyq:~/work_pc/WebAssembly$ ls
emsdk
wbyq@wbyq:~/work_pc/WebAssembly$ cd emsdk/
wbyq@wbyq:~/work_pc/WebAssembly/emsdk$ ls
bazel            emscripten-releases-tags.json  emsdk_env.bat   emsdk_env.ps1        emsdk.ps1                 legacy-emscripten-tags.txt  README.md
docker           emsdk                          emsdk_env.csh   emsdk_env.sh         emsdk.py                  LICENSE                     scripts
emcmdprompt.bat  emsdk.bat                      emsdk_env.fish  emsdk_manifest.json  legacy-binaryen-tags.txt  llvm-tags-64bit.txt         test

(3)安装最新的编译器

代码语言:javascript复制
wbyq@wbyq:~/work_pc/WebAssembly/emsdk$ ./emsdk install latest
Resolving SDK alias 'latest' to '3.1.4'
Resolving SDK version '3.1.4' to 'sdk-releases-upstream-39e60dda6945cfcd6487725bdb1361ae7975173f-64bit'
Installing SDK 'sdk-releases-upstream-39e60dda6945cfcd6487725bdb1361ae7975173f-64bit'..
Installing tool 'node-14.18.2-64bit'..
Error: Downloading URL 'https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/node-v14.18.2-linux-x64.tar.xz': <urlopen error unknown url type: https>
Warning: Possibly SSL/TLS issue. Update or install Python SSL root certificates (2048-bit or greater) supplied in Python folder or https://pypi.org/project/certifi/ and try again.
error: installation failed!

搭建环境过程中的会经历的正常流程。。。。。。

文件无法下载,那么接下来就手动下载文件。

(4)创建zips目录,这个目录存放接下来手动下载的软件压缩包,手动将所有需要的包都下载好了,再次运行 ./emsdk install latest命令即可自动解压安装。

代码语言:javascript复制
wbyq@wbyq:~/work_pc/WebAssembly/emsdk$ mkdir zips

(5)修改emsdk.py 文件

emsdk.py 里存放的就是文件下载代码,需要把下载部分代码屏蔽掉,打印出下载的url地址,然后自己使用wget命令手动下载,下载之后将文件放到zips目录下。

代码语言:javascript复制
wbyq@wbyq:~/work_pc/WebAssembly/emsdk$ gedit emsdk.py 

修改后的文件:

(6)接下来陆续的下载文件

先执行./emsdk install latest命令,会报错并提示输出下载地址,得到下载地址使用wget手动下载,下载后将压缩包放到zips目录下,然后继续执行./emsdk install latest命令,又会有新的下载地址提示,然后一直持续到所有包都下载安装完毕, 也就是./emsdk install latest命令成功运行不再报错就完成了。

代码语言:javascript复制
wbyq@wbyq:~/work_pc/WebAssembly/emsdk$ wget https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/node-v14.18.2-linux-x64.tar.xz
--2022-02-17 15:25:06--  https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/node-v14.18.2-linux-x64.tar.xz
正在解析主机 storage.googleapis.com (storage.googleapis.com)... 142.251.43.16, 172.217.163.48, 172.217.160.80, ...
正在连接 storage.googleapis.com (storage.googleapis.com)|142.251.43.16|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度: 21848416 (21M) [application/x-tar]
正在保存至: “node-v14.18.2-linux-x64.tar.xz”

node-v14.18.2-linux-x64.tar.xz         100%[=========================================================================>]  20.84M  9.16MB/s    用时 2.3s  

2022-02-17 15:25:09 (9.16 MB/s) - 已保存 “node-v14.18.2-linux-x64.tar.xz” [21848416/21848416])

wbyq@wbyq:~/work_pc/WebAssembly/emsdk$ mv node-v14.18.2-linux-x64.tar.xz zips/
wbyq@wbyq:~/work_pc/WebAssembly/emsdk$ ./emsdk install latest
Resolving SDK alias 'latest' to '3.1.4'
Resolving SDK version '3.1.4' to 'sdk-releases-upstream-39e60dda6945cfcd6487725bdb1361ae7975173f-64bit'
Installing SDK 'sdk-releases-upstream-39e60dda6945cfcd6487725bdb1361ae7975173f-64bit'..
Skipped installing node-14.18.2-64bit, already installed.
Installing tool 'releases-upstream-39e60dda6945cfcd6487725bdb1361ae7975173f-64bit'..
--------------------------------------------------------

https://storage.googleapis.com/webassembly/emscripten-releases-builds/linux/39e60dda6945cfcd6487725bdb1361ae7975173f/wasm-binaries.tbz2
--------------------------------------------------------

Unpacking '/home/wbyq/work_pc/WebAssembly/emsdk/zips/39e60dda6945cfcd6487725bdb1361ae7975173f-wasm-binaries.tbz2' to '/home/wbyq/work_pc/WebAssembly/emsdk/upstream'
tar: /home/wbyq/work_pc/WebAssembly/emsdk/zips/39e60dda6945cfcd6487725bdb1361ae7975173f-wasm-binaries.tbz2:无法 open: 没有那个文件或目录
tar: Error is not recoverable: exiting now
['tar', '-xf', '/home/wbyq/work_pc/WebAssembly/emsdk/zips/39e60dda6945cfcd6487725bdb1361ae7975173f-wasm-binaries.tbz2', '--strip', '1'] failed with error code 2!
error: installation failed!

注意,有些包下载下来的名称与安装使用的名称对不上,导致安装失败,需要重新根据提示命名就能解决。

(7)激活SDK

代码语言:javascript复制
wbyq@wbyq:~/work_pc/WebAssembly/emsdk$ ./emsdk activate latest

(8)生效环境变量

代码语言:javascript复制
wbyq@wbyq:~/work_pc/WebAssembly/emsdk$ source emsdk_env.sh

该命令只能在当前终端生效,可以将命令加到etc/profile里,重启系统全局生效。

3. 编写C/C 代码测试

下面编写一个C语言代码,导出函数接口,给前端JS调用测试。

(1)编写简单的C代码,提供1个测试函数

代码语言:javascript复制
int square(int x) 
{
  return x * x;
}

(2)编译测试

代码语言:javascript复制
emcc ./app.c -Os -s WASM=1 -s SIDE_MODULE=1 -o ./app.wasm

(3)编写js文件调用测试。名称设置为:loader.js,因为下面HTML文件里引用的名称叫loader.js,也可以改成别的。

代码语言:javascript复制
function loadWebAssembly(filename, imports = {}) {
  return fetch(filename)
    .then(response => response.arrayBuffer())
    .then(buffer => {
      imports.env = imports.env || {}
      Object.assign(imports.env, {
        memoryBase: 0,
        tableBase: 0,
        __memory_base: 0,
        __table_base: 0,
        memory: new WebAssembly.Memory({ initial: 256, maximum: 256 }),
        table: new WebAssembly.Table({ initial: 0, maximum: 0, element: 'anyfunc' })
      })
      return WebAssembly.instantiate(buffer, imports)
    })
    .then(result => result.instance )
}

function loadJS (url, imports = {}) {
  return fetch(url)
    .then(response => response.text())
    .then(code => new Function('imports', `return (${code})()`))
    .then(factory => ({ exports: factory(imports) }))
}

(4)编写一个HTML文件。名称设置为: index.html

代码语言:javascript复制
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Compile C to WebAssembly</title>
  <meta name="apple-mobile-web-app-capable" content="yes" />
  <meta name="apple-mobile-web-app-status-bar-style" content="black" />
  <meta name="apple-touch-fullscreen" content="yes" />
  <meta name="format-detection" content="telephone=no, email=no" />
  <script src="./loader.js"></script>
</head>

<body>
  <h1>Compile C to WebAssembly</h1>
  <p>The test result can be found in console.</p>

  <script>
    loadWebAssembly('./app.wasm')
      .then(instance => {
        const square = instance.exports.square

        console.log('2^2 =', square(2))
        console.log('3^2 =', square(3))
        console.log('(2   5)^2 =', square(2   5))
      })
  </script>
</body>
</html>

(5)启动HTTP服务器

代码语言:javascript复制
python -m http.server

(6)打开浏览器访问

按下F12,查看控制台的输出。

代码语言:javascript复制
http://127.0.0.1:8000/index.html

0 人点赞