-
-
Notifications
You must be signed in to change notification settings - Fork 14.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
gccWithoutTargetLibc: if glibc, enable threads and pass headers #241208
Conversation
This commit adds `hasSharedLibraries` to `lib.systems`. We need `plat.hasSharedLibraries` in order to know whether or not to expect `gcc` (and many other tools) to emit shared libraries (like `libgcc_s.so`). Many of the GNU build scripts are smart enough that if you configure them with `--enable-shared` on a platform (such as `arm-none-eabi`) that doesn't support dynamic linking, they will simply skip the shared libraries instead of aborting the `configurePhase`. Unfortunately the missing shared libraries in the final build product cause very hard-to-troubleshoot problems later on. The alternative to introducing `hasSharedLibraries` would be to set `isStatic` in these situations. However doing so causes `make-derivation.nix` to insert `-static` between the `pname` and `hostPlatform` suffix, which is undesirable. If at some point in the future we eliminate the `-static` suffix, then `hasSharedLibraries` can be made equal to `!isStatic`.
…rgetLibc This commit allows `gccCrossStageStatic` to build dynamically-linked libraries. Since is no longer restricted to building static libraries its name is no longer appropriate, and this commit also renames it to the more-accurate `gccWithoutTargetLibc`. By default, you can't build a gcc that knows how to create dynamic libraries unless you have already built the targetPlatform libc. Because of this, our gcc cross-compiler is built in two stages: 1. Build a cross-compiler (gccCrossStageStatic) that can build only static libraries. 2. Use gccCrossStageStatic to compile the targetPlatform libc. 3. Use the targetPlatform libc to build a fully-capable cross compiler. You might notice that this pattern looks very similar to what we do with `xgcc` in the stdenv bootstrap. Indeed it is! I would like to work towards getting the existing stdenv bootstrap to handle cross compilers as well. However we don't want to cripple `stdenv.xgcc` by taking away its ability to build dynamic libraries. It turns out that the only thing gcc needs the targetPlatform libc for is to emit a DT_NEEDED for `-lc` into `libgcc.so`. That's it! And since we don't use `gccCrossStageStatic` to build anything other than libc, it's safe to omit the `DT_NEEDED` because that `libgcc` will never be loaded by anything other than `libc`. So `libc` will already be in the process's address space. Other people have noticed this; crosstool-ng has been using this approach for a very long time: https://github.com/crosstool-ng/crosstool-ng/blob/36ad0b17a732aaffe4701d5d8d410d6e3e3abba9/scripts/build/cc/gcc.sh#L638-L640
This commit renames the `crossStageStatic` argument to the `gcc` expression to `withoutTargetLibc`. See previous commit for details.
We want a `libgcc_s.so` to be built by the first stage cross-compiler (withoutTargetLibc), since that is the compiler which will compile the target libc. This commit accomplishes that, by making three changes: 1. Replacing the `targetPlatform.libc == "msvcrt" &&` conditional with `enableShared`, so that the code which cross-build `libgcc_s.so` is used for all cross compilers capable of emitting shared libraries. 2. Removing the `targetPlatform == hostPlatform` guard from the code which produces the `libgcc` output. 3. Looking for build products in in "lib/${targetPlatform.config}/" rather than "lib/", so we will find them when cross compiling.
This commit is reverted in #240596 (which must go to staging).
The situation described in the comment preceding `export inhibit_libc=true` does not match the conditional which follows it. Specifically, the comment says that this line is meant for "clang builds gcc" situations, yet it is enabled even when `!stdenv.cc.isClang`. This commit tightens the conditional to make it match the situation described in the comment.
This expression allows to build the glibc headers without first having built a targetPlatform compiler. It is needed in order to break the dependency cycle between glibc and libgcc: 1. glibc must have the exact path to libgcc embedded into it via user-defined-trusted-dirs; see nixpkgs commit 7553d0f. This reference is not part of the ELF structure so we can't use `patchelf` to update it. 2. libgcc must be able to see the glibc headers in order to compile unwinder support. Otherwise, it will deliberately `assert()` when a thread which has called `pthread_cleanup_push()` exits: https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgcc/unwind-dw2.c;h=d0afce7a9ea9f5b12a5a01ef1e940e1452b48cab;hb=HEAD#l1336 Unfortunately due to how GNU autoconf works, you can't *usually* get the glibc headers without a targetPlatform compiler, because the headers are partially generated based on autoconf results, and autoconf is based on running the targetPlatform C compiler on various inputs and seeing if they fail. Fortunately the glibc developers are at least partially aware of this being problematic, which is why they have avoided using any targetPlatform-compiler-derived data when producing the targetPlatform headers, and have provided the `--enable-hacker-mode` flag for `./configure`, which runs just enough of the process to allow `make install-headers` to work (but `make` certainly *won't*).
If ${targetPackages.glibc}/include/stdio.h does not exist during the configurePhase of pkgsCross.*.gcc.libgcc, the stack unwinder will be silently disabled. The resulting libgcc_s.so will deliberately crash any process which attempts to use `pthread_cleanup_push()` or similar calls. Closes #213453
Update: so, this does fix #213453, and it does work on Apparently being able to After much digging around in the guts of There are two ways to do this:
So to summarize:
|
Description of changes
If
${targetPackages.glibc}/include/stdio.h
does not exist during theconfigurePhase
ofpkgsCross.*.gcc.libgcc
, the stack unwinder will be silently disabled.The resulting libgcc_s.so will deliberately crash any process which attempts to use
pthread_cleanup_push()
or similar calls.This PR ensures that
${targetPackages.glibc}/include/stdio.h
does exist during theconfigurePhase
ofpkgsCross.*.gcc.libgcc
, so we get an unwinder-capablelibgcc_s.so
.This also adds a new package
glibcHeaders
, which allows to build the glibc headers without first having built a targetPlatform compiler. This is needed in order to break the dependency cycle between glibc and libgcc. Additional details are in the commit message for that particular commitCloses:
mbuffer
: cross-compiled libgcc_s.so.1 must be built with glibc headers for pthread_cleanup_push() to work #213453Includes
Things done
sandbox = true
set innix.conf
? (See Nix manual)nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD"
. Note: all changes have to be committed, also see nixpkgs-review usage./result/bin/
)