Conversation
|
r? @TaKO8Ki rustbot has assigned @TaKO8Ki. Use Why was this reviewer chosen?The reviewer was selected based on:
|
rustc uses heuristics to determine whether the self-contained path should be on the linker search path. It's important to get these right, because if self-contained is improperly missing from the search path, linking will fail (as seen in [1]), but if it's improperly present, a broken executable can be produced due to e.g. linking two different libcs (as seen in [2][3]). All of this works reasonably well when rustc is doing the linking, but when linking is done externally, there's a problem: there's no way for a build tool to know whether rustc would include the self-contained path or not. Without a way to find this out from rustc, the only way for a build tool to correctly link with a staticlib produced by rustc is to exactly reimplement rustc's heuristics. Not ideal. The existing rustc --print native-static-libs option exists to enable build tools to find out what linker flags should be used when linking a rustc-produced staticlib. Without including the argument to add the self-contained directory to the search path when necessary, though, it doesn't meet its intended purpose — build tools relying on `native-static-libs` will still sometimes do the wrong thing. Fixing this will make it possible for build tools to link the correct self-contained libraries when necessary, without each build tool having to match rustc's heuristics itself. This will enable fixing real problems encountered with Meson, where either self-contained libraries were not found, or self-contained libraries were incorrectly linked. [1]: mesonbuild/meson#15216 [2]: https://bugs.gentoo.org/970166 [3]: https://bugs.gentoo.org/967728
0d8d502 to
6d07079
Compare
|
If you are building a staticlib, I wouldn't expect it to contain self-contained artifacts. Whatever executable/dylib you link it into already has to either provide those artifacts for itself or get them from the system even if the rust staticlib wasn't linked in. The self-contained artifacts consists of a linker, libraries and object files (think |
|
The staticlib in this case does not contain/bundle artifacts, but it might expect to link with e.g. rustc's self-contained libunwind. If I build a staticlib with rustc's +crt-static x86_64-unknown-linux-musl target, it's expected to be ultimately linked with libunwind even though the musl C toolchain probably doesn't provide that by default. In a mixed Rust+C program, if rustc does the final link, it will link with the self-contained libunwind. Presumably, since the libunwind requirement is coming from the Rust part, that same libunwind (from rustc's self-contained directory) should be used when the C toolchain happens to be doing the final link. |
|
(Building pure Rust applications with Meson works fine, because then rustc does the final link.) |
|
The standard library needs either libunwind or libgcc (libgcc_eh.a or libgcc_s.so) as unwinder. It is important that only one unwinder ends up getting linked into the entire program to ensure dynamic registration of unwind tables will always be done against the same unwinder as the one that does the actual unwinding. If your C toolchain comes with libgcc instead of libunwind you should probably link against that instead. If your C toolchain provides neither, is it not capable of compiling C++ code? |
|
I believe it provides libgcc_eh.a, but per bootstrap.example.toml, rustc will only ever use libunwind for musl +crt-static, not libgcc_eh. Lines 1075 to 1077 in f0b782b |
|
(And if I am supposed to link against libgcc_eh anyway, that means I can't trust the output of native-static-libs, which includes -lunwind, even though it may not exist outside of self-contained.) |
|
r? compiler |
|
@rustbot reroll |
|
@rustbot reroll |
|
@rustbot reroll |
|
@rustbot reroll |
|
r? me |
Wouldn't the solution here be to link libunwind only if self-contained mode is active? |
If we didn't explicitly link libunwind, no unwinder would be linked at all. |
|
If we are not in self-contained mode the user has to supply Musl objects and libs, either by linking with I forgot that we handle unwind library linking via |
If the user statically links the executable, linking libgcc is not enough. libgcc_eh also needs to be linked. And even if that may be the default of gcc and clang, we explicitly disable linking to default libraries on most targets. |
My bad there, I thought of libgcc unwind library (libgcc{_eh,_s}) when writing libgcc.
Yeah, but then we explicitly link the unwind library. So, ideally for musl we'd link:
|
|
We don't know if the host toolchain uses libgcc or compiler-rt, right? In the latter case libunwind would still be used I think. |
Builtins and unwinder are two distinct things. First one is handled by Perhaps we could use target-feature akin to |
libgcc_s contains both. So you can't use libunwind when dynamically linking libgcc. |
Well, yes it's a linker script that links
I don't understand. You cannot use libuwind when linking either libgcc unwinder, be it libgcc_s or libgcc_eh. Still you can use LLVM's EDIT: fixed typo. |
|
If you statically link libgcc.a you have the option to use libunwind instead of libgcc_eh. If you dynamically link libgcc_s.so (which I assumed would be providing the compiler builtins instead of libgcc.a), you don't have the option to use libunwind. |
|
I think I see where the confusion is coming from. You could say that symbols from So, to rephrase it. You (almost) always need the unwinder (shared: If we had target modifier to control the unwinder, we could let the user decide which one to use (unless I'm missing something). Rather than forcing one whether linking Musl statically or dynamically. But that's a much more complex solution. Coming back to the solution proposed by this PR, Regarding https://bugs.gentoo.org/967728 I suppose I think mesonbuild/meson#15216 is an unfortunate workaround for our shortcomings in this area, because AFAIK the files layout is an implementation detail and therefore not guaranteed. |
Alas it is more complicated than this! My toolchain does not have libgcc_eh.a, because libgcc is built with --disable-shared. In this case, there's no need for separate static/non-static unwinding implementations, so unwinding just gets built into libgcc.a. This means the right thing for rustc to do in this case would be to link -lgcc. It's not clear to me how this should be accomodated in rustc. Whether to link libgcc_eh.a or libgcc.a depends on how the toolchain was built. GCC knows which to link, but that doesn't help us given we tell it not to include default libraries. We could try detecting whether libgcc_eh.a exists before invoking the linker? Maybe we could do something with a linker script? I'm not sure there's a better solution.
It certainly seems that this isn't the right fix for my problem, since it turns out that I shouldn't even be linking libunwind! I plan to propose a revert of my Meson PR, since it's clearly not right and is causing people problems. |
|
Maybe we should stop using |
|
That would certainly make me happy! |
Gotta love when decisions made 20 years ago still haunt us today...
It's fine to link libunwind if you know that's the only unwinder. But indeed you often don't know it upfront.
Is it just me, or does this start drifting into a total makeover of how we handle "system" libs linking?
I'm afraid Frankly, I believe the least hairy way for musl hosts (and some others like MSYS2) there is right now, is to patch Rust compiler to just get rid of self-contained. |
|
r? bjorn3 I think you have a better understanding of what's happening here than I do. |
View all comments
(I suggest reviewing with whitespace ignored.)
rustc uses heuristics to determine whether the self-contained path should be on the linker search path. It's important to get these right, because if self-contained is improperly missing from the search path, linking will fail (as seen here), but if it's improperly present, a broken executable can be produced due to e.g. linking two different libcs (as seen here and here). All of this works reasonably well when rustc is doing the linking, but when linking is done externally, there's a problem: there's no way for a build tool to know whether rustc would include the self-contained path or not. Without a way to find this out from rustc, the only way for a build tool to correctly link with a staticlib produced by rustc is to exactly reimplement rustc's heuristics. Not ideal.
The existing
rustc --print native-static-libsoption exists to enable build tools to find out what linker flags should be used when linking a rustc-produced staticlib. Without including the argument to add the self-contained directory to the search path when necessary, though, it doesn't meet its intended purpose — build tools relying onnative-static-libswill still sometimes do the wrong thing. Fixing this will make it possible for build tools to link the correct self-contained libraries when necessary, without each build tool having to match rustc's heuristics itself. This will enable fixing real problems encountered with Meson, where either self-contained libraries were not found, or self-contained libraries were incorrectly linked.