-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Store metadata in import libraries for MSVC #39669
Conversation
r? @arielb1 (rust_highfive has picked a reviewer for you, use r? to override) |
☔ The latest upstream changes (presumably #39694) made this pull request unmergeable. Please resolve the merge conflicts. |
src/librustc_metadata/locator.rs
Outdated
@@ -889,6 +889,24 @@ fn get_metadata_section_imp(target: &Target, | |||
let blob = MetadataBlob::Raw(buf); | |||
verify_decompressed_encoding_version(&blob, filename)?; | |||
return Ok(blob); | |||
} else if target.options.is_like_msvc { | |||
// Treat the import library as though it were an rlib! | |||
let ref implib_filename = filename.with_extension("dll.rlib"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks basically equivalent to the rlib branch above, can these branches be shared?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, will do that
src/librustc_trans/back/link.rs
Outdated
let _ = fs::create_dir_all(dst_dir); | ||
let ref dst = dst_dir.join(filestem).with_extension("dll.lib"); | ||
|
||
// Modify import library to remove metadata before linking |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to emit the symbol with a visibility level that we don't have to do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or otherwise, can you comment as to why we're doing this?
cc @vadimcn This looks pretty good to me, but ideally we'd unify code paths as much as possible to avoid too much divergence between platforms. It seemed a little odd to me to be frequently frobbing between |
Does the metadata really have to be removed from the |
I'll add more of a description in the comments, but for anyone reading, the new WRT the back and forth between For the reverse direction, I tested both with and without the code to remove the metadata prior to linking. While not removing the metadata seemed to work™️, I wasn't confident enough that there wasn't some edge case where it would fail, say under different linker flags. It's also what we do for |
Sounds like we are doing a bunch of unnecessary I/O every time we are linking. All for the sake of not having an extra file around? @alexcrichton: IMHO, we should just bite the bullet and move metadata to a sidecar file for all library formats on all platforms. |
@Diggsey If not removing the metadata before linking works, and the resulting binary doesn't suddenly become bigger, then we should definitely not waste time removing the metadata until someone can demonstrate an edge case where it does fail. |
@Diggsey I'm not sure what you mean about rlibs, we don't store metadata as an object file in there? We take it out manually when we pass @vadimcn do you feel that should block this PR? Or happen in parallel? |
@alexcrichton: I am not super-opposed to landing this, but opposed nevertheless - on the grounds that every special case we add becomes an extra bit maintenance burden later. It is already hard to follow all the special cases we have in link.rs |
@vadimcn yeah that's true. @Diggsey can you elaborate on the technical rationale for doing this on Windows? @vadimcn I think we'd want to consider such a change carefully though as it'd be changing the binary layout of other platforms which is susceptible to cause breakage. Whereas with windows there's already an extra file to place metadata into it seems there's a much lower risk of breaking things (although I'd prefer to avoid changing the name if possible) |
I simply meant that the metadata was stored as an additional file within the archive, not that it was a valid object file. I think my confusion stems from the fact that there is no It might be better if the
I explained this in the RFC, but to summarise:
|
I agree with @vadimcn that more platform-specific code means more platform-specific code, introducing more vectors for bugs and such. I also agree though that this is the "proper" solution to the problem on MSVC, however. I don't think the technical benefits here are really all that much, almost no one is shipping Rust dylibs much less on MSVC. I'd still personally be ok landing this PR, however. (with comments addressed) |
Cool, I'll make the changes ASAP. (Also, you are shipping rust dylibs on MSVC 😉 ) |
d84efba
to
43a5561
Compare
Remove metadata objects from rlib import libraries Fix tidy issues Don't try to remove metadata before linking Undo change to dylib linking
43a5561
to
9a58016
Compare
Updated and squashed |
I'm a little unsure about how to proceed with this PR. I agree with @vadimcn that all the extra casing in an already very complicated backend isn't great. The technical benefits seem slim to only improving file size of the dll itself, but my guess is that this PR as-is actually inflates the size of the rustc distribution at least (due to metadata being stored uncompressed in import libraries. I think it'd be a slam dunk, though, if we had some concrete numbers showing something like the compiler loads X% faster or we save Y bytes in the distribution. @Diggsey you wouldn't happen to have any of those numbers would you? |
If metadata is stored compressed in the dll originally, is there any reason we can't store it compressed in the import library? |
Not particularly, no. It's not what this PR does, nor is it what we do on any other platform. I don't think it would help the "this is just adding more special cases" counterargument as well. |
@alexcrichton Here is a list of DLL sizes and the changes:
Of these DLLs, the ones that exist in
Overall, the losses and gains balance out, and there is almost no change to the overall rust distribution size. However, there are real savings for programs built with rust which use dynamic linking. Even the smallest dynamically linked rust program saves ~1.4mb due to the reduced size of |
Ok but to clarify, we don't know of any programs using dynamic linking? (it's barely supported by Cargo/rustc). Also to clarify, what do you mean that a dynamically linked program will save memory? The contents of the dll don't go into the executable? Do you mean the metadata sections don't need to get loaded into memory? |
I didn't mention memory? However, now that you bring it up, the DLLs being smaller means that they should use less memory when loaded. As far as programs using dynamic linking: the RLS, clippy, and rust itself use dynamic linking, not because they rely on a plugin architecture (which AFAIK is the only benefit of dynamic linking not well supported by rust atm) but because there are multiple binaries with common dependencies, and so dynamic linking has the potential to save space. Most programs (unlike rust) are not compilers, and so would not need to distribute the import libraries. |
Sorry I meant that you claimed a rust program save 1.4mb, but I don't know where this is coming from. None of those programs distribute dlls though, so I don't think there's any gains to be won there? It sounds like this change as-is does:
Overall I'm not particularly in favor of this given these numbers unfortunately. |
ping @Diggsey, any thoughts on my last comment? |
If clippy were to ship in binary form, it should be distributing those DLLs. RLS doesn't need to because it's going to be shipped as part of rust. Overall, I think the biggest point in favour of this is |
But none of the reflects reality? The one user shipping dlls, the compiler, is hurt by this change? |
none of those* |
Not to my knowledge, although I wouldn't necessarily know - for example, do either servo or firefox dynamically link their rust components? Based on comparable C/C++ applications, distributing DLLs is exceedingly common. However, if you think that rust is sufficiently far from reaching that point that it's not worth optimizing for yet, then I'll close this. |
☔ The latest upstream changes (presumably #40867) made this pull request unmergeable. Please resolve the merge conflicts. |
triage: we discussed this in the tools meeting. It sounds like the benefits of this PR will not be realised until we have better dynamic library support and it adds complexity to an already complex part of the code base. Closing for now, potentially worth revisiting if/when we distributing DLLs is more common-place. @michaelwoerister suggested that an alternative that works today is making a cdylib where we already strip metadata. This works even with Rust code, as long as you only need the C API. |
This reduces the size of rust dylibs by an order of magnitude in some cases.