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
命令即可自动解压安装。
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
命令成功运行不再报错就完成了。
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