在 Windows 上使用 emscripten 将 Rust 编译成 webassembly 时出错

Error in compiling Rust into webassembly using emscripten on Windows

我刚刚尝试在 Windows 上使用 emscripten 将 Rust 示例项目编译成 webassembly,但它会导致错误。 我该如何解决?

我做了什么:

  1. 安装 emscripten
>git clone https://github.com/emscripten-core/emsdk.git
>cd emsdk
>git pull
>emsdk install latest
>emsdk activate latest
>emsdk_env.bat
  1. 安装 rustup 从 https://www.rust-lang.org/ja/tools/install 下载 rustup-init.exe 并且 运行 它
  2. 通过 rustup 安装 wasm32 目标
>rustup target add wasm32-unknown-emscripten
  1. 创建示例项目
>cargo new --bin web_assembly
>cd web_assembly
  1. 尝试编译,但出现错误
>cargo build --target wasm32-unknown-emscripten
   Compiling web_assembly v0.1.0 (F:\github\rusttest\web_assembly)
error: linking with `emcc.bat` failed: exit code: 1
  |
  = note: "cmd" "/c" "emcc.bat" "-s" "DISABLE_EXCEPTION_CATCHING=0" "-L" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib" "-L" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\self-contained" "F:\github\rusttest\web_assembly\target\wasm32-unknown-emscripten\debug\deps\web_assembly.web_assembly.egwz9uoo-cgu.0.rcgu.o" "F:\github\rusttest\web_assembly\target\wasm32-unknown-emscripten\debug\deps\web_assembly.web_assembly.egwz9uoo-cgu.1.rcgu.o" "F:\github\rusttest\web_assembly\target\wasm32-unknown-emscripten\debug\deps\web_assembly.web_assembly.egwz9uoo-cgu.2.rcgu.o" "F:\github\rusttest\web_assembly\target\wasm32-unknown-emscripten\debug\deps\web_assembly.web_assembly.egwz9uoo-cgu.3.rcgu.o" "F:\github\rusttest\web_assembly\target\wasm32-unknown-emscripten\debug\deps\web_assembly.web_assembly.egwz9uoo-cgu.4.rcgu.o" "F:\github\rusttest\web_assembly\target\wasm32-unknown-emscripten\debug\deps\web_assembly.web_assembly.egwz9uoo-cgu.5.rcgu.o" "F:\github\rusttest\web_assembly\target\wasm32-unknown-emscripten\debug\deps\web_assembly.web_assembly.egwz9uoo-cgu.6.rcgu.o" "F:\github\rusttest\web_assembly\target\wasm32-unknown-emscripten\debug\deps\web_assembly.web_assembly.egwz9uoo-cgu.7.rcgu.o" "-o" "F:\github\rusttest\web_assembly\target\wasm32-unknown-emscripten\debug\deps\web_assembly.js" "-s" "EXPORTED_FUNCTIONS=[\"_main\",\"_rust_eh_personality\"]" "F:\github\rusttest\web_assembly\target\wasm32-unknown-emscripten\debug\deps\web_assembly.3a2jxscq1lvbzwaf.rcgu.o" "-O0" "--memory-init-file" "0" "-g4" "-s" "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]" "-L" "F:\github\rusttest\web_assembly\target\wasm32-unknown-emscripten\debug\deps" "-L" "F:\github\rusttest\web_assembly\target\debug\deps" "-L" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\libstd-28368703ab79076a.rlib" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\libpanic_unwind-c6cbccdff18b55f7.rlib" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\librustc_demangle-a5ffc5310c14c91c.rlib" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\libhashbrown-08c349e57dac68c0.rlib" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\librustc_std_workspace_alloc-ce3363c7b27912b6.rlib" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\libunwind-686deac84d1c117a.rlib" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\libcfg_if-1aefc0615f4a87c4.rlib" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\liblibc-35a51890c8428321.rlib" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\liballoc-d41456f5d5a426f6.rlib" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\librustc_std_workspace_core-2a7cc4e4deb2c4e8.rlib" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\libcore-997b7450818c8186.rlib" "C:\Users\Username\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\wasm32-unknown-emscripten\lib\libcompiler_builtins-68f9d21fef2c27f2.rlib" "-l" "c" "-s" "ERROR_ON_UNDEFINED_SYMBOLS=1" "-s" "ASSERTIONS=1" "-s" "ABORTING_MALLOC=0" "-Wl,--fatal-warnings"
  = note: shared:INFO: (Emscripten: Running sanity checks)
          emcc: warning: please replace -g4 with -gsource-map [-Wdeprecated]
          error: undefined symbol: __gxx_personality_v0 (referenced by top-level compiled C/C++ code)
          warning: Link with `-s LLD_REPORT_UNDEFINED` to get more information on undefined symbols
          warning: To disable errors for undefined symbols use `-s ERROR_ON_UNDEFINED_SYMBOLS=0`
          warning: ___gxx_personality_v0 may need to be added to EXPORTED_FUNCTIONS if it arrives from a system library
          Error: Aborting compilation due to previous errors
          emcc: error: 'F:/github/emsdk/node/14.15.5_64bit/bin/node.exe F:\github\emsdk\upstream\emscripten\src\compiler.js C:\Users\Username\AppData\Local\Temp\tmpang8muuo.txt' failed (1)


