What is the Difference Between `dylib` and `cdylib`

Hello everybody,

I'm trying to understand what the difference between dylib and cdylib are. I want to understand better how to work dynamic linking in Rust. I wrote a tutorial with a minimal example of how to do plugins in Rust, using dylib, but I've also seen a comment on GitHub about dylib being a world of pain right now.

I understand that using dylib would require using the same exact version of the rust compiler and that isn't a concern for me, but I've seen a cargo issue that that brings up the issue that Cargo is not going to build the dependencies of a library that I build as dylib which would mean that I need to manually compile all of the dependencies, which could result in linking issues, so it wouldn't actually solve the problem anyway. cdylib is supposed to be a decent enough solution, as far as I can tell, but the size of cdylib's are much larger than their equivalent dylib when I test that with my minimal example codebase. This makes me think that the cdylib is bundling more code into the library and possibly statically linking dependencies like the standard library, which sort of defeats the purpose of using the dylib which is supposed to avoid bundling dependencies into every plugin.

Also, on a side note, it looks like the rpath Rust codegen option also doesn't work with cdylibs.

In summary, I'm trying to understand the differences in behavior when I change the crate type from dylib to cdylib in my example. What is the cause of the following differences:

  • The cdylib libraries are much larger than the dylib libraries. 1.5-1.8M compared to 14kb-500kb in my example.
  • The -C rpath rust flag doesn't cause the cdylibs to be loaded relative to the binary's path.

And also:

  • What is the difference in how the dependencies of a cdylib and a dylib are bundled/linked, including how the standard library is linked?
12 Likes

OK, here is my current understanding of different Rust library types.

Rlib

rlib's are Rust static libraries. They contain all of the metadata and code necessary to build a Rust crate and link it into another Rust crate statically. Given just the rlib for a crate, you can include that crate into a Rust program by using extern crate crate_name. Even if you are dynamically linking a crate like a .dll, .so, etc., you will still need to have the rlib to include that crate into another crate because they shared library is missing some of the required metadata ( I think ).

Cdylib

cdylib's are primarily designed for building shared libraries that can be linked into C/C++ programs.

  • They have a minimum size of ~2.2M on Linux, so the smallest cdylib is larger than the smallest dylib. This might be because it statically links the standard library.
  • They are designed for building a C ABI that can be dynamically linked to C/C++ programs ( and Rust programs that define extern blocks )
    • If you want to expose any portion of the a cdylib's interface over the C ABI you must use Extern Functions.
    • If you want to link a Rust program to a Rust cdylib over the C ABI you have to use Extern Blocks ( See Rust reference doc ).
  • When building a cdylib, any functions that are not exposed through an extern block will be automatically stripped from the generated library as an optimization.
    • For example, if you build a cdylib for a large rust library and you do not export any functions using the extern keyword, the library will be essentially empty and will be about 2.2M ( because that is the minimum size for a cdylib, again, possibly because it statically links the standard library ).

Dylib

dylib's are Rust shared libraries which have an unstable ABI that can change across Rust releases.

  • To build a dylib, you probably need the -C prefer-dynamic rustflag set so that it will not attempt to statically link the standard library.
  • Within the same Rust version, you can dynamically link to a Rust dylib from a Rust crate without having to use extern functions or blocks because it will go over the Rust ABI.
  • dylib's will not strip out any unused functions when built. Even if none of the functions in the library are explicitly expose or used in the crate, all of the functions will still be included in the generated library.
27 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.