编译到 WebAssembly:它正在发生!

WebAssembly 是一种用于编译到 Web 的新的二进制格式。它目前正在设计和实现中,主要的浏览器供应商正在合作进行开发。进展非常迅速!在这篇文章中,我们将通过深入研究 WebAssembly 的工具链方面来展示我们最近取得的一些进展。

为了使 WebAssembly 可用,我们需要两个主要组件:能够编译代码到 WebAssembly 的工具链,以及能够执行该输出的浏览器。这两个组件都取决于 WebAssembly 规范 完成的进度,但在其他方面基本上是独立的工程工作。这种分离是一件好事,因为它将使编译器能够发出在任何浏览器中运行的 WebAssembly,并使浏览器能够运行 WebAssembly,无论它是由哪个编译器生成的;换句话说,它允许多个工具链和多个浏览器协同工作,从而提高用户选择。这种分离还允许现在并行进行这两个组件的工作。

WebAssembly 工具链方面的一个新项目是Binaryen。Binaryen 是一个用于 WebAssembly 的编译器基础设施库,用 C++ 编写。如果您自己没有开发 WebAssembly 编译器,您可能永远不需要了解它,但如果您使用 WebAssembly 编译器,它可能会在幕后为您使用 Binaryen;稍后我们将看到一些示例。

Binaryen 的核心是一组模块化的类,可以解析和发出 WebAssembly,以及以专为编写灵活的转换过程而设计的 AST 来表示它。在此基础上构建了几个有用的工具

  • Binaryen shell,它可以加载 WebAssembly 模块,对其进行转换,在解释器中执行它,打印它等。加载和打印使用 WebAssembly 当前的临时 s 表达式格式,该格式的后缀为 .wast(正在设计 WebAssembly 二进制格式 以及最终的 文本格式,但它们还没有准备好)。
  • asm2wasm,它将 asm.js 编译成 WebAssembly。
  • wasm2asm,它将 WebAssembly 编译成 asm.js。(这还在开发中。)
  • s2wasm,它将 .s 文件(由 LLVM 中正在开发的新 WebAssembly 后端 发出的格式)编译成 WebAssembly。
  • wasm.js,Binaryen 本身移植到 JavaScript 的版本。这使我们能够在网页或任何其他 JavaScript 环境中运行所有上述组件。

有关 Binaryen 的一般概述,您可以查看我最近发表的演讲的 幻灯片。不要跳过 第 9 张幻灯片 :)

需要注意的是,WebAssembly 仍处于设计阶段,Binaryen 可以读取和写入的格式(.wast、.s)不是最终的。Binaryen 一直在随着这些变化而不断更新;变化的速度正在降低,但请做好应对中断的准备。

让我们讨论一些 Binaryen 可以提供帮助的具体领域。

使用 Emscripten 编译到 WebAssembly

Emscripten 可以将 C 和 C++ 编译成 asm.js,而 Binaryen 的 asm2wasm 工具可以将 asm.js 编译成 WebAssembly,因此 Emscripten+Binaryen 共同提供了一种完整的将 C 和 C++ 编译成 WebAssembly 的方法。您可以直接在 asm.js 代码上运行 asm2wasm(它可以在命令行上运行),但最简单的方法是让 Emscripten 为您执行此操作,例如使用

emcc file.cpp -o file.js -s ‘BINARYEN=”path-to-binaryen”’

Emscripten 将编译 file.cpp,并发出一个主要的 JavaScript 文件和一个用于 WebAssembly 输出的单独文件,格式为 .wast。在幕后,Emscripten 编译成 asm.js,然后在 asm.js 文件上运行 asm2wasm 以生成 .wast 文件。有关更多详细信息,请参阅 Emscripten 关于 WebAssembly 的维基页面

但是等等,当浏览器尚不支持时,编译到 WebAssembly 有什么用呢?好问题 :) 是的,我们不想发布这段代码,因为浏览器无法运行它。但它对于测试目的仍然非常有用:我们希望知道 Emscripten 能够尽快正确地编译到 WebAssembly,因为我们不想等待浏览器支持。

但是,如果我们无法运行它,我们如何检查 Emscripten 是否确实正确地编译到 WebAssembly 呢?为此,我们可以使用 wasm.js,Emscripten 在我们之前运行该 emcc 命令时将其集成到我们的输出 .js 文件中。wasm.js 包含编译到 JavaScript 的 Binaryen 的部分,包括 Binaryen 解释器。如果您运行 file.js(在 node.js 中或在网页上),那么解释器将执行该 WebAssembly。这使我们能够实际验证编译的 WebAssembly 代码是否执行了正确操作。您可以在 此处 查看此类已编译程序的示例,并且在 构建套件存储库 中有一些用于测试目的的其他构建。