error: aborting due to previous error

error: could not compile `web_assembly`

To learn more, run the command again with --verbose.

工具版本:

>emcc.bat --version
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 2.0.20-git (8ed0f4fee2abd04923c2fd2bf44835169ce2ac2e)
Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

>rustup --version
rustup 1.24.1 (a01bd6b0d 2021-04-27)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.52.1 (9bc8c42bb 2021-05-09)`

如果您不严格要求 Emscripten,您应该使用 Rust 的自定义 WASM 支持,它可以通过 wasm32-unknown-unknown 获得,因为这是大多数与 Rust 相关的 WASM 开发发生的地方。

如果您想了解如何使用此目标的示例,请查看 Rust WASM book

Emscripten 使用 tip-of-tree LLVM,这可能与 Rust 使用的更稳定的 LLVM 版本不兼容。这意味着您必须将特定版本的 Emscripten 与与 Rust 的 LLVM 版本非常匹配的 LLVM 一起使用,而不是使用 latest.

自 Rust 52 以来与 Rust 的 LLVM 最匹配的 Emscripten 版本是 Emscripten 2.0.13,所以我会尝试使用它。

记录和跟踪最好使用的 Emscripten 版本的最佳资源是 https://blog.therocode.net/2020/10/a-guide-to-rust-sdl2-emscripten,尽管它还没有针对 Rust 52+ 进行更新。

未找到错误的真正原因。然而我确定哪个 emcc 版本停止使用 rust(使用最新的稳定版 1.55.0 测试)。 Emscripten 2.0.9 有效,但 Emscripten 2.0.10 失败并出现 ___gxx_personality_v0 错误。

如果您 want/need emscripten(使用基于 c 或 c++ 的 crates 或喜欢工作矮人调试)这里是修复构建错误的方法。

这里描述错误原因:https://github.com/rust-lang/rust/issues/85821

解决方法是:

为缺失的函数创建存根(另存为文件 gxx_personality_v0_stub.cpp):

#include "unwind.h"
#include "stdint.h"

extern "C" _Unwind_Reason_Code __gxx_personality_v0   (int version, _Unwind_Action actions, uint64_t exceptionClass, _Unwind_Exception* unwind_exception, _Unwind_Context* context) {
    return  _URC_NO_REASON;
}

使用 emcc 构建:

emcc -c gxx_personality_v0_stub.cpp

Create/modify.cargo/config 文件:

[build]
rustflags = ["-C", "link-args=gxx_personality_v0_stub.o"]

享受最新的 Rust(使用 v1.55.0 测试)和 emscripten (v2.0.29)

注意:恐慌时堆栈展开不适用于此存根。但是由于该函数在 emscripten 中被存根了,所以您不会丢失任何功能。

您也可以使用 EMCC_CFLAGS 作为解决方法:

EMCC_CFLAGS="-s ERROR_ON_UNDEFINED_SYMBOLS=0 --no-entry" cargo build --target wasm32-unknown-emscripten

在旧版本中,此标志称为 EMMAKEN_CFLAGS:

EMMAKEN_CFLAGS="-s ERROR_ON_UNDEFINED_SYMBOLS=0 --no-entry" cargo build --target wasm32-unknown-emscripten