How can I use wasm-bindgen from a program compiled with Emscripten?

Viewed 284

I am trying to link a Rust library containing code generated by wasm-bindgen against a program written in C which I would like to compile with Emscripten. My MRE is as follows:

On the Rust side, I have Cargo.toml:

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

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

[dependencies]
wasm-bindgen="0.2"

and in lib.rs I have:

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!");
}

As a first step, I compile this with cargo build --target wasm32-unknown-unknown which produces a librust_project.a. I then set up the following C project with main.c:

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

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

and 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)

Finally, I attempt to put it all together using the Emscripten toolchain as follows:

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

Which is where something appears to go wrong at the linking stage with emcc reporting that __wbg_log_941ab916ed5a24bd is an undefined symbol. I suspect that this symbol (among others) is being stripped out as part of an optimization effort but I am not sure at what stage or how I can disable this optimization.

Adding the following linker options in CMake results in compilation with a warning about the undefined symbol:

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

but I believe these missing symbols are problematic and when I run wasm-bindgen (the CLI tool) over c_project.wasm I get the following error:

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

How can I prevent the wasm-bindgen imported/exported functions from being stripped during this process?

1 Answers

This is a work-in-progress answer, which hopefully I will be able to turn into a complete answer in the near future. If not perhaps, it will at least serve as a starting point for others who have come down this path.

I have been working on making my MWE even more minimal by removing CMake and Emscripten and just compiling with Clang directly. This is sufficient since I don't need to worry about the standard library in this MWE.

My command for compiling then becomes:

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

Worthwhile noting is that I can trigger the following wasm-bindgen error by adding/removing the --export-all linker argument. Suggesting that the LLVM linker was responsible for removing this section before it could be processed with wasm-bindgen.

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