Code change:
<ins> //! This is a regression test for #129020 //! It ensures we can use `/WHOLEARCHIVE` to link a rust staticlib into DLL //! using the MSVC linker //@ only-msvc // Reason: this is testing the MSVC linker use std::path::PathBuf; use run_make_support::{cc, cmd, env_var, extra_c_flags, rustc}; fn main() { // Build the staticlib rustc().crate_type("staticlib").input("static.rs").output("static.lib").run(); // Build an empty object to pass to the linker. cc().input("c.c").output("c.obj").args(["-c"]).run(); // Find the C toolchain's linker. let mut linker = PathBuf::from(env_var("CC")); let linker_flavour = if linker.file_stem().is_some_and(|s| s == "cl") { linker.set_file_name("link.exe"); "msvc" } else if linker.file_stem().is_some_and(|s| s == "clang-cl") { linker.set_file_name("lld-link.exe"); "llvm" } else { panic!("unknown C toolchain"); }; // As a sanity check, make sure this works without /WHOLEARCHIVE. // Otherwise the actual test failure may be caused by something else. cmd(&linker) .args(["c.obj", "./static.lib", "-dll", "-def:dll.def", "-out:dll.dll"]) .args(extra_c_flags()) .run(); // FIXME(@ChrisDenton): this doesn't currently work with llvm's lld-link for other reasons. // May need LLVM patches. if linker_flavour == "msvc" { // Link in the staticlib using `/WHOLEARCHIVE` and produce a DLL. cmd(&linker) .args([ "c.obj", "-WHOLEARCHIVE:./static.lib", "-dll", "-def:dll.def", "-out:dll_whole_archive.dll", ]) .args(extra_c_flags()) .run(); } } </ins>

Related discussion:
text: So the DLL is created here: is used so that the DLL includes every single object in the staticlib, even if it's unneeded or indeed causes conflicts. But then is used to add a which presumably defines what actually gets exported from the DLL. What I'm not understanding is what would be different if, for MSVC, it just linked normally without ? I.e. using instead.
On MSVC, static linking doesn't let you reexport dependencies' symbols automatically, they're subject to DCE. . However, PE-COFF static libraries don't support symbol visibility, so the is there to make all Rust symbols private and keep only the librsvg ones. See e.g. and for consequences of not blocking out symbols like .
Sure but the should work regardless of if is used or not because using the export will force the linker to go looking for the symbol(s) listed in the file. E.g. as a test I have the following static lib (using to make symbols easier to find): Which I compile into a static lib using: rustc -O --crate-type=staticlib And I have the following file: Which for simplicity I compile via rustc but I'm using an empty file and also raw linker arguments: rustc -O --crate-type=cdylib -C link-args=" " This compiles and if I see the two functions I wanted: No std symbols are exported.
Independent of whether whole-archive is necessary for this specific use case, we should support linking rust staticlibs with whole-archive, even if because of the fact that not linking with whole-archive can mask linker errors, which will later show up when any change to the cgu partitioning is made, which often causes people to report a regression even though their crate is at fault.
If I repeat the above using even in this simple case I get a bunch of errors, not just : I'm not really sure if rustc can currently guarantee that whole archive will work without doing some of the work of a linker. Which sounds like a new feature and not specific to MSVC.
All duplicate symbol errors for are caused by That it works without is by accident and likely to break in case of cgu partitioning changes.