-
-
Notifications
You must be signed in to change notification settings - Fork 59
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
cargo zigbuild
doesn't support static glibc builds with an explicit --target
#231
Comments
Not really, if you don't pass |
#include <stdio.h>
int main(void) {
printf("hello");
return 0;
} build with $ python3 -m ziglang cc -static -o t t.c
$ ldd t
linux-vdso.so.1 (0x00007ffc22dfb000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f72e7e00000)
/lib64/ld-linux-x86-64.so.2 (0x00007f72e8186000) Seems that |
Building the static binary with glibc is not recommended actually, because glibc is not designed this way. See this reference https://stackoverflow.com/questions/57476533/why-is-statically-linking-glibc-discouraged If static binaries are wanted, the goto approach is |
Probably worth mentioning that (README section doesn't clarify that gotcha), it also seems to be the case if I use I noticed that I could specify an invalid glibc version in the target too and that still builds successfully, but a little more surprising was that building with dynamic link to version # In Fedora 33 (glibc 2.32):
$ cargo build --release --target x86_64-unknown-linux-gnu
# In Fedora 32 (glibc 2.31):
$ ./example
./example: /lib64/libc.so.6: version `GLIBC_2.32' not found (required by ./example)
# Build on Fedora 33 (with cargo-zigbuild):
$ cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.32
# Run on Fedora 32:
$ ./example
Hello, world!
# Build on Fedora 33:
$ cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.33
# Run on Fedora 32:
$ ./example
./example: /lib64/libc.so.6: version `GLIBC_2.33' not found (required by ./example)
# Fedora 32:
$ ldd --version
ldd (GNU libc) 2.31
$ dnf info glibc
Installed Packages
Name : glibc
Version : 2.31
UPDATE: On Fedora 33, I was able to build without the linking error by including
# Fedora 33 (creates a dynamically linked binary despite static request):
$ RUSTFLAGS="-C target-feature=+crt-static -L /usr/lib/gcc/x86_64-redhat-linux/10" cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.31
$ ldd target/x86_64-unknown-linux-gnu/release/example
linux-vdso.so.1 (0x00007ffe6af58000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fcd227cf000)
libc.so.6 => /lib64/libc.so.6 (0x00007fcd22604000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcd227fa000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007fcd225ff000) Without # Fedora 33:
RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target x86_64-unknown-linux-gnu
Compiling libc v0.2.153
Compiling example v0.1.0 (/tmp/example)
Finished release [optimized] target(s) in 0.44s
# Fedora 32 (this is with the code for triggering a specific failure when linking glibc 2.32 statically and trying to run on glibc 2.31):
$ ./example
./example: dl-call-libc-early-init.c:37: _dl_call_libc_early_init: Assertion `sym != NULL' failed.
# If it were dynamically linked, it'd fail with this error instead due to the incompatible glibc version:
./example: /lib64/libc.so.6: version `GLIBC_2.32' not found (required by ./example)
# Fedora 40 (glibc 2.39) that same binary segfaults, but would otherwise work fine if dynamically linked:
$ ./example
Segmentation fault
# Fedora 33 binary appears static?:
$ ldd target/x86_64-unknown-linux-gnu/release/example
not a dynamic executable
$ file target/x86_64-unknown-linux-gnu/release/example
target/x86_64-unknown-linux-gnu/release/example: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=d8908ed9620212e108235a3d8b7b7264cdac6af3, for GNU/Linux 3.2.0, with debug_info, not stripped, too many notes (256)
# `dl_open` usage from glibc makes it secretly dynamic still:
$ nm -an target/x86_64-unknown-linux-gnu/release/example | grep dl_open
000000000049b6e0 t .annobin_dl_open.c
000000000049baa2 t .annobin__dl_open.start
000000000049bab0 T _dl_open
000000000049bd04 t .annobin__dl_open.end
000000000049be42 t .annobin_dl_open_worker.start
000000000049be50 t dl_open_worker
000000000049c80c t .annobin_dl_open.c_end
000000000049c80c t .annobin_dl_open_worker.end
00000000004a12ef t .annobin___libc_register_dl_open_hook.start
00000000004a12f0 T __libc_register_dl_open_hook
00000000004a1333 t .annobin___libc_register_dl_open_hook.end
0000000000543740 d _dl_open_hook
I've commented there trying to build static hello world by the advice to provide the extra It now claims to be statically linked via
I am aware of this, I wanted to reproduce some of the issues related to it for documenting this concern (in particular, this one). As shown above I can't reproduce when using Zig to specify the glibc (even when using dynamic linking, the behaviour is unexpected?) For some programs like a basic hello world it should be fine to static link with glibc AFAIK, while the NSS caveat kind of applies to a static build with musl too?
Yeah I use that, but that has some gotchas too:
|
I really appreciate the detailed write-up. FYI, static linking glibc has never been the goal of this project so it has never been tested. But I'm open to merge PRs that enable this if you really want it and willing to invest time to coding and testing. |
I don't know how to successfully use As you helped point out, that seems to be an upstream issue with Zig's static linking support, which is possibly complicated further when static linking libc since it's doing it's own thing for the glibc version feature support it has? Until there is answers there on how to statically compile For now, I think it's better to just point out that EDIT: PR ready, hope that covers it well 👍 |
One thing that I am wondering is why you insist on running a binary built with glibc 2.32 on a system with glibc 2.31 with static linking. Static linking is not a panacea, it does not solve compatibility issues. If you prefer glibc, the very traditional approach is building your app against a low version of glibc (rust can support as low as 2.17) with dynamically linking, and everything should be fine. Another approach is redistributing your own glibc of whatever new version you like with your app, which should work also but needs more effort. |
Not that hard with zigbuild? [root@9ea04f2aa461 hello-tls]# cargo zigbuild --release --target x86_64-unknown-linux-musl
Compiling openssl-sys v0.9.96
Compiling tokio v1.27.0
Compiling futures-core v0.3.28
Compiling mio v0.8.11
Compiling tokio-macros v2.0.0
Compiling socket2 v0.4.9
Compiling num_cpus v1.15.0
Compiling itoa v1.0.6
Compiling futures-task v0.3.28
....
Compiling hello-tls v0.1.0 (/root/cargo-zigbuild/tests/hello-tls)
Finished release [optimized] target(s) in 6m 23s
[root@9ea04f2aa461 hello-tls]# file target/x86_64-unknown-linux-musl/release/hello-tls
target/x86_64-unknown-linux-musl/release/hello-tls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped
[root@9ea04f2aa461 hello-tls]# ./target/x86_64-unknown-linux-musl/release/hello-tls
Response status 200 OK |
I did not expect it to work, I wanted an example of static linking with a On glibc 2.31 or earlier you'd get that error I showed AFAIK:
While on newer glibc it appears to segfault (which it won't if dynamically linked of course), which is why it's specific to glibc 2.32 unlike others which AFAIK may still be forward compatible with glibc when static linking (there is a subset that is IIRC and it improves with newer releases). In fact I think from 2.33, this method was changed to be compatible with static build so it shouldn't segfault when static linking to 2.33+ 👍 This also helps highlight the difference vs dynamic linking glibc where you'd otherwise expect a different error emitted when not compatible:
However, I want to draw attention to Zig dynamic linking not emitting that error and working on glibc 2.31 instead. Yet if I target 2.33 instead of 2.32 it would emit the equivalent error as shown in the quote as you'd expect. So why didn't that happen for 2.32? 🤷♂️ So to reiterate, I wanted an example of static linking glibc where breakage occurs. You don't get that with hello world, you need to call something that'd trigger the
It's about a portable build. Some users will build with a For those that wonder about it and may reason that it seems fine for them instead of using a I've seen this misunderstanding quite a few times and even personally been curious about how to reproduce a static glibc incompatibility for some time and I only recently got around to investigating how to.
Yes I'm aware of this advice 👍 I was interested in the static build context, since dynamic linking glibc would not be as portable as the musl static build. Musl has it's own gotchas to accommodate, I just needed to properly reproduce the big gotcha for glibc static. Prior to Rust 1.72 there was a notable issue where static builds still accidentally dynamically linked even with musl, but those now surface at build time thankfully, whereas the glibc concern is more subtle and I imagine would still surprise some users not as familiar as yourself as to why it breaks :)
Sure, but the focus here was on a single distributable binary. For myself that's via GH releases and Docker. I am not too experienced with dynamic linking libs that way, does relative paths work? Perhaps other gotchas? (I know with |
|
Glad you have figured out the openssl/vendored issue. I forgot to mention Therefore zigbuild is really a cross compiling tool, it does not help a lot when targeting the same host, especially when you want to explore static linking with glibc. Most linker errors you showed above are because Finally,
Why? zigbuild should work for |
That's a great benefit, thanks!
I was referring to without That along with the easy builds for different arch is great! ❤️
https://github.com/ziglang/glibc-abi-tool#strategy
I detailed a reproduction case with my glibc 2.32 concern with more information here: #232 (comment) Disregarding static build:
So what happens in that scenario?
Additional tip for dynamic glibc builds, how to check the minimum version linked: # Parse the binary file for GLIBC symbols with specific format, then extract the semver via sed,
# followed by sorting major.minor fields numerically correctly, finally select the last result with tail:
$ readelf -W --version-info --dyn-syms target/x86_64-unknown-linux-gnu/release/bin-name-here | grep 'Name: GLIBC' | sed -re 's/.*GLIBC_(.+) Flags.*/\1/g' | sort -t . -k1,1n -k2,2n | tail -n 1
2.32 |
cargo zigbuild
doesn't support static builds with an explicit --target
cargo zigbuild
doesn't support static glibc builds with an explicit --target
Update: Zig recently resolved ziglang/zig#17268 (comment) which should avoid one of the linking errors. Zig still lacks support for glibc static builds that don't segfault but that may be resolved in future too. If they also resolve support for |
cargo zigbuild
is not compatible withRUSTFLAGS="-C target-feature=+crt-static"
, aka static builds. (EDIT: At least when an explicit--target
is configured)Reproduction
Now with
cargo zigbuild
:It seems that
cargo-zigbuild
(or zig itself?) cannot support statically linked builds?If you use the official Rust image (Debian via
rust:latest
), you can perform the static build without installing any extra package likeglibc-static
, but you'll still get the same error when trying withcargo zigbuild
.Insights
There is a related Github Discussion about this problem from Sep 2023, but no solution.
cargo init
.Given those last findings that it works without
--target
or without the static flag, it seems this is not an upstream zig issue, but related to Cargo?--target
is required usually for a static build if any proc macro is involved, otherwise you'll get build errors.--target
will avoid using static on the build scripts IIRC, while still using it for your build target during compilation.gcc_eh
AFAIK is related to panic support, while Clang offerslibunwind
as an alternative, from what I've read you can only have a single implementation and that gets complicated if you have deps that are C/C++ related.libunwind
.no_std
withpanic = "abort"
I think is an example), butrustc
hard-codes this link requirement anyway? 🤷♂️ (similarly for thelibgcc.a
requirement)My interest was in reproducing this example, which depends on
glibc 2.32
specifically.glibc 2.32
withoutcargo-zigbuild
via Fedora 33 and using it'sglibc-static
package which matches that version.cargo zigbuild
but was surprised that it didn't work, and that there is barely any discussion about the failure 😅The text was updated successfully, but these errors were encountered: