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无法完成,无法将控制权返回给浏览器。这可能会影响使用无限主循环编写应用程序的方式。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。