当然,鉴于这种奇怪的测试环境,我们还没有达到我们希望的那么稳固的地步:一个编译到 WebAssembly 的 C++ 程序,在一个本身从 C++ 编译到 JavaScript 的 WebAssembly 解释器中运行,并且还没有其他方法可以运行该程序。但我们有一些理由相信结果

  • 此输出通过了 Emscripten 测试套件。其中包括许多实际的代码库(Python、zlib、SQLite 等)以及许多针对 C 和 C++ 中极端情况的单元测试。经验表明,当该测试套件通过时,其他代码也很可能能够工作。
  • Binaryen 解释器通过了 WebAssembly 规范测试套件,表明它正在正确运行 WebAssembly。换句话说,当浏览器获得原生支持时,它们应该以相同的方式运行它(但速度要快得多!此代码在简单的解释器中运行以进行测试,因此速度非常慢;但请注意,正在研究 快速 方法 polyfill)。
  • 此输出是使用 Emscripten 生成的,Emscripten 是一个在生产环境中使用的稳定编译器,并且在 Binaryen 之上只有一小部分代码(只有几千行)。新代码越少,错误的风险就越小。

总的来说,这表明我们目前处于良好的状态,并且可以使用 Emscripten + Binaryen 将 C 和 C++ 编译到 WebAssembly,即使浏览器尚不支持它。

请注意,除了发出 WebAssembly 之外,我们在此模式下发出的构建通常还会使用 Emscripten 工具链中的所有其他内容:Emscripten 移植的 musl libc 和 syscalls 以访问它、OpenGL/WebGL 代码、浏览器集成代码、node.js 集成代码等等。因此,这支持 Emscripten 已有的所有功能,并且使用 Emscripten 的现有项目只需切换一个开关即可切换到发出 WebAssembly。这是让现有的编译到 Web 的 C++ 项目在 WebAssembly 发布时获益的关键部分,而无需他们付出任何额外的努力。

使用新的实验性 LLVM WebAssembly 后端与 Emscripten

我们刚刚看到了 Emscripten 的一个重要里程碑,即它可以编译到 WebAssembly 甚至测试我们是否获得了有效的输出。但事情并没有到此结束:那是使用 Emscripten 当前的 asm.js 编译器后端,以及 asm2wasm。有一个新的 LLVM 后端正在直接在上游 LLVM 存储库中开发用于 WebAssembly,虽然它还没有准备好供普遍使用,但从长远来看,它将非常重要。Binaryen 也支持这一点。

LLVM 后端,与大多数 LLVM 后端一样,会发出汇编代码,在本例中,使用特定的 .s 格式。该输出接近于 WebAssembly,但并不完全相同——它看起来更像是 C 编译器的输出(指令的线性列表,每行一条指令等),而不是 WebAssembly 更结构化的 AST。但是,.s 文件可以以相当直接的方式转换为 WebAssembly,并且 Binaryen 包含 s2wasm,这是一个将 .s 转换为 WebAssembly 的工具。它可以在命令行上独立运行,但也具有 Emscripten 集成支持:Emscripten 现在有一个 WASM_BACKEND 选项,您可以像这样使用它

emcc file.cpp -o file.js -s ‘BINARYEN=”path-to-binaryen”’ -s WASM_BACKEND=1

(请注意,您还需要 BINARYEN 选项,因为 s2wasm 是 Binaryen 的一部分。)提供该选项后,Emscripten 将使用新的 WebAssembly 后端而不是现有的 asm.js 后端。在调用后端并从其接收 .s 后,Emscripten 调用 s2wasm 将其转换为 WebAssembly。一些您可以使用新后端构建的程序示例在 Emscripten 维基 上。

因此,有两种方法可以使用 Binaryen 编译到 WebAssembly:Emscripten + asm.js 后端 + asm2wasm,它现在可以工作并且应该相当健壮和可靠,以及Emscripten + 新的 WebAssembly 后端 + s2wasm,它还没有完全投入使用,但随着 WebAssembly 后端的成熟,它应该成为一个强大的选项,并有望在未来取代 asm.js 后端。目标是使这种转换无缝进行:在两种 WebAssembly 模式之间切换只需设置一个选项,就像我们看到的那样。

