乐趣区

关于webassembly:WebAssembly-与-cc

c/c++ 有用宏大的生态 – 海量 c 库。反对 c/c++ 编译到 WebAssembly 意味着开发者能够在 web 端应用这些 c 库。

想想那些新兴语言,在倒退初期,都是间接封装 c 库,以此来欠缺本人的生态,比方 golang 的 cgo。

编译环境

能够应用 Emscripten 来将它编译到 WebAssembly。

Emscripten 环境的装置略微简单一点,如下:

git clone https://github.com/juj/emsdk.git
cd emsdk

# 在 Linux 或者 Mac OS X 上
./emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
./emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit

# 在 Windows 上
emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit

# 留神:Windows 版本的 Visual Studio 2017 曾经被反对,但须要在 emsdk install 须要追加 --vs2017 参数。

留神:–global 标识会让 PATH 变量在全局被设置,所以接下来所关上的终端或者命令行窗口都会被设置。如果您仅仅想让 Emscripten 在以后窗口失效,就删掉这个标识。

不过有另外一种简略办法,间接应用 docker 镜像作为编译环境,省去了咱们配置环境的懊恼。该办法在后面的文章中有用到,如下:

docker run 
  --rm 
  -v `pwd`:`pwd` 
  -w `pwd` 
  -u $(id -u):$(id -g) 
  emscripten/emsdk 
  emcc native/fibonacci.c -o wasm/fibonacci.wasm --no-entry

示例

该示例来自于官网文档,之所以没有抉择相似 hello-world 之类,一是因为之前的文章中,咱们其实有波及到应用 c 编写一个斐波那契数列 wasm,而后在浏览器端应用。二是,该示例是对于 WebP 的,更加能够让大家领会到 c/c++ 如何通过 wasm,促成 web 开发。

让咱们将 WebP 的编码器编译为 wasm。WebP 编解码器的源代码是用 C 编写的,能够在 GitHub 上找到,以及一些扩大的 API 文档。

$ git clone https://github.com/webmproject/libwebp

首先,通过编写一个名为 webp.c的 C 文件将 WebPGetEncoderVersion()encode.h裸露给 JavaScript:

#include "emscripten.h"
#include "src/webp/encode.h"

EMSCRIPTEN_KEEPALIVE
int version() {return WebPGetEncoderVersion();
}

这是一个很好的简略程序,用于测试是否能够编译 libwebp 的源代码,因为它不须要任何参数或简单的数据结构即可调用此函数。

要编译该程序,您须要应用 - I 标记通知编译器在哪里能够找到 libwebp 的头文件,并将须要的所有 libwebp C 文件都传递给编译器。一个有用的策略就是给它所有 C 文件,并依附编译器除去所有不必要的货色:

docker run 
  --rm 
  -v `pwd`:`pwd` 
  -w `pwd` 
  -u $(id -u):$(id -g) 
  emscripten/emsdk 
  emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' 
  -I libwebp 
  webp.c 
  libwebp/src/{dec,dsp,demux,enc,mux,utils}/*.c

编译胜利后,生产如下文件:

  • a.out.js
  • a.out.wasm

须要编写一些 html 和 js 代码,来应用咱们的 webp 了。

<script src="./a.out.js"></script>
<script>
  Module.onRuntimeInitialized = async _ => {
    const api = {version: Module.cwrap('version', 'number', []),
    };
    console.log(api.version());
  };
</script>

运行成果如下:

残缺代码,大家参见谷歌 chrome 示例 repo。官网导出的办法更多。

当然咱们能够加-o version.html — 指定这个选项将会生成 HTML 页面来运行咱们的代码,并且会生成 wasm 模块,以及编译和实例化 wasm 模块所须要的“胶水”js 代码,这样咱们就能够间接在 web 环境中应用了。

论断

通常依赖于 C 的规范库,操作系统,文件系统等。Emscripten 提供了大多数这些性能,然而有一些限度。这些限度包含:

  • Networking — Emscripten 反对 libc 网络性能,然而您必须将本人限度为异步(非阻塞)操作。这是必须的,因为根底 JavaScript 网络性能是异步的。
  • 文件系统 — Emscripten 反对 libc 文件系统性能,并且能够按惯例形式编写 C / C ++ 代码。
    在浏览器环境中运行的代码是沙盒化的,不能间接拜访本地文件系统。相同,Emscripten 创立了一个虚构文件系统,该文件系统能够预加载数据或链接到 URL 以进行提早加载。这会影响何时能够调用同步文件系统性能以及如何编译我的项目。
  • Application Main Loop — 浏览器事件模型应用合作式多任务处理 - 每个事件都有一个“turn”来运行,而后必须将控制权返回给浏览器事件循环,以便能够解决其余事件。HTML 页面挂起的常见起因是 JavaScript 无奈实现,无奈将控制权返回给浏览器。这可能会影响应用有限主循环编写应用程序的形式。
退出移动版