-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
linking staticlib files into shared libraries exports all of std:: #33221
Comments
I'm curious, how do y'all end up doing this? We have a few options in Rust for what's going on here, but it may not quite overlap with what you're doing:
Those are some ideas off the top of my head at least, but depending on what Gecko is already doing we can likely do something similar :) |
cc @brson, @rust-lang/tools |
We compile with On Windows I believe we don't have to do any of this because the default is to have local symbols in the library and you explicitly export what you want. (We wrap STL headers on Windows, but for different reasons.)
Ah, that's super-useful all on its own! We should definitely start doing this.
Is that with I don't think a linker script would work for us, because of the messiness of specifying the appropriate symbols (C++ symbol mangling, lovely), but it might be worth investigating.
That was the possibility I initially thought of, but then I assume you'd have to compile objects separately for shared vs. static libraries or play weird linking tricks. The number of symbols that |
This is not really an issue on Windows with msvc due to symbols only being exported from a DLL if they are marked as |
Awesome, thanks for the info! I was discussing with @brson a bit today about symbol visibility, and our prospects may be bleak in doing something like change by default to hidden visibility (due to backcompat concerns now). In general though it seems that not a lot of thought has gone into the visibility of symbols in Rust beyond "internal or public", and it seems that hidden/protected/default linkage (at least in LLVM terms) is a whole new suite of choices within the "this is a public symbol" option. All that basically to say, the compiler probably can't generate hidden symbols today (LLVM certainly can, we just haven't bound it), and it's not the clearest how we'd want to do that just yet. Should be possible in the long term of course though!
One note about LTO is that it retains all
Yeah, although once you enable Rust LTO the --gc-sections option shouldn't actually do much else (unless you rely on it for stripping C code)
Ah yeah so to clarify, Rust LTO isn't like C LTO where we have a special object file format or something like that and the linker takes care of it. Rather Rust LTO is our way of saying "take the whole world of Rust code, optimize it all together, then emit one object file". We do this by loading LLVM bytecode from rlibs, internalizing all symbols, then throwing it at the LLVM optimizer. So to answer your question, this LTO happens at staticlib generation time. The .a archive will just have a smaller object file (as much of it will be stripped), and that object shouldn't necessarily be special in any way.
Yeah right now we use the same object file for
Right yeah most of this stuff is just for future monomorphizations. An example of this is that all format strings in rust (e.g. Basically all that is to say that these symbols are basically just a ton of internal implementation details, and it should be totally fine to hide all of them so long as other Rust code can still link to them. (aka this sounds like exactly hidden visibility) |
Adding However, the library filesize went from 5033882 to 6321450. |
@rillian you're sure optimizations are turned on, right? (e.g. |
No, that was an unoptimized build. Trying with -O now. |
Ok, in an opt build |
See https://bugzilla.mozilla.org/show_bug.cgi?id=1268547 about turning this on for gecko. |
This might be the same underlying problem as in #37530. |
Some more comments on this thread -- https://internals.rust-lang.org/t/rust-staticlibs-and-optimizing-for-size/5746 |
Consider this toy example:
Compile and link:
With rust 1.8.0, we have:
which is quite large (2MB!) for such a simple program. Despite all of
std
being compiled with the moral equivalent of-ffunction-sections
, adding-Wl,--gc-sections
does very little to slim down the binary:That's only about 400 bytes eliminated, which seems suboptimal.
The problem is that all of the public functions in
libstd.rlib
are marked as global symbols. Whensl.a
is linked into a shared library, all of those global symbols fromlibstd.rlib
are now treated as symbols that the newly-created shared library should export as publically visible symbols. Which creates bloat in terms of a large PLT the shared library must tote around as well as rendering-Wl,--gc-sections
ineffective, as virtually everything is transitively reachable from these public functions fromlibstd.rlib
.hello.so
has ~5000 visible functions, when it should really only have a handful.hello.so
contains code for parsing floating-point numbers, even though it really shouldn't, according to the functions shown above.This example is admittedly contrived, but Firefox's use of Rust is not terribly dissimilar from this: we compile all the crates we use into rlibs, link all of the rlibs together into a staticlib, and then link the staticlib into our enormous shared library, libxul. We're pretty careful with symbol visibility; we have hundreds of thousands of symbols in libxul, but fewer than 500 exported symbols. We would very much like it if:
std
(or otherwise) that it doesn't use.We didn't think terribly hard about this when we enabled Rust on our desktop platforms (though we should have), but our Android team cares quite a bit about binary size, and Rust support taking up this much space would be a hard blocker on our ability to ship Rust on Android. It would be somewhat less than the above because we'd be compiling for ARM, but it'd still be significant. (I assume the situation is similar on Mac and Windows, though I haven't checked.)
cc @alexcrichton @rillian @glandium
The text was updated successfully, but these errors were encountered: