gcc: for cross compilers, don't build libgcc twice

Cross-compiled binaries currently end up with two different libgcc
outpaths in their closure.  This is harmless, but confusing.

The two libgccs are:

- One of them is the "first" targetPlatform libgcc, which is built
  by the "first" cross-compiler.  This "first libgcc" and "first
  compiler" are used to build the targetPlatform glibc.

- Once glibc is built, we *rebuild* the cross-compiler, since gcc
  can't enable most of its features unless you give it an
  already-compiled targetPlatform glibc.  When this "second"
  compiler is built, it also builds an extra copy of libgcc.

This commit discards the second, extra libgcc, and instead puts a
reference to the first (correct) libgcc into the "second compiler"
`.passthru.libgcc`, so that anybody expecting `stdenv.cc.cc.libgcc`
to exist will still find it there.

Closes #249680
This commit is contained in:
Adam Joseph 2023-08-16 22:27:32 -07:00 committed by Artturin
parent e6aa338820
commit aafab3b5b6
2 changed files with 22 additions and 5 deletions

View file

@ -8,6 +8,7 @@
, targetPlatform
, hostPlatform
, withoutTargetLibc
, libcCross
}:
assert !stdenv.targetPlatform.hasSharedLibraries -> !enableShared;
@ -31,7 +32,7 @@ drv: lib.pipe drv
# nixpkgs did not add the "libgcc" output until gcc11. In theory
# the following condition can be changed to `true`, but that has not
# been tested.
lib.optional (lib.versionAtLeast version "11.0")
lib.optionals (lib.versionAtLeast version "11.0")
(let
targetPlatformSlash =
@ -39,11 +40,20 @@ lib.optional (lib.versionAtLeast version "11.0")
then ""
else "${targetPlatform.config}/";
# If we are building a cross-compiler and the target libc provided
# to us at build time has a libgcc, use that instead of building a
# new one. This avoids having two separate (but identical) libgcc
# outpaths in the closure of most packages, which can be confusing.
useLibgccFromTargetLibc =
libcCross != null &&
libcCross?passthru.libgcc;
enableLibGccOutput =
(!stdenv.targetPlatform.isWindows || (with stdenv; targetPlatform == hostPlatform)) &&
!langJit &&
!stdenv.hostPlatform.isDarwin &&
enableShared
enableShared &&
!useLibgccFromTargetLibc
;
# For some reason libgcc_s.so has major-version "2" on m68k but
@ -54,6 +64,14 @@ lib.optional (lib.versionAtLeast version "11.0")
else "1";
in
[
(pkg: pkg.overrideAttrs (previousAttrs: lib.optionalAttrs useLibgccFromTargetLibc {
passthru = (previousAttrs.passthru or {}) // {
inherit (libcCross) libgcc;
};
}))
(pkg: pkg.overrideAttrs (previousAttrs: lib.optionalAttrs ((!langC) || langJit || enableLibGccOutput) {
outputs = previousAttrs.outputs ++ lib.optionals enableLibGccOutput [ "libgcc" ];
# This is a separate phase because gcc assembles its phase scripts
@ -143,5 +161,4 @@ in
+ ''
patchelf --set-rpath "" $libgcc/lib/libgcc_s.so.${libgcc_s-version-major}
'');
}))))
}))]))

View file

@ -450,7 +450,7 @@ ${""} done
}
))
([
(callPackage ./common/libgcc.nix { inherit version langC langCC langJit targetPlatform hostPlatform withoutTargetLibc enableShared; })
(callPackage ./common/libgcc.nix { inherit version langC langCC langJit targetPlatform hostPlatform withoutTargetLibc enableShared libcCross; })
] ++ optionals atLeast11 [
(callPackage ./common/checksum.nix { inherit langC langCC; })
])