-
-
Notifications
You must be signed in to change notification settings - Fork 15.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
glibcCross: use a libgcc built separately from gcc #247900
Conversation
@ofborg build tests.cross.mbuffer |
🎉 |
@ofborg eval |
Figured out how to do this without a rebuild of native |
Building
Bisect results:
|
Thanks for catching this, @Majiir.
|
I've squashed these two commits into the commit after them. I originally separated them in order to try to change only one package per commit, but unfortunately that creates non-evaluable commits in the history which -- as you noticed -- is a pain when |
This commit restores the pkgs/development/libraries/gcc/libgcc package, which was deleted by commit 9818d12. We need to be able to build libgcc separately from gcc in order to avoid a circular dependency. Nixpkgs is unusual -- unlike any other distribution, it cannot tolerate circular dependencies between dynamically linked libraries. Because of this, upstream is extremely unsympathetic to the trouble that the glibc<->gcc circular dependency causes for us; if we don't solve it ourselves it will not be solved.
This is necessary in order to prevent gcc from switching on `inhibit_libc`, which cripples the `libgcc_s.so` unwinder.
This duplicates (by reference) the two-line adjustment to libgcc's Makefile needed in order to get crtstuff to build without a full build of gcc.
A lot of these flags were unnecessary.
This commit minimizes libgcc's gccConfigureFlags, and -- importantly -- includes the three flags needed in order to prevent `inhibit_libc` from becoming active.
### Summary This PR completely and finally solves the gcc<->glibc circular `buildInputs` problem, for cross compilation. The same technique can be applied to native builds in the future. Closes #213453 ### Motivation Prior to this PR, we had the following circular `buildInputs` problem: 1. gcc has glibc in its `buildInputs` - a compiled copy of glibc must be present before building gcc; if it isn't, gcc cripples itself (`inhibit_libc`) and refuses to build libgcc_s.so 2. glibc has libgcc_s.so in its `buildInputs` - glibc `dlopen()`s libgcc_s.so in order to implement POSIX thread cancellation. For security reasons `glibc` requires that the path to `libgcc_s.so` is [hardwired] into `glibc` at compile time, so it's technically not a true dynamic link -- it just pretends to be one. 3. libgcc_s.so is built in the same derivation as gcc - libgcc_s.so is built as part of the gcc build process We must cut one of these three links in the loop. ### Previous Attempts Previously #238154 had attempted to cut link (1) by building `gcc` without `glibc`, and using the `libgcc_s` which emerges from that build. Unfortunately this just doesn't work. GCC's configure script extracts quite a lot of information from the glibc headers (which are a build artifact -- you can't just copy them out of the source tarball) and various `./configure`-driven linking attempts. If `glibc` isn't around at build time you wind up with a `libgcc_s.so` that is missing various unwinder features (see #213453 for the most problematic one). Musl "cuts" link (2), or rather never creates it in the first place. ["Cancellation cleanup handling in musl has no relationship to C++ exceptions and unwinding... glibc implements cancellation as an exception"](https://wiki.musl-libc.org/functional-differences-from-glibc.html#Thread-cancellation). IMHO Musl made the smarter decision here. It is incredibly rare to find a codebase that uses both POSIX thread cancellation *and* C++ exceptions. I have never seen a codebase that uses both *and* expects them to be aware of each other, and I would be astonished if one existed. Glibc paid an immense cost in complexity for something nobody has ever used. ### Changes Made This PR cuts link (3): instead of building libgcc_s.so as part of gcc, we build it separately from gcc. Now there is a strict acyclic graph of `buildInputs`: ``` gccWithoutTargetLibc | +--->glibc-nolibgcc | | | v +--->libgcc | | | v +--->glibc | | | v +--->gcc ``` In other words, there's a simple linear `buildInputs` chain `glibc-nolibgcc` `->` `libgcc` `->` `glibc` `->` `gcc` where all four packages are compiled by (and therefore have as a `(native)BuildInput`) `gccWithoutTargetLibc`. `gccWithoutTargetLibc` and `glibc-nolibgcc` are strictly bootstrapping artifacts; nothing else has them as a `buildInput` and they shouldn't appear in the closure of any final deployment packages. `glibc-nolibgcc` lacks `libgcc_s.so`, so it will segfault if you try to use it with POSIX thread cancellation. Fortunately all we need from it is (a) its headers (`lib.getDev`) and (b) to use it in the `./configure` script for `libgcc`. When translated over to the native bootstrap, `xgcc` takes the place of `gccWithoutTargetLibc`, and the "first `glibc`" (we build two of them) takes the place of `glibc-nolibgcc`. At that point our native and cross bootstrap have the same overall architecture, and it becomes possible to merge them (at last!) [213453]: #213453 [238154]: #238154 [hardwired]: https://github.com/NixOS/nixpkgs/blob/7553d0fe29801938bcb280bb324b579ef9016aea/pkgs/development/libraries/glibc/default.nix#L69-L88
This test passes now. Also fixes a minor oversight in the bug -- the test case needs to `touch $out` on success.
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.
Build successful, and it fixes the mbuffer
issue. 🎉 I tested it on my armv7l hardware (cross-compiled from x86_64) to be sure.
I'm also trying to cross-compile my whole armv7l system on this branch, but currently running into build failures on latest master (unrelated to this PR). I'll update if I get a successful build or run into any problems.
I spent some time reading through your commits. I'm not qualified to give these changes a critical review, but it generally looks good to me.
Thank you for your efforts on this and for looking after the core bits of nixpkgs!
Let me know how it goes! If you run into any problems that manifest for cross but not for native let me know; there's a good chance I've seen them before. I mostly hang out in |
I get the |
Summary
This PR completely and finally solves the gcc<->glibc circular
buildInputs
problem, for cross compilation. The same technique can be applied to native builds in the future.Closes #213453
Motivation
Prior to this PR, we had the following circular
buildInputs
problem:gcc has glibc in its
buildInputs
inhibit_libc
) and refuses to build libgcc_s.soglibc has libgcc_s.so in its
buildInputs
dlopen()
s libgcc_s.so in order to implement POSIX thread cancellation. For security reasonsglibc
requires that the path tolibgcc_s.so
is hardwired intoglibc
at compile time, so it's technically not a true dynamic link -- it just pretends to be one.libgcc_s.so is built in the same derivation as gcc
We must cut one of these three links in the loop.
Previous Attempts
Previously #238154 had attempted to cut link (1) by building
gcc
withoutglibc
, and using thelibgcc_s
which emerges from that build. Unfortunately this just doesn't work. GCC's configure script extracts quite a lot of information from the glibc headers (which are a build artifact -- you can't just copy them out of the source tarball) and various./configure
-driven linking attempts. Ifglibc
isn't around at build time you wind up with alibgcc_s.so
that is missing various unwinder features (see #213453 for the most problematic one).Musl "cuts" link (2), or rather never creates it in the first place. "Cancellation cleanup handling in musl has no relationship to C++ exceptions and unwinding... glibc implements cancellation as an exception". IMHO Musl made the smarter decision here. It is incredibly rare to find a codebase that uses both POSIX thread cancellation and C++ exceptions. I have never seen a codebase that uses both and expects them to be aware of each other, and I would be astonished if one existed. Glibc paid an immense cost in complexity for something nobody has ever used.
Changes Made
This PR cuts link (3): instead of building libgcc_s.so as part of gcc, we build it separately from gcc. Now there is a strict acyclic graph of
buildInputs
:In other words, there's a simple linear
buildInputs
chainglibc-nolibgcc
->
libgcc
->
glibc
->
gcc
where all four packages are compiled by (and therefore have as a(native)BuildInput
)gccWithoutTargetLibc
.gccWithoutTargetLibc
andglibc-nolibgcc
are strictly bootstrapping artifacts; nothing else has them as abuildInput
and they shouldn't appear in the closure of any final deployment packages.glibc-nolibgcc
lackslibgcc_s.so
, so it will segfault if you try to use it with POSIX thread cancellation. Fortunately all we need from it is (a) its headers (lib.getDev
) and (b) to use it in the./configure
script forlibgcc
.When translated over to the native bootstrap,
xgcc
takes the place ofgccWithoutTargetLibc
, and the "firstglibc
" (we build two of them) takes the place ofglibc-nolibgcc
. At that point our native and cross bootstrap have the same overall architecture, and it becomes possible to merge them (at last!)