Emscripten 中 asm.js 和 WebAssembly 支持之间也是如此,这只是一个可以设置的选项,并且那里的转换也应该是无缝的。换句话说,将有一条简单明了的路径从

  • 使用 Emscripten 发出 asm.js 到
  • 使用它通过 asm2wasm 发出 WebAssembly(今天可以实现,但浏览器还无法运行它)到
  • 使用它通过新的 LLVM 后端发出 WebAssembly(后端准备就绪后)。

每个步骤都应该带来巨大的好处,而无需开发人员付出任何额外努力。

最后,请注意,虽然这篇文章重点介绍了将 Binaryen 与 Emscripten 结合使用,但其核心设计是成为一个通用的 C++ WebAssembly 库:如果您想使用 WebAssembly 编写一些与工具链相关的内容,您可能需要代码来读取 WebAssembly,打印它,操作 AST 等,Binaryen 提供了这些功能。它在编写 asm2wasm、s2wasm 等方面非常有用,希望其他项目也能发现它的用处。

关于 Alon Zakai

Alon 是 Mozilla 研究团队的成员,他主要从事 Emscripten 的工作,Emscripten 是一个将 C 和 C++ 编译成 JavaScript 的编译器。Alon 于 2010 年创立了 Emscripten 项目。

更多由 Alon Zakai 撰写的文章…


