Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why must a WASM library in Rust set the crate-type to cdylib?

The Rust reference states:

A dynamic system library will be produced. This is used when compiling a dynamic library to be loaded from another language. This output type will create *.so files on Linux, *.dylib files on macOS, and *.dll files on Windows.

My WASM is not a *.dylib, *.dll, or *.so... so why must the crate type be set to cdylib? What is really happening under the hood?

lib.rs

#[no_mangle]
pub extern fn add_one(x: u32) -> u32 {
    x + 1
}

Cargo.toml

[package]
name = "utils"
version = "0.1.0"
authors = [""]
edition = "2018"

[dependencies]

[lib]
crate-type = ["cdylib"] // Why is this needed

index.html:

<!DOCTYPE html>
<html>
  <head>
    <script> 
      fetch("utils.gc.wasm")
        .then(response => response.arrayBuffer())
        .then(result => WebAssembly.instantiate(result))
        .then(wasmModule => {
          const result = wasmModule.instance.exports.add_one(2);
          const text = document.createTextNode(result);
          document.body.appendChild(text);
        });
    </script>
  <head>
  <body></body>
<html>

Terminal:

$ cd utils
$ cargo build --target wasm32-unknown-unknown --release
$ wasm-gc target/wasm32-unknown-unknown/release/utils.wasm -o utils.gc.wasm
$ http
like image 768
Armeen Harwood Avatar asked May 20 '19 20:05

Armeen Harwood


1 Answers

It is exactly as the Rust reference states: We are creating a dynamic library to be loaded from another language. So why is the output neither .dll, .so or .dylib? That is because we are not compiling for either Windows, Linux or MacOS. We are compiling for wasm32-unknown-unknown. So the only shortcoming of the reference here is not listing all possible platforms and their dynamic library file endings.

We need a dynamic library, because dynamic libraries can be loaded at runtime (typically by the browser). Rust libraries have to be statically linked to be used.

An extra tidbit of information of what is going on under the hood:

If you invoke the wasm_bindgen macro it will (among other things) expand the signature of a function into a C function.

#[wasm_bindgen]
pub fn my_function() 
#[export_name = "my_function"]
pub extern "C" fn __wasm_bindgen_my_function()

Why a C Function? Function calls can differ from language to language. By mangling, order of the arguments on the callstack, etc. . This is called the ABI. C has the distinct advantage of having a defined and stable ABI, which is why it is a popular choice for foreign function interfaces.

like image 137
Markus Klein Avatar answered Nov 01 '22 10:11

Markus Klein