《WebAssembly 权威指南》(6)在浏览器中运行遗留代码


译者注:这篇文章是《WebAssembly 权威指南》一书的第六章,介绍了如何使用 WebAssembly 在浏览器中运行遗留代码,即已经存在的 C/C++ 代码库。文章以一个实际的例子,即使用 Emscripten 工具将 C++ 代码编译为 WebAssembly 模块,并在浏览器中使用 JavaScript 调用它。文章详细说明了 Emscripten 的工作原理、编译选项、运行时环境和调试方法。

现在,我们再仔细地看看在浏览器中调用 C/C++ 代码的过程。大多数编程语言的代码都不是为了在浏览器中以下载的形式运行。但是,正如香港骑士(译者注:The Hong Kong Cavaliers,电影《天生爱神》中的主角 Buckaroo Banzai 的乐队名称)的队长那样,偶尔你会发现自己出现在某个意想不到的新地方,而那里只有你。

我们对在浏览器中调用 C/C++ 代码感兴趣的原因是多方面的。但取代 JavaScript 并不是其中之一。至少对大多数人来说不是。相反,我们有大量的用 C 和 C++ 等语言编写的遗留代码。其中有很多是非常有用的,如果能在我们的网络应用程序中使用这些代码,那就太好了。其中一些可能是将组织与遗留系统联系在一起的。能够通过浏览器分发这些代码将是一个很大的进步。

此外,有些问题根本不适合用 JavaScript 来写。可以用另一种语言来编写应用程序的这一部分,而不需要一个单独的运行时,这是非常吸引人的。而且,正如我们的最后一个用例所表明的那样,对于敏感和棘手的软件(如加密算法)来说,有来自可信来源的可信代码提供证明才是有价值的。能够简单地重新编译来自你所认识的人的现有代码,他们知道自己在做什么,这也是一种有用的能力。

在上一章中,我们展示了使用常规的支持 WebAssembly 的 C 编译器(如 clang)和一些头和库的依赖性管理来实现基本的集成是可能的。然而,必须提供我们自己的标准库版本,并手动将 C 代码连接到所提供的 JavaScript 上,这样做很快就会过时。

幸运的是,Emscript 项目 [1] 奠定了基础,它比其他方式更容易。这并不奇怪,因为它的主要开发者 Alon Zakai 和 Luke Wagner 一直是这项工作的幕后推手,从 asm.js 开始,延伸到 WebAssembly MVP,再到推动规范的发展 ,一直持续到今天。Emscripten 工具链在这一过程中发挥了重要作用。

该项目是基于 LLVM 平台的。在前面的章节中,我指出它最初有一个自定义的后端,用来生成 asm.js 的可优化的 JavaScript 子集。一旦 WebAssembly 平台被定义,一个新的后端就能生成 Wasm 二进制文件。

不幸的是,这只是解决方案的一部分。还需要支持数据进出内存,链接模块,包装现有的库,等等。一个提供用户界面或监听网络请求的 C 语言程序经常在一个相当紧密的循环中响应输入活动。鉴于浏览器默认为单线程环境,这种主循环会出现操作上的不匹配。Emscripten 工具链已被修改,以解决在试图将本地 C/C++ 移植到 Web 环境中运行时可能出现的许多类型的问题。与大多数主题一样,本书不可能全面介绍这个项目的所有内容,但我将尝试让你快速入门。

适当的 "Hello, World!"

所以,首先要承认:我们本可以在第二章中就在浏览器中拥有一个有效的、未经修改的 "Hello, World!" 的例子,早在 2000 年就有了。最后一次,我们将向你展示例 6-1 中的代码。

例 6-1. 典型的 "Hello, World!" 程序用 C 语言表达

#include 
int main () {
printf ("Hello, World!\n");
return 0;
}

使用 Emscripten C 语言编译器(安装说明见附件 [2]),我们只需要告诉它编译 C 代码并生成一些 JavaScript 脚手架。之后,它就会在 Node.js 中未经修改地运行。

brian@tweezer ~/g/w/s/ch06> emcc hello.c -o hello.js 
brian@tweezer ~/g/w/s/ch06> ls -laF
total 520
drwxr-xr-x 7 brian staff 224 Mar 1 14:45 ./
drwxr-xr-x 7 brian staff 224 Mar 1 13:02 ../
-rw-r--r-- 1 brian staff 121457 Mar 1 13:05 bootstrap.min.css
-rw-r--r-- 1 brian staff 76 Mar 1 13:02 hello.c
-rw-r--r-- 1 brian staff 388 Mar 1 13:07 hello.html
-rw-r--r-- 1 brian staff 121686 Mar 1 14:45 hello.js
-rwxr-xr-x 1 brian staff 11711 Mar 1 14:45 hello.wasm*
brian@tweezer ~/g/w/s/ch06> node hello.js
Hello, World!

例 6-2 中的 HTML 文件并不是由这个过程生成的,它与我们之前看到的文件有明显的不同。有一个单一的