21 条评论

  1. Juan Linietsky

    关于编译的好消息!迫不及待地想在实际的浏览器中对其进行测试,而无需自己编译它们 :P

    2015 年 12 月 17 日 上午 11:35

  2. Etiene

    哦哦哦!!!我一直在等待这个!!太激动了!自从我听说 WebAssembly 以来,我就迫不及待地想将 Lua 解释器发布到浏览器 :D 好消息,谢谢!

    2015 年 12 月 17 日 下午 13:19

  3. Robin

    有人记得大约在 2000-2001 年左右的旧网站 assembler.org 吗?它提供了几个针对 Internet Explorer 的低级编程演示——称为“WebAssembly”——展示了 Web 浏览器中非常快速的图形效果,比当时 JavaScript 和 Flash 提供的效果快得多。该网站提供了几个游戏和图形演示,所有这些都令人印象深刻,并且屏幕更新完美,没有闪烁,没有卡顿等。

    在阅读本文时,感觉 Mozilla 就像往常一样在重新发明,而不是发明。

    2015 年 12 月 17 日 下午 13:27

  4. Tom Marsden

    这真是令人兴奋,写得很好!

    2015 年 12 月 17 日 下午 16:18

  5. jiyinyiyong

    期待 WebAssembly 生态系统成熟,然后编译我的基于缩进的语言
    http://cirru.org/ 到它 :P

    2015 年 12 月 17 日 下午 19:16

  6. BanMe

    way back machine 可能会在证明这一点方面提供帮助,如果他们编目了该网站的话.. 我记得在过去编码了一些类似的东西,将 Win32 api 包装到 vbscript 或 javascript 中,现在可能也需要查找一下。

    2015 年 12 月 17 日 下午 20:56

  7. Sajid Qureshi

    规范很难理解,因为它使用了诸如“可以”、“应该”等措辞,以及未来时、现在时和过去时的句子语法混合。

    对于规范来说,必须应用严格性以避免延长草案的最终确定。

    给人一种太多内容被推迟的印象,尤其是在没有关于与执行环境相关的功能的具体概述的情况下。

    将运行时(地址空间)划分为 32 位和 64 位没有必要。关于数据类型大小的推测太多,大小必须定义,并且代码能够在运行时查询以进行适配。

    共享内存支持不能被推迟,否则以后会带来很大的麻烦,并且应该在 32 位、64 位和云运行时/地址空间中保持一致——支持拆分执行,而无需依赖网络端点或管道。

    跨线程使用消息传递进行通信将严重降低协程和多线程数据处理性能。

    为了进行 IO 操作,请考虑将内存映射 IO、Unix 风格的 IOCTL 和套接字作为规范的一部分,以及实现者必须自定义和/或调整的一组库。

    2015 年 12 月 18 日 上午 03:08

  8. 该来的总会来

    该来的总会来!我有一段时间一直在惊恐地关注整个“编译到 JS”运动。

    2015 年 12 月 18 日 上午 06:25

  9. Steve Naidamast

    哦,我们又来了…

    我们从 1980 年代开始使用解释性代码。然后我们在 1990 年代开始使用二进制文件。然后出现了 Java,随后是 .NET,我们又回到了解释性代码。

    现在微软宣布了 .NET Native,这是一个编译器,而我们这里有 Mozilla 的 WebAssembly。

    世事变迁,万事如常。我们本应该坚持使用编译后的二进制文件。它们更快也更安全。但不行!每个人都必须使用所有那些新潮的工具……

    2015年12月18日 上午08:43

    1. Alon Zakai

      @Steve

      需要明确的是,这不是一个仅限于Mozilla的项目。正如文章中提到的,它是所有浏览器厂商的项目:Mozilla、Google、Microsoft和Apple。

      是的,这里可能有一些历史的既视感。但浏览器厂商认识到,二进制格式有一些网络无法获得的其他好处。所以,是的,二进制文件之前也用过,但现在对网络平台来说,这样做是有意义的。当然,在保持网络跨厂商、可移植、开放和安全的同时——我们只想要二进制文件的好处,而不是坏处。

      2015年12月18日 上午09:11

  10. Steve Naidamast

    @Alon Zakai

    是谁在做这个过程并不重要。如果你像我一样关注趋势,你会发现,有一些迹象表明,这个领域正在非常缓慢地开始转向可执行二进制文件。这对.NET或Java平台来说都不是什么大问题。

    但是,你无法使二进制文件跨平台兼容,但对于网络应用程序来说,这无关紧要,因为这些组件只会运行在服务器端。

    无论如何,这样做是为了盈利。最终,你会看到关于使用编译后的可执行文件的优势的广告,所以每个人都必须做好准备,再次迁移到一个“新的”平台。

    在这个领域工作了这么久,你会发现趋势总是重复出现。此外,自2010年以来,这个领域已经变得一团糟……

    2015年12月18日 下午12:19

  11. Jim

    开源世界正在经历它的ActiveX时刻

    2015年12月19日 上午01:21

  12. hutzlibu

    @Steve Naidamast
    好吧,即使我“在该领域的时间”没有你那么长,我认为它更像是螺旋楼梯……

    有很多既视感,但在更高的(或者至少是不同的)层面上。

    网络已经成为一个非常重要的场所,因此,自然而然地,使其尽可能快是明智之举。
    而且,当理论上存在更好的做事方法时,这并不重要,当你想要在现实生活中完成事情时,现在就可以。

    因此,没有人声称,你应该为所有事情都使用wasm,但对于那些想要面向网络的人——他们很快就会获得一个更强大的工具——我对此满怀期待,并带着微笑。

    所以,对于Alon Zakai和其他相关人员:感谢你们的辛勤工作!

    2015年12月19日 上午01:33

  13. Francis Kim (@franciskim_co)

    迫不及待!

    2015年12月19日 下午19:34

  14. BaasBartels

    @Robin 不确定你是开玩笑还是认真,但是根据assembler.org上的信息页面,该网站和展示的演示是使用“动态DHTML”(原文如此)构建的,也就是html + javascript + css + dom。它们也旨在在IE4+和Netscape 4+之间跨平台。
    (https://web.archive.org/web/20010622081048/http://assembler.org/XLAT/info/index.html)

    2015年12月20日 上午01:03

  15. Dusty

    我对这项技术非常感兴趣,它真的可以推动整个生态系统的进步,请让它实现!:-)

    2015年12月21日 上午01:19

  16. Jim Lonero

    它如何处理指针、STD库类和智能指针?

    2015年12月21日 上午09:12

    1. Alon Zakai

      所有这些都应该可以正常工作,并且在我们通过的测试套件中。

      对于STD库类、智能指针等,它们之所以能工作,是因为我们使用了现有的稳定Emscripten标准库。

      2015年12月21日 上午10:15

  17. JS

    我爱它!

    2015年12月28日 上午06:44

  18. Ravenmetrix

    我们对这次重大更新感到兴奋!我已经要求我的技术团队检查Emscripten以及WebAssembly如何影响/有利于我们当前和未来的项目

    2016年1月2日 上午07:32

  19. AndyX

    真是乱七八糟!就好像网页开发正在崩溃一样。企业需要一定的稳定性才能运营。潜在的开发人员需要对学习什么有一个大致的概念。当一切都处于如此混乱的状态时,任何人都如何能够为他们的个人生活或商业生活做计划?!

    2016年1月6日 下午19:24

本文评论已关闭。