11

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
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Armeen Moon
  • 18,061
  • 35
  • 120
  • 233

1 Answers1

8

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.

Markus Klein
  • 1,202
  • 12
  • 10
  • 1
    Any docs on what makes a dynamic library "dynamic"? Sorry for ignorance :( – Armeen Moon May 21 '19 at 16:52
  • I think ignorance is ok on a site specifically designed to ask questions ;-). Sadly I can not think of any reference stating the exact differences between static and dynamic libraries. On the top of my hat I can think of two things though: First: Dynamic libraries have to compiled with position independent code, although this is nowadays also the default for static libs. Second: Dynamic libraries provide an initialization function to be called then they are loaded. Usually this is used to initialize their global symbols. – Markus Klein May 22 '19 at 15:32