如何使用 Emscripten 编译的程序中的 wasm-bindgen?

Posted

技术标签:

【中文标题】如何使用 Emscripten 编译的程序中的 wasm-bindgen?【英文标题】:How can I use wasm-bindgen from a program compiled with Emscripten? 【发布时间】:2022-01-23 19:07:24 【问题描述】:

我正在尝试将包含由 wasm-bindgen 生成的代码的 Rust 库与我想用 Emscripten 编译的用 C 编写的程序链接。我的 MRE 如下:

在 Rust 方面,我有 Cargo.toml:

[package]
name = "rust_project"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["staticlib"]

[dependencies]
wasm-bindgen="0.2"

lib.rs 我有:

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" 
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);


#[no_mangle]
pub extern "C" fn call_from_c() 
    log("Hello, World!");

作为第一步,我使用cargo build --target wasm32-unknown-unknown 编译它,生成librust_project.a。然后我使用main.c 设置了以下C 项目:

/* forward declare the function from Rust */
void call_from_c();

/* call the function from main */
int main() 
   call_from_c();
   return 0;

CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)
project(c_project)
add_executable(c_project main.c)
target_link_libraries(c_project /path/to/librust_project.a)

最后,我尝试使用 Emscripten 工具链将它们组合在一起,如下所示:

cmake -DCMAKE_TOOLCHAIN_FILE=path/to/Emscripten.cmake ../
make

这是链接阶段出现问题的地方,emcc 报告 __wbg_log_941ab916ed5a24bd 是一个未定义的符号。我怀疑这个符号(以及其他符号)正在作为优化工作的一部分被删除,但我不确定在哪个阶段或如何禁用此优化。

在 CMake 中添加以下链接器选项会导致编译时出现关于未定义符号的警告:

target_link_libraries(c_project
   path/to/librust_project.a
   "-s EXPORTED_FUNCTIONS=[\"_main\",\"___wbg_log_941ab916ed5a24bd\"]"
   "-s ERROR_ON_UNDEFINED_SYMBOLS=0")

但我认为这些缺少的符号是有问题的,当我在 c_project.wasm 上运行 wasm-bindgen(CLI 工具)时,我收到以下错误:

import of `__wbg_log_941ab916ed5a24bd` doesn't have an adapter listed

如何防止 wasm-bindgen 导入/导出的函数在此过程中被剥离?

【问题讨论】:

【参考方案1】:

这是一个正在进行中的答案,希望我能在不久的将来变成一个完整的答案。如果不是,它至少可以作为其他走这条路的人的起点。

我一直致力于通过删除 CMake 和 Emscripten 并直接使用 Clang 进行编译,从而使我的 MWE 更加精简。这已经足够了,因为我不需要担心这个 MWE 中的标准库。

然后我的编译命令变成:

clang -Wall --target=wasm32-unknown-unknown --no-standard-libraries \
    -Wl,--export-all \
    -Wl,--no-entry \
    -Wl,-L/path/to/librust_project_a
    -Wl,-lrust_project
    -o main.wasm main.c

值得注意的是,我可以通过添加/删除 --export-all 链接器参数来触发以下 wasm-bindgen 错误。建议 LLVM 链接器负责在使用 wasm-bindgen 处理之前删除此部分。

import of `__wbg_log_941ab916ed5a24bd` doesn't have an adapter listed

【讨论】:

以上是关于如何使用 Emscripten 编译的程序中的 wasm-bindgen?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用库导入编译 C 文件到 webassembly 文件(Emscripten)

如何让 JetBrains CLion 中的“cmake”工作来编译 Emscripten/WebAssembly?

Emscripten:我如何编译带有像 immintrin.h 这样的内在头文件的 c 文件?

使用 Clang 编译的可执行文件中的 emscripten

Emscripten 中的“大”整数

如何在 React / React Native 中使用 Emscripten 编译的 JavaScript