mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-02-11 22:54:17 +00:00
![Sergei Trofimovich](/assets/img/avatar_default.png)
The primary reason for the layout change is for `gcc.libgcc` to match closer `gcc.lib` layout. That way we allow `$STRIP_FOR_TARGET` to strip `libgcc_s.so.1` file moved to $libgcc output. Otherwise `$STRIP` (for host) fails to do it and leaves debug strings like references to headers in it and bloats HOST closure with BUILD inputs. The change shrinks `aarch64-multiplatform-musl.coreutils` closure from 50MB down to 10MB: Before: $ nix path-info -rsSh $(nix-build -A pkgs.pkgsCross.aarch64-multiplatform-musl.coreutils) |& unnix /<<NIX>>/xgcc-13.2.0-libgcc 155.8K 155.8K /<<NIX>>/musl-aarch64-unknown-linux-musl-1.2.3 3.8M 3.8M /<<NIX>>/libunistring-1.1 1.7M 1.7M /<<NIX>>/libidn2-2.3.7 352.7K 2.1M /<<NIX>>/glibc-2.39-52 28.7M 31.0M /<<NIX>>/bash-5.2p26 1.5M 32.5M /<<NIX>>/musl-aarch64-unknown-linux-musl-1.2.3-bin 69.4K 3.8M /<<NIX>>/linux-headers-6.7 6.2M 6.2M /<<NIX>>/musl-aarch64-unknown-linux-musl-1.2.3-dev 550.2K 43.1M /<<NIX>>/aarch64-unknown-linux-musl-gcc-13.2.0-libgcc 579.7K 43.6M /<<NIX>>/aarch64-unknown-linux-musl-gcc-13.2.0-lib 3.8M 47.4M /<<NIX>>/gmp-with-cxx-aarch64-unknown-linux-musl-6.3.0 653.4K 48.1M /<<NIX>>/attr-aarch64-unknown-linux-musl-2.5.2 73.8K 3.8M /<<NIX>>/acl-aarch64-unknown-linux-musl-2.3.2 156.4K 4.0M /<<NIX>>/coreutils-aarch64-unknown-linux-musl-9.5 1.6M 49.9M After: $ nix path-info -rsSh $(nix-build -A pkgs.pkgsCross.aarch64-multiplatform-musl.coreutils) |& unnix /<<NIX>>/musl-aarch64-unknown-linux-musl-1.2.3 3.8M 3.8M /<<NIX>>/aarch64-unknown-linux-musl-gcc-13.2.0-libgcc 147.9K 147.9K /<<NIX>>/aarch64-unknown-linux-musl-gcc-13.2.0-lib 3.8M 7.7M /<<NIX>>/gmp-with-cxx-aarch64-unknown-linux-musl-6.3.0 653.4K 8.4M /<<NIX>>/attr-aarch64-unknown-linux-musl-2.5.2 73.8K 3.8M /<<NIX>>/acl-aarch64-unknown-linux-musl-2.3.2 156.4K 4.0M /<<NIX>>/coreutils-aarch64-unknown-linux-musl-9.5 1.6M 10.1M
160 lines
6.3 KiB
Nix
160 lines
6.3 KiB
Nix
{ lib
|
|
, stdenv
|
|
, version
|
|
, langC
|
|
, langCC
|
|
, langJit
|
|
, enableShared
|
|
, targetPlatform
|
|
, hostPlatform
|
|
, withoutTargetLibc
|
|
, libcCross
|
|
}:
|
|
|
|
assert !stdenv.targetPlatform.hasSharedLibraries -> !enableShared;
|
|
|
|
drv: lib.pipe drv
|
|
|
|
([
|
|
|
|
(pkg: pkg.overrideAttrs (previousAttrs:
|
|
lib.optionalAttrs (
|
|
targetPlatform != hostPlatform &&
|
|
(enableShared || targetPlatform.isMinGW) &&
|
|
withoutTargetLibc
|
|
) {
|
|
makeFlags = [ "all-gcc" "all-target-libgcc" ];
|
|
installTargets = "install-gcc install-target-libgcc";
|
|
}))
|
|
|
|
] ++
|
|
|
|
# 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.optionals (lib.versionAtLeast version "11.0")
|
|
|
|
(let
|
|
targetPlatformSlash =
|
|
if hostPlatform == targetPlatform
|
|
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 &&
|
|
!useLibgccFromTargetLibc
|
|
;
|
|
|
|
# For some reason libgcc_s.so has major-version "2" on m68k but
|
|
# "1" everywhere else. Might be worth changing this to "*".
|
|
libgcc_s-version-major =
|
|
if targetPlatform.isM68k
|
|
then "2"
|
|
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
|
|
# in bash instead of nix (we should fix that).
|
|
preFixupPhases = (previousAttrs.preFixupPhases or []) ++ lib.optionals ((!langC) || enableLibGccOutput) [ "preFixupLibGccPhase" ];
|
|
preFixupLibGccPhase =
|
|
# delete extra/unused builds of libgcc_s in non-langC builds
|
|
# (i.e. libgccjit, gnat, etc) to avoid potential confusion
|
|
lib.optionalString (!langC) ''
|
|
rm -f $out/lib/libgcc_s.so*
|
|
''
|
|
|
|
# move `libgcc_s.so` into its own output, `$libgcc`
|
|
# We maintain $libgcc/lib/$target/ structure to make sure target
|
|
# strip runs over libgcc_s.so and remove debug references to headers:
|
|
# https://github.com/NixOS/nixpkgs/issues/316114
|
|
+ lib.optionalString enableLibGccOutput (''
|
|
# move libgcc from lib to its own output (libgcc)
|
|
mkdir -p $libgcc/${targetPlatformSlash}lib
|
|
mv $lib/${targetPlatformSlash}lib/libgcc_s.so $libgcc/${targetPlatformSlash}lib/
|
|
mv $lib/${targetPlatformSlash}lib/libgcc_s.so.${libgcc_s-version-major} $libgcc/${targetPlatformSlash}lib/
|
|
ln -s $libgcc/${targetPlatformSlash}lib/libgcc_s.so $lib/${targetPlatformSlash}lib/
|
|
ln -s $libgcc/${targetPlatformSlash}lib/libgcc_s.so.${libgcc_s-version-major} $lib/${targetPlatformSlash}lib/
|
|
''
|
|
+ lib.optionalString (targetPlatformSlash != "") ''
|
|
ln -s ${targetPlatformSlash}lib $libgcc/lib
|
|
''
|
|
#
|
|
# Nixpkgs ordinarily turns dynamic linking into pseudo-static linking:
|
|
# libraries are still loaded dynamically, exactly which copy of each
|
|
# library is loaded is permanently fixed at compile time (via RUNPATH).
|
|
# For libgcc_s we must revert to the "impure dynamic linking" style found
|
|
# in imperative software distributions. We must do this because
|
|
# `libgcc_s` calls `malloc()` and therefore has a `DT_NEEDED` for `libc`,
|
|
# which creates two problems:
|
|
#
|
|
# 1. A circular package dependency `glibc`<-`libgcc`<-`glibc`
|
|
#
|
|
# 2. According to the `-Wl,-rpath` flags added by Nixpkgs' `ld-wrapper`,
|
|
# the two versions of `glibc` in the cycle above are actually
|
|
# different packages. The later one is compiled by this `gcc`, but
|
|
# the earlier one was compiled by the compiler *that compiled* this
|
|
# `gcc` (usually the bootstrapFiles). In any event, the `glibc`
|
|
# dynamic loader won't honor that specificity without namespaced
|
|
# manual loads (`dlmopen()`). Once a `libc` is present in the address
|
|
# space of a process, that `libc` will be used to satisfy all
|
|
# `DT_NEEDED`s for `libc`, regardless of `RUNPATH`s.
|
|
#
|
|
# So we wipe the RUNPATH using `patchelf --set-rpath ""`. We can't use
|
|
# `patchelf --remove-rpath`, because at least as of patchelf 0.15.0 it
|
|
# will leave the old RUNPATH string in the file where the reference
|
|
# scanner can still find it:
|
|
#
|
|
# https://github.com/NixOS/patchelf/issues/453
|
|
#
|
|
# Note: we might be using the bootstrapFiles' copy of patchelf, so we have
|
|
# to keep doing it this way until both the issue is fixed *and* all the
|
|
# bootstrapFiles are regenerated, on every platform.
|
|
#
|
|
# This patchelfing is *not* effectively equivalent to copying
|
|
# `libgcc_s` into `glibc`'s outpath. There is one minor and one
|
|
# major difference:
|
|
#
|
|
# 1. (Minor): multiple builds of `glibc` (say, with different
|
|
# overrides or parameters) will all reference a single store
|
|
# path:
|
|
#
|
|
# /nix/store/xxx...xxx-gcc-libgcc/lib/libgcc_s.so.1
|
|
#
|
|
# This many-to-one referrer relationship will be visible in the store's
|
|
# dependency graph, and will be available to `nix-store -q` queries.
|
|
# Copying `libgcc_s` into each of its referrers would lose that
|
|
# information.
|
|
#
|
|
# 2. (Major): by referencing `libgcc_s.so.1`, rather than copying it, we
|
|
# are still able to run `nix-store -qd` on it to find out how it got
|
|
# built! Most importantly, we can see from that deriver which compiler
|
|
# was used to build it (or if it is part of the unpacked
|
|
# bootstrap-files). Copying `libgcc_s.so.1` from one outpath to
|
|
# another eliminates the ability to make these queries.
|
|
#
|
|
+ ''
|
|
patchelf --set-rpath "" $libgcc/lib/libgcc_s.so.${libgcc_s-version-major}
|
|
'');
|
|
}))]))
|