Rust: 让 Rust 与 emscripten 一起工作

创建于 2012-04-18  ·  30评论  ·  资料来源: rust-lang/rust

我花了一些时间来解决这个问题,rustc 现在生成了 emscripten 可以翻译的代码,但是编译的 javascript 在遇到运行时函数时失败。 下一步是使用emcc作为编译器开始构建运行时。 剔除所有不在EMSCRIPTEN ifdefs 后面构建的东西。

Emscripten 正在添加一种将内联程序集视为 javascript 的方法,因此所有不使用 emscripten 构建的运行时部分都可以使用 javascript 内联实现。

或者,我们可以在 javascript 中零碎地重新实现运行时,而根本不需要从 C++ 编译它。 不推荐这种方法。

A-runtime E-hard

最有用的评论

我正在做大量的分类工作,让我们为 1.0 做好准备。 作为其中的一部分,我正在将类似愿望清单的内容移至 RFC 存储库,因为这是应该讨论/优先考虑主要新事物的地方。

此问题已移至 RFC 存储库:rust-lang/rfcs#604

所有30条评论

另见#3608。

还是不错的; 不在任何成熟度里程碑上。

仍然会很好,但不是很重要。 这应该会变得更容易,因为很多运行时都是用 rust 重写的。

现在运行时是用 Rust 编写的,这会如何改变这个 bug 的前景? 通过 emscripten 运行无运行时的 Hello World 有多难?

现在为 emscripten 添加非常好的支持应该不是特别困难。 它已经非常适用于 rust-core。 在编译器中,我们需要添加对正确目标三元组的支持,正确设置各种目标属性,然后将运行时中目前无法在 js、线程和上下文切换中工作的少数部分隔离开来。

一旦 1:1 调度模式更加成熟,我们甚至可以通过 Web Worker 添加对任务的支持,尽管目前它需要不同的消息传递解决方案。 根据添加到 js/emscripten 的并行支持,我们最终可能能够准确地支持 rust 的消息传递语义。

@brson :我认为#10780 将是目前最大的

感谢-Z no-landing-pads现在可以正常工作了! 向标准库添加对此的明确支持是可能的,但大多数大多数都不会工作(文件、tcp、udp 等),所以我认为没有必要。 如果标准库获得独立支持,它将开始工作,我们可以根据可以映射到 JavaScript 的功能打开更多问题。

如果可以的话,我实际上想暂时将其打开。 我认为这样做将是朝着确保标准库可扩展并能够在任何数量的平台上运行的良好步骤。

我确实同意大部分工作可能已经完成,这可能需要libemscripten来提供特定于 emscripten 的 I/O,但我认为沿途可能会遇到足够多的障碍,值得离开开放的问题(这仍然是一个有趣的项目!)

@alexcrichton :不可能为

状态更新:

@alexcrichton 已将标准库重构为一堆具有更易于理解的依赖关系的较小库。 现在将 core、alloc、rand 和 collections 库编译到 Web 上应该几乎是微不足道的。

以下是我建议解决此问题的方法:

  • 使用 rust 和 LLVM 工具链做一些实验,以了解代码生成器如何交叉编译为 asm.js。
  • 使用 emscripten 手动构建 libcore 并证明它可以在网络上运行。
  • 修改 rustc 和 mk/platform.mk 以了解特定于 emscripten 的目标三元组,生成一个只包含 libcore.rlib 的交叉编译工具链
  • 通过允许它与系统(在本例中由 emscripten 提供) malloc 一起工作来解决 liballoc,然后是其他无运行时的 crate。

这是一个非常好的开始!

好的,所以我尝试了第一步,显然马上就遇到了问题。

我用--emit bc libcore编译--emit bc ,当试图用emcc -O0编译它时,我得到:

/Users/arcnor/emscripten-fastcomp/build/bin/llvm-nm: /tmp/tmpfTkmfj/core_0.o: Invalid CMPXCHG record.
/Users/arcnor/emscripten-fastcomp/build/bin/opt: /tmp/tmpfTkmfj/core.bc: error: Invalid CMPXCHG record
Traceback (most recent call last):
  File "/Users/arcnor/emscripten/emcc", line 1573, in <module>
    shared.Building.llvm_opt(final, link_opts)
  File "/Users/arcnor/emscripten/tools/shared.py", line 1335, in llvm_opt
    assert os.path.exists(target), 'Failed to run llvm optimizations: ' + output
