@Diggsey it’s important to keep in mind that we’re pretty far removed from whatever the cl.exe compiler does as we’re driving link.exe directly. Things like that #pragma I believe just emit directives into the object file being generated which are then later parsed and dealt with in the linker. This means that everything in MSVC translates to some invocation of the linker, which is what’s relatable to what we’re doing in Rust.
I’m not really sure what it means to use a header in a dll or exe, but it’d be useful, however, to analyze the full process there. The header is included by some file which is then translated to an object file which is in turn passed to the linker (with these embedded directives). This all translates to some set of libraries being passed to the linker which may or may not look similar to what we do in Rust.
A primary point of the static linkage in Rust is to make distribution of native dependencies possible without distributing the libraries themselves. For example this means that we can build small C shims into an rlib and then forget about them, we don’t have to manually ship them everywhere next to our artifacts.
This is unfortunately simply a downside of C, you can’t really have private implementation details in a global namespace where you’re just using different versions of the same C library because both copies of the library have the same symbols.
Primarily this is quite rare, system libraries are almost never static libraries. This behavior is useful, however, to ensure that the linker robustly succeeds in all cases as well as everything gets resolved to the right invocation. Failure modes include:
- If a library isn’t bundled then an intermediate artifact which only included half of it could cause a linker failure somewhere else down the road.
- If you’re using two copies of a library, some library calls may be routed to one while others may be routed to another, this is almost always a situation where segfaults and unexpected behavior arises.
- Distributing a static library without having to actually distribute the library itself is quite useful
I think you’re conflating a lot of issues together here and it would be beneficial to tease them apart. It looks like this is quickly going down a slippery slope of “everything is awful” which makes it difficult to reason about what needs to be addressed vs what needs to be understood. I’ll try to address each point of this in turn.
Can you be more concrete here? I don’t understand what this looks like in Rust, what the failure modes are, or what we should do as a result.
I think this is a red herring, this is the exact same behavior for all platforms. The compiler does not know about the “system linker paths” and it’s just unfortunate that we have to actually calculate it on Windows. In order to be consistent here we would have to do this across all platforms, not just Windows.
As a result, this seems quite orthogonal to anything having to do with #[link].
That’s because this is incorrect. When a linker pulls in a static library it typically only pulls in the parts that are needed, not the entire library. This means that if you create a Rust dylib which links to a native static library it may not actually include all of the static library, which in turn can cause future linkage to fail.