-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
x86_64-unknown-linux-musl
with -Ctarget-feature=-crt-static
links to glibc
#135244
Comments
You need to install libgcc_s for musl. Rust needs libgcc_s.so for the unwinder, but musl doesn't install it by default. When statically linking without musl-gcc, rustc's bundled copy of libgcc.a is used instead. |
musl oesn't use the system GCC libgcc_s, and doesn't use its own. There is no way for me to install one. Either way it's broken. |
Musl itself doesn't use any unwinder. Programs that are compiled for musl however can use libgcc_s as unwinder if they want to. In that case you need to install a libgcc_s version compiled for musl. For example Alpine linux has the libgcc package for this: https://pkgs.alpinelinux.org/package/edge/main/x86_64/libgcc It seems like Archlinux doesn't have a package with a precompiled libgcc_s however. It doesn't have a package for any other unwinder that can be used either. By the way I was wrong about rustc using libgcc by default on musl when statically linking. Libunwind is used instead. Archlinux doesn't have libunwind compiled for musl either however. tl;dr: You will either have to statically link against rustc's bundled libunwind, you have to compile an unwinder for musl yourself or you have to compile on alpine with the libgcc package installed. |
Ultimately it doesn't matter as long as long as linking with musl-gcc is broken anyway (the missing libgcc_s only happens with musl-gcc as linker) Still, I think either rustc should detect systems/configurations where |
musl-gcc? |
wrapper script around gcc shipped with musl that passes in a .specs file that sets up the musl libraries, interpreter and crt. |
@richfelker Okay, I know we already have busted compilation semantics for musl atm, but what exactly should I be doing here for the unwinder on musl? Should I just ship a Rust unwinding library for musl targets? |
We already ship libunwind for musl when statically linking. When dynamically linking we can't safely use this however as there may only be a single unwinder in the whole program and one of the dynamic libraries the program depends on may already be linking against libgcc_s.so as unwinder, so we are forced to dynamically link against libgcc_s.so too as at least on Alpine linux that is the system unwinder that is used. Shipping our own libgcc_s.so copy would be an option, but that would only fix compilation. Not running it on Archlinux which should work if libgcc_s.so is part of LD_LIBRARY_PATH as the musl package also installs the correct dynamic linker and libc.so in the location where the executable would expect it. The correct solution I think would be for Archlinux to provide libgcc_s.so as part of their musl package or as separate libgcc-musl package. |
I can take this to their bug tracker tomorrow, I think this is solvable on their side. Where does that leave Rust? is musl-gcc the "correct" way to link to a dynamic musl & loader with Also, as a side note, musl-gcc seems to want to pull in |
I think libgcc_s.so is a dynamic library made by linking libgcc.a and libgcc_eh.a together. Statically linking libgcc_eh.a when dynamically linking musl may result in multiple unwinders in the same program, which is UB. |
I'm confused by this whole issue, especially text like:
A non-static musl target binary is only usable on a musl-based host or one where musl is installed alongside something else in
No, musl-gcc is a wrapper for evaluation purposes and compiling/linking simple C-only programs on non-musl hosts. It's not a proper cross compiler and not the right way (not even present) on musl-based hosts. I think this whole issue is confusing 3 different scenarios:
Case 3 seems to be what a lot of people are assuming when they hear "musl", but it shouldn't be considered exclusively at the expense of breaking the others.
This is not supposed to be the case. There is no good reason you can't have multiple unwinders in the same program, as long as they're all capable of processing the read-only unwind tables mapped at execution time. We do not intend to support the legacy "register eh frame" way of doing things; the unwinder is supposed to call If this is not working right, we should try to get it fixed. In any case I don't see how it's relevant. If you're static linking musl, you have to static link everything. There is no such thing (in the context of musl) as a binary with static libc but dynamic linked to other things. If you try to make such a thing, it will always come out broken, and that seems to be what's going on in the original issue report here. If you dynamic link musl, you must have dynamic target libs and a dynamic musl execution environment ( |
JIT's need to use |
I have some responses in mind to that but they're probably off-topic for this issue. If you believe it's necessary to use a single unwinder, then that's automatically achieved with static linking, and for dynamic linking - which is only valid on a musl-based host or if you're cross-compiling and have proper target libs for a musl-based environment - you just use whatever is the expected shared unwinder for the target system, most likely libgcc_s (built against musl and already there as part of the target environment). |
Yeah, that is kind of the point I was trying to make. For dynamic linking of musl rustc can't workaround Archlinux's musl package missing libgcc_s.so by bundling it's own unwinder. It has to be fixed on Archlinux's side by shipping libgcc_s.so for musl too. (and same for every other glibc based distro with a musl package that is missing libgcc_s.so) |
So then, is or can I understand that I might've put too many unrelated cases/information into my initial report in an attempt to be comprehensive, and it's lead to a lot of discussion I'm not well versed in. My primary issue is still that linking with |
This isn't specific to The answer is probably not to bundle them with musl but provide packages for whichever ones the user is likely to need. |
If you're building to use musl on a non-musl-based host, dynamic linking generally does not make sense unless the user is prepared to setup an environment for running foreign dynamic linked binaries. If "unsupported" is the word you want to use for that, ok, but it should be allowed for users who specifically want to, and of course makes sense for the case of cross compiling which is mechanically the same thing, or should be.
I don't understand how/why this is happening, but it suggests something is deeply broken in target handling/cross compiling. The host gcc compiler driver, library paths, etc. should not be used at all in this case. |
Unless you specifically override the linker, rustc will use the default linker for the target whether you are cross-compiling or not. This is fine when cross-compiling between 32bit and 64bit x86 for the same OS or when cross-compiling to a bare-metal target (where we set the default linker to lld and don't configure it to link against any C libraries) It also works fine when cross-compiling to statically linked musl as rustc tells the linker the directory to find libc.a and the crt objects for musl using |
It probably does, but this is a huge hack, not supported usage. It's almost surely broken on archs with specific ABI requirements that don't match glibc, and depends on having a suitable
If Rust wants to have this self-contained mode, I think it should ignore |
We are providing libc.a, libunwind.a and the crt objects.
If you try to use any other library you will get a broken executable.
Yeah, I may make sense to make the self-contained mode invoke the linker directly. And in fact in that case it should be possible to use the rust-lld we ship to not have any dependency on a host toolchain. As you said, it requires a lot of magic flags, but in the end it would be much less of a hack than we currently have.
I guess it would be possible to disable link-self-contained by default at the same time we change to -crt-static by default as the latter requires users to change their build process anyway if they are building static executables using musl (though I have no clue when we will make that change. I honestly expected it to be done years ago.). And yes, we should deny the combination of -crt-static and link-self-contained. Even on a musl based distro that doesn't do what it says it does as it will still use the system libc.so when linking, while link-self-contained is supposed to avoid using any system libraries. |
It should really be suppressing the host library paths so you get a link failure not a silently broken executable.
This, but also, cross mode should not be invoking the host linker at all. It should always be invoking a tuple-named one; or if using lld, lld in the correct cross mode.
I don't understand what you mean here, and again I'm a bit concerned that Rust is doing something wacky with musl, treating it as a second-class thing that's for making self-contained binaries on glibc hosts rather than a first-class target in itself. While making self-contained binaries like this is a usage we very much want to support, it's not fair to break musl as its own target for this. Link-self-contained should not be a default, but if it's enabled, it should be highest priority. |
Is there a way to do that without also switching to directly invoking the linker? Or do we need to switch to directly invoking the linker in self-contained mode?
Currently |
Not without poking at gcc specfile stuff (passing a custom specfile). This is the whole point of the
So is self-contained mode a thing that's also selected by default for musl targets now? If so, yes that should be changed. I thought it was only something that users explicitly request. So the changes you're proposing sound like a real improvement that will both solve the issue under discussion here, and fix a lot of problems musl-based distros are having to work around with Rust. |
Yes, it is currently selected on musl by default when statically linking, but not when dynamically linking: rust/compiler/rustc_codegen_ssa/src/back/link.rs Lines 1877 to 1880 in 13f3924
Great. FWIW while I'm on the compiler team, I'm speaking in personal capacity here. |
The confusion with target-feature=-crt-static should be fixed soon. It has been planned since 2021. And was discussed for many years before. Musl targets should behave like other targets. |
Hello sorry to re-ask the question. But I have been recently tying to make a lightweight build image and then run the output on a scratch docker. Whilst I can get the code to compile I am having issues finding the binary on the scratch image. When I try and run the binary on an alpine image I seem to be getting issues with alpine looking for Why am I still getting dynamic links even if I am telling the compiler to build statically, what is actually going on under the hood with the static build, are there any resources so I can learn what happens in this instance and how to make sure everything is statically linked? Or is it one of the other libraries causing the problem and requirement for libgcc?
I am sorry if I am asking the same question I am just trying to wrap my head around whats happening, I cannot say I am an expert with cross compilation and it is really baffling me. Is this why people say to avoid building on alpine? |
How are you trying to tell rustc to link statically? Are you using
There is absolutely no point in installing glibc when trying to build for musl. |
I am using the command :
Oh interesting, so what could be causing it to still be a dynamic link? |
Notice how I wrote |
Oh I am such an idiot, thank you! |
tested with rustc stable 1.83.0, on Arch Linux (kernel 6.6.69 LTS)
The same thing happens with
cargo build
andRUSTFLAGS
instead ofcargo rustc
.This happens irrespective of whether a the musl system package is installed or not.
If you set
target.x86_64-unknown-linux-musl.linker = "musl-gcc"
then linking fails with-Ctarget-feature=-crt-static
(complains about missinglibgcc_s
), and without-Ctarget-feature
, the resulting binary crashes instantly (that's a duplicate of #95926), but is dynamically linked to the musl library and loader.I think rustc should error out on musl targets if attempting to disable
crt-static
, since anything else produces wrong or broken binaries. If the idea is that-crt-static
works on targets where musl is the system libc (e.g. Alpine), then perhaps there should be something that detects whether the system libc is musl, and errors (or ignorescrt-static
) if not.The text was updated successfully, but these errors were encountered: