ABI stability guarantee of dylib vs cdylib

I have a host and plugin DLL written in Rust, both host and plugin use types defined in a shared crate without any marshalling across the DLL boundary, assuming the ABI is the same for all of these types when host and plugin are compiled with the same nightly.

  1. Is this assumption valid with crate-type = ["cdylib"]?
  2. Is this assumption valid for dylib?

Here someone wrote:

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.

But they only wrote it for dylib, not cdylib.

Someone on discord told me that even with the same nightly the ABI could change between compiler invocations and that there are NO guarantees.
Which is also written here:

ABI and even layout can change between any two compiler invocations even if they are 100% identical

In the linkage docs it says for dylib:

The resulting dynamic library can be used as a dependency for other libraries and/or executables.

It says nothing explicitly about ABI stability guarantee between different compiler invocations but implies it!
Otherwise, using the dylib as a dependency would only work when both are compiled in the same compiler invocation. And if that was the case, surely that would be mentioned here, right?

So: Does using dylib instead of cdylib give me any more ABI stability guarantees?
Or does even cdylib have the guarantee that if host and plugin are compiled with the same nightly, the types will use the same ABI?

Currently I'm using cdylib (to get a lean DLL without unused symbols) and don't do marshalling because firstly it's much more convenient and also I need lowest latency for host<->plugin communication. And it seems to work right now with cdylib and compiling both with the same nightly. But future nightlies could change the ABI with every invocation?
Even things like trait layout?
(My DLL entry point returns a trait object (*mut dyn Plugin from Box::into_raw) which the host takes ownership of).

That was me. :slight_smile:

Just a disclaimer, that post was actually me mostly asking for answers and then doing the best I could to provide them myself based on research and experimentation.

I actually didn't know you could use cdylib and still link Rust crates over the Rust ABI. I thought only dylib's worked like that, but I guess it makes sense that cdylib's would too.

Hmm, that's interesting. I hadn't heard that one before.

My guess, keep in mind it's a guess, is that the fact that you can link dylib's or cdylib's only work because the Rust ABI happens to be identical in this case and that neither of them are actually making any guarantees about the Rust ABI and that neither of them have an effect on the Rust ABI.

I believe that rustc currently reserves to itself the option of optimizing each struct, enum, and fn* call differently each time rustc is invoked. That permission increases the set of optimizations that the compiler can employ, including profile-guided architecture-dependent storage layout optimizations. Stated differently, rustc reserves to itself the right to improve its set of available code optimizations.

There is an ongoing effort on the Internals forum to specify a stable, modular ABI for Rust, which would support interoperation across different rustc invocations and point releases for items annotated repr(Rust).

2 Likes