AssertionError: Failed to run llvm optimizations:

不确定我是否可以对此做任何事情,或者是因为我们无法为此使用rustc --emit输出。

对不起,如果这不是评论这个的地方......

我也尝试过libnum ,一个更简单的,并且bc生成正确,但我在emcc过程中收到一个警告,关于使用错误的三元组和由此产生的 . js 在libnum中没有任何函数,所以我觉得我在这里太天真了:)

@Arcnor您可能会向一些以前使用 emscripten 编译过简单测试的人询问他们的过程。 我只有几个想法。

  • LLVM 位码随版本变化而变化,Rust 使用的版本并不总是与 emscripten 相同。 让它们都使用相对相似的 LLVM 版本可以提高兼容性。
  • 从您的错误消息来看,您似乎正在使用 emscripten 的新“fastcomp”后端。 与旧后端相比,这在 Rusty 工作负载上的测试可能更少。 手动选择使用旧后端至少可能会产生不同的结果。
  • Emscripten 通常使用自己的目标三元组,因此 rustc 可能需要追求使用相同的三元组。

尝试编译libcore时的错误似乎与这个emscripten 问题有关。 将libcore编译

可能有一种方法可以从 Rust 方面解决这个问题,但根据 emscripten 问题中的评论,我认为将原子支持加入 emscripten 是最有意义的。

如果 emscripten 有自己的平台,我们也许可以为它们的单线程变体配置所有原子,但我同意在上游 emscripten 中使用它会更好!

如果我没记错的话,emscripten新的“fastcomp”后端是LLVM的一个分支(而之前的后端只是LLVM之上的一层),所以fastcomp的LLVM版本可能很难升级,不会升级频繁地。

如果它需要与 Rust 的输出兼容,这将是有问题的。 例如现在 fastcomp 的 LLVM 版本是 3.3,而 Rust 使用的 LLVM 是 3.4。

旧的 emscripten 后端已被弃用,根据官方文档不应使用,因此它可能不是使用它的选项。

我似乎是目前唯一一个试图为 emscripten 编译的人。

为了记录,以下是我尝试过的事情:

  • 编译为字节码(由 Rust 的 LLVM 3.4 生成)并将其传递给 fastcomp(LLVM 3.3 的分支); 导致 fastcomp 崩溃
  • 编译为 IR,手动编辑直到它与 LLVM 3.3 兼容并将其传递给 fastcomp ; 太复杂,太多东西要修改任何非平凡的代码
  • --llvm-root编译 Rust stage1 指向 emscripten 的 fastcomp ; 这不起作用,因为他们删除了对 ARM/MIPS/等的支持。 在他们的 fork 中(因此我从 makefile 和链接期间收到错误)
  • 修改 Rust 源代码中的 LLVM git 子模块,使其指向 3.3 时代的旧提交; 在 LLVM 中的某个时候出现段错误
  • 使用--llvm-root编译 Rust 指向预编译的 LLVM 3.3(来自官方 ubuntu 存储库); 在 stage1 编译结束时获得断言失败,并且生成的 rustc 二进制文件不起作用。

除非有人有想法,否则我的结论是我们需要等待emscripten升级。

朗姆酒似乎奏效了,有点; 也许这会有所帮助

次要更新:emscripten-fastcomp 已更新至 LLVM 3.4,稍后将更新至 LLVM 3.5。

@tomaka你试过用 3.4 版本做任何事情吗? 我能够用它编译朗姆酒示例,但任何更多的失败都出现了难以理解的错误。

@ibdknox 3.4 与 3.5 不兼容
即使是一个简单的 hello world 也会产生一个失败的断言: LLVM ERROR: 0 && "some i64 thing we can't legalize yet"

嗯。 我能够从rustc --emit ir foo.rust获取输出并通过 emscripten-incoming 运行它。 现在 LLVM 3.5 上有 Rust 吗?

Rust 已经使用 LLVM 3.5 很长时间了。 您可以很幸运,并且不会生成任何不兼容的东西。
例如,这编译得很好:

#[start]
fn main(_: int, _: *const *const u8) -> int {}

这不是因为不兼容的 IR:

fn main() { println!("hello world"); }

@ibdknox http://www.reddit.com/r/rust_gamedev/comments/2n0x08/emscripten_experiments/
看起来不兼容的地方比我想象的要少。

