Why do I need to set the crate-type to cdylib to build a wasm binary?

When building a wasm binary, the crate-type must be cdylib, but since the wasm binary itself is a proprietary binary format, there seems to be no need to set it to cdylib I think.

Why cdylib?
Why not dylib or rlib?

I have done a lot of research but could not find the answer to this question.
If anyone knows, I would appreciate it if you could let me know.

The cdylib crate type tells the Rust compiler to create a dynamic library that is loadable at runtime (typically to access a C API - hence the c bit). When compiling to WebAssembly this results in a *.wasm binary, on Windows this will be a *.dll, on MacOs this will be a *.dylib, and on Linux this will be a *.so.

If you don't set the crate type as cdylib, it'll compile to a library that the Rust compiler can use when linking with other crates. This has the *.rlib extension, which isn't in the WebAssembly format.

This page explains the different crate types:

https://doc.rust-lang.org/reference/linkage.html

1 Like

If you don't set the crate type as cdylib, it'll compile to a library that the Rust compiler can use when linking with other crates. This has the *.rlib extension, which isn't in the WebAssembly format.

Thank you:)
Am I correct in understanding that *.rlib is incompatible with the wasm format, but *.dylib is compatible?
Also, when rustc (strictly LLVM?) generates the wasm binary, does it mean that it is generating it from dylib?

The only crate type that is compatible with WebAssembly is cdylib.

The rlib, lib, and dylib formats are purely for the Rust compiler and used when linking crates together (if you are familiar with C, think of them as *.o files).

A *.dylib will be in the Mach-O format, a *.dll will be in the PE format, and *.so is an ELF file. All three are incompatible with WebAssembly and are the native executable format for MacOS, Windows, and Linux respectively.

Not necessarily - the compiler can generate a cdylib from most of the crate types. So it could consume dependencies as an rlib and compile the resulting program/library to a cdylib.

You will almost never need to care about crate types, by the way. The only time it really makes a difference is when you are exposing a C API that will be used by non-Rust languages (e.g. to be loaded as WebAssembly in the browser) and need to output your library in a specific format.

There are a lot of nitty-gritty details I'm glossing over, but hopefully that all made sense.

1 Like

Thank you :slight_smile:

I apologize for my lack of understanding.

My understanding is that the cdylib crate is a configuration for creating dynamic libraries such as *.dylib, *.so, *.dll, etc.
I don't quite understand why it is needed to generate *.wasm. (I do appreciate the detail you provided)

Is it because the artifacts needed to generate *.wasm during the compilation process can only be created by cdylib?

Maybe "how the compiler generates *.wasm" is what I really want to know...

It's not that cdylib invokes some necessary thing that the compiler could not do otherwise; the compiler could make crate-type mean whatever it likes. Rather, cdylib accurately describes a WebAssembly module, or at least much more accurately than the other crate types:

  • lib, rlib and dylib are all for further Rust compilation operations.
  • It's not a bin because it exports symbols, not a single main() entry point.
  • It's not a staticlib because we're not going to perform static linking on it.

So, cdylib is the most fitting choice β€” a dynamically loaded (into the WebAssembly runtime) library (or 'module' in WebAssembly terms) that exports symbols. As the docs put it: β€œThis is used when compiling a dynamic library to be loaded from another language.”

6 Likes

I think the confusion might be due to you conflated wasm32 (the target) and wasm (the file type).

the target wasm32 (currently wasm32-unknown-unknown and wasm32-unknown-emscripten will show up by rustup target list) tells the compiler to choose the wasm32 backend as code generator, it has nothing to do with the crate-type.

wasm is the file type for the cdylib crate type on the wasm32-xxxx-xxxx target, the same crate type might have different file type on different target triplets, e.g., dll on windows, so on linux, etc.

if you are building a crate for the wasm32 target, it desn't neccesarily mean the crate type must be cdylib, you can perfectly build other crate types for the wasm32 target (for instance, the dependency crates will most likely be built as default lib type).

the crate type only matters for the "main" crate: if you want to run some program on wasm32, the runtime/vm/interpreter/whatever only accepts modules of the wasm file type, which is built from a cdylib crate; just like if you want to run a program on windows, the operating system will only load exe file type, which is built from a bin crate, (although listed [[bin]] in Cargo.toml, crate-type is always bin and cannot be overwritten).

does that clear any of your confusion?

1 Like

Thank you for the detailed explanation.
Maybe, I think I understand now.
Thanks to everyone else for their detailed explanations as well.
It helped me a lot :slight_smile:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.