I noticed that the (addresses of the static variables of rlib from binary) and the (addresses of static variables of rlib from dylib) are equal, when I change dylib to cdylib, this behavior disappears, do I think correctly that in this case rlib behaves like a dynamic library?
And is this behavior caused by my -C prefer-dynamic flag? And why this optimization does not apply to higher crates (e.g. std) and I have to set -C prefer-dynamic?
When compiling a rust dylib rustc will by default attempt to statically link all crates into the dylib except when either one of the crates is only available as dylib or -Cprefer-dynamic is used, the it will attempt to dynamically link all crates and fallback to statically linking where necessary. When linking a rust dylib which statically links an rlib, this version of the rlib embedded in the dylib will be used rather than statically linking the rlib into the executable. When a dependency is only available as dylib cargo will add -Cprefer-dynamic automatically. This will cause libstd to be dynamically linked. If cargo didn't do this, a rustc bug would be hit whereby it gets confused by the existence of both the statically linked libstd in the rust dylib and the dylib version, making it try to pick the dylib version when linking the binary, which will result in rustc emitting an error as you can't link a crate twice.
How did you get adding a cdylib dependency to the binary working? That shouldn't be possible. A cdylib doesn't export a rust interface, only a C FFI interface.
I wrote a little incorrectly, I didn't use cdylib as a dependency, I just imported Symbols.( I'll try to express my thoughts more clearly). Naming`
B-binary,
D-dylib,
R-rlib.
R is a static library I created, there is no dynamic version on my computer. I noticed when B and D import R (which is available only and only in static form), it is not embedded 2 times for each crate (I found out by comparing the addresses of a static variable)
Does it mean that the compiler somehow optimizes and loads R only once? But if I turn my lib into a cdylib that exports "C" Symbols, and import "C" Symbols from it to B, then the addresses become different (R in this case is also available only as rlib)
R gets linked into D, then when compiling B, rustc will notice that D already contains a copy of R and use this one instead. If there were two different dylibs linking R and you try to use both dylibs in B, rustc would error out as it can't find a way to prevent R from getting duplicated.
A cdylib is entirely independent of any rust code that may link it. A cdylib will statically link every dependency and ensure that only #[no_mangle] symbols are exported and thus none of R's symbols. Then when using the cdylib from B, rustc will see it as an opaque blob without any knowledge that R was linked in, thus causing it to be duplicated.