作为更新,当我使用现已更新到 3.5 的 emscripten 编译 hello world 时,我得到以下信息:

Value:   %28 = call fastcc { i8, [0 x i8], [0 x i8] } @_ZN3fmt5write20h2c56fdda0b308d94DFAE({ i8*, void (i8*)** }* noalias nocapture dereferenceable(8) %arg.i, %"struct.core::fmt::Arguments[#3]"* noalias nocapture readonly dereferenceable(24) %__args31), !noalias !22
LLVM ERROR: Unrecognized struct value
Traceback (most recent call last):
  File "/Users/chris/Downloads/emsdk_portable/emscripten/incoming/emcc", line 1259, in <module>
    shared.Building.llvm_opt(final, link_opts)
  File "/Users/chris/Downloads/emsdk_portable/emscripten/incoming/tools/shared.py", line 1401, in llvm_opt
    assert os.path.exists(target), 'Failed to run llvm optimizations: ' + output
AssertionError: Failed to run llvm optimizations:

这是我的编译方式:

rustc --target i686-apple-darwin -C lto --emit ir foo.rust
emcc -v foo.ll -o test.html

不过,似乎没有带来 fmt 的事情通常似乎有效。

上周我一直在利用空闲时间研究这个问题。 我在夏天和现在之间的某个时间阅读了 rust 的书,非常喜欢该语言的机制,但直到最近才开始用它实现一些东西。 我对 rust 编译器的了解与我本周所学的知识一样,但希望我能做出贡献。

所以我想首先要注意我学到的东西(但我花了几个晚上才注意到)是 Rust 在 7 月转移到了 LLVM 3.6。 所以当前版本的 Rust 和 emscripten-fastcomp 是不兼容的。

我尝试用--llvm-root指向 emscripten-fastcomp 1.29.2 编译 rust 并得到这个错误:

rustc: x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib/libcore
error: internal compiler error: unexpected panic
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: http://doc.rust-lang.org/complement-bugreport.html
note: run with `RUST_BACKTRACE=1` for a backtrace
thread 'rustc' panicked at 'assertion failed: self.raw.hash != self.hashes_end', /Users/zen/Code/rust/src/libstd/collections/hash/table.rs:776


make: *** [x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib/stamp.core] Error 101

为了解决这个错误,我配置并构建了 emscripten-fastcomp

../configure --enable-optimized --disable-assertions --enable-targets=host,js,arm,aarch64,mips

而不是推荐的emscripten指南

../configure --enable-optimized --disable-assertions --enable-targets=host,js

尽管不需要为所有目标构建 Rust,但它目前总是与 LLVM 链接,并为所有目标编译 CPU 支持。 这是一个可以在未来修复的问题的解决方法,因此我们可能不需要总是使用该配置编译 emscripten-fastcomp。

一旦我发现 Rust 已经转移到 LLVM 3.6,我就在 rust-lang/llvm 上查找了最后一个分支,即 LLVM 3.5。 https://github.com/rust-lang/llvm/tree/rust-llvm-2014-07-24我针对它而不是 emscripten-fastcomp 进行编译,很想知道结果如何。 针对 emscripton-fastcomp 最近迁移到 LLVM 3.5 进行编译时,我遇到了完全相同的错误。 我认为这意味着 Rust 现在在某种程度上与 LLVM 3.5 不兼容,否则我真的不会期望。

所以现在我们等待或必须获得 emscripten-fastcomp 到 LLVM 3.6 :wink:

值得一提的是,我下载了一个存档的 0.11 副本,并且能够为emcc理解的 hello world 生成 LLVM IR,但随后遇到了链接问题。 看到它超越了对字节码的理解是非常令人兴奋的,但实际上让它链接需要在 Rust 代码库中工作。

我看了一眼将 rust-lang/llvm 合并到 emscripten-fastcomp。 当时有超过 43 个文件的 117 个冲突部分。

我提到让 Rust 0.11 和 emcc 1.29.2 进入链接阶段。 这是具体的结果:

$ emcc -v hello.ll -o hello.js
INFO     root: (Emscripten: Running sanity checks)
WARNING: Linking two modules of different data layouts: '/Users/zen/.emscripten_cache/libc.bc' is 'e-p:32:32-i64:64-v128:32:128-n32-S128' whereas '/tmp/tmpv_yB8E/hello_0.o' is 'e-p:32:32-f64:32:64-f80:128-n8:16:32'
WARNING: Linking two modules of different target triples: /Users/zen/.emscripten_cache/libc.bc' is 'asmjs-unknown-emscripten' whereas '/tmp/tmpv_yB8E/hello_0.o' is 'i686-apple-darwin'
warning: incorrect target triple 'i686-apple-darwin' (did you use emcc/em++ on all source files and not clang directly?)
warning: unresolved symbol: _ZN2io5stdio12println_args20h0caae70b0e2eb347Iol7v0_11_0E
warning: unresolved symbol: _ZN10lang_start20h70f93b7d0a75f99atre7v0_11_0E

似乎 emcc/fastcomp 用下划线替换符号中的点,而 Rust 期望以另一个下划线作为前缀,但我对此不太确定。 第一个未解析的符号在 i686-apple-darwin 构建的 libstd 中显示为__ZN2io5stdio12println_args20h0caae70b0e2eb347Iol7v0.11.0E 。 即使我可以让 emcc 知道如何在构建的库中找到这个符号,我猜测库包含机器代码而 emcc 将需要 LLVM 字节代码。 我想我记得有人提到需要为 emscripten 编译标准库。 这将是需要的一部分。

因此,如果有人想亲自尝试一下,下面是我希望尝试和努力的后续步骤。 (或者可以让我知道我是对还是错。)

  • 将 rust-lang/llvm 合并到 emscripten-fastcomp
  • 在没有 JS 后端支持的情况下使用合并的 fastcomp 构建 Rust
    希望这将是对合并的一个很好的健全性测试。
  • 将 emscripten 的三元组添加到 Rust 并构建它
    据我所知,我需要更改或添加许多文件。

    • mk/cfg/asmjs-unknown-emscripten.mk

    • rt/arch/asmjs/{morestack.S,record_sp.S}(可能是空的?)

      需要这些文件来为 Rust 构建 morestack.a 以支持 LLVM 的分段堆栈。 如果我没记错的话,Emscripten 的堆栈也是头部。 它使用堆的另一端作为堆栈,因为对于 asmjs 你不能改变数组的大小,创建新的堆栈段是不可能的。 我在 librustc_back 目标文件中的 TargetOption 中看到了一个字段,希望可以禁用它。

    • librustc_trans/trans/cabi_asmjs.rs

    • librustc_trans/trans/cabi.rs

      我不确定是否需要这些,目前只是猜测。

    • librustc_back/target/asmjs_unknown_emscripten.rs

    • librustc_back/asmjs.rs

    • librustc_syntax/abi.rs

    • librustc_back/back/write.js configure_llvm()

    • librustc_llvm/lib.rs static_link_hack_this_sucks()

  • 实现缺失的系统接口
    我在 11 月看到 libgreen 被删除了。 由于 emscripten 需要等待某种方式与浏览器中的工作人员共享,如果发生这种情况,则需要恢复诸如 libgreen 之类的东西或以某种方式专门为 emscripten 填充 pthread,例如 rust 如何为 pthreads 或 windows 线程 api 构建。

IO也是。 可能还有我不知道的其他部分。

“将 rust-lang/llvm 合并到 emscripten-fastcomp”

您可能不想这样做 - Emscripten 基于 pnacl-llvm/pnacl-clang,因此您正在创建一个带有补丁的分支,这可能会很痛苦。 如果您有兴趣,可以在https://github.com/kripken/emscripten-fastcomp/issues/51#issuecomment -62323164 上的 r33 -> r34 的 Emscripten 合并调查中查看分支的一些详细信息.

我听说 pnacl 计划比以前更接近地跟踪上游,但我在 pnacl 问题跟踪器中看不到任何相关问题要更新到 3.6,所以可能需要一段时间(特别是考虑到 3.6 仅在 5 天前才分支!)。 ..我猜你可能会提出问题? 如果您决定不使用自己的 Emscripten fork,我会看到两种选择 - 等待 pnacl 或帮助 Emscripten 脱离 pnacl 并进入上游。

编辑:将“现在”更正为“不”。 一个关键的区别。

我正在做大量的分类工作,让我们为 1.0 做好准备。 作为其中的一部分,我正在将类似愿望清单的内容移至 RFC 存储库,因为这是应该讨论/优先考虑主要新事物的地方。

此问题已移至 RFC 存储库:rust-lang/rfcs#604

此页面是否有帮助?
0 / 5 - 0 等级