gcc: 2 symlink 2 hack (#380325)

OK, let's try this again.
This commit is contained in:
K900
2025-02-19 14:05:03 +03:00
committed by GitHub
2 changed files with 84 additions and 53 deletions

View File

@@ -3,13 +3,16 @@
stdenv,
enableMultilib,
targetConfig,
withoutTargetLibc,
}:
let
forceLibgccToBuildCrtStuff = import ./libgcc-buildstuff.nix { inherit lib stdenv; };
isCross = with stdenv; targetPlatform.config != hostPlatform.config;
in
# We don't support multilib and cross at the same time
assert !(enableMultilib && isCross);
originalAttrs:
(stdenv.mkDerivation (
finalAttrs:
@@ -210,64 +213,94 @@ originalAttrs:
'';
preInstall =
# What follows is a horribly cursed hack.
#
# GCC will install its libraries to $out/lib, $out/lib32, $out/lib64,
# $out/$targetConfig/lib, $out/$targetConfig/lib32 or $out/$targetConfig/lib64,
# depending on whether it's built as native or cross, and the exact target spec.
#
# We can't predict what it's actually going to do, and we also can't just tell it
# to always install to lib, but we want everything to end up in lib
# for consistency (multilib weirdness aside).
#
# So, we create a bunch of symlinks before we run GCC's install phase,
# redirecting every possible directory it may want to write to to the place
# we actually want things to be installed.
# We will then nuke the symlinks in postInstall.
#
# FIXME: there must be a better way to do this.
''
mkdir -p "$out/''${targetConfig}/lib"
mkdir -p "''${!outputLib}/''${targetConfig}/lib"
declare -ga compatibilitySymlinks=()
makeCompatibilitySymlink() {
declare -a outputsToLink=("$out")
if [ -n "$lib" ]; then
outputsToLink+=("$lib")
fi
for output in "''${outputsToLink[@]}"; do
local linkTarget="$1"
local linkName="$output/$2"
echo "Creating compatibility symlink: $linkTarget -> $linkName"
mkdir -p "$(dirname "$linkName")"
ln -s "$linkTarget" "$linkName"
compatibilitySymlinks+=("$linkName")
done
}
''
+
# if cross-compiling, link from $lib/lib to $lib/${targetConfig}.
# since native-compiles have $lib/lib as a directory (not a
# symlink), this ensures that in every case we can assume that
# $lib/lib contains the .so files
lib.optionalString (with stdenv; targetPlatform.config != hostPlatform.config) ''
ln -Ts "''${!outputLib}/''${targetConfig}/lib" $lib/lib
# This will redirect $output/lib{32,64} to $output/lib.
# Multilib is special, because it creates $out/lib (for 32-bit)
# and $out/lib64 (for 64-bit). No other targets can have both.
lib.optionalString (!enableMultilib) ''
makeCompatibilitySymlink lib lib32
makeCompatibilitySymlink lib lib64
''
+
# Make `lib64` symlinks to `lib`.
lib.optionalString
(!enableMultilib && stdenv.hostPlatform.is64bit && !stdenv.hostPlatform.isMips64n32)
''
ln -s lib "$out/''${targetConfig}/lib64"
ln -s lib "''${!outputLib}/''${targetConfig}/lib64"
''
+
# On mips platforms, gcc follows the IRIX naming convention:
#
# $PREFIX/lib = mips32
# $PREFIX/lib32 = mips64n32
# $PREFIX/lib64 = mips64
#
# Make `lib32` symlinks to `lib`.
lib.optionalString (!enableMultilib && stdenv.targetPlatform.isMips64n32) ''
ln -s lib "$out/''${targetConfig}/lib32"
ln -s lib "''${!outputLib}/''${targetConfig}/lib32"
# This will redirect $output/$targetConfig/lib{,32,64} to $output/$targetConfig/lib.
lib.optionalString isCross ''
makeCompatibilitySymlink lib $targetConfig/lib32
makeCompatibilitySymlink lib $targetConfig/lib64
'';
postInstall = ''
# Move runtime libraries to lib output.
moveToOutput "''${targetConfig+$targetConfig/}lib/lib*.so*" "''${!outputLib}"
moveToOutput "''${targetConfig+$targetConfig/}lib/lib*.la" "''${!outputLib}"
moveToOutput "''${targetConfig+$targetConfig/}lib/lib*.dylib" "''${!outputLib}"
moveToOutput "''${targetConfig+$targetConfig/}lib/lib*.dll.a" "''${!outputLib}"
moveToOutput "''${targetConfig+$targetConfig/}lib/lib*.dll" "''${!outputLib}"
# Clean up our compatibility symlinks (see above)
for link in "''${compatibilitySymlinks[@]}"; do
echo "Removing compatibility symlink: $link"
rm -f "$link"
done
# Move target runtime libraries to lib output.
# For non-cross, they're in $out/lib; for cross, they're in $out/$targetConfig/lib.
targetLibDir="''${targetConfig+$targetConfig/}lib"
moveToOutput "$targetLibDir/lib*.so*" "''${!outputLib}"
moveToOutput "$targetLibDir/lib*.la" "''${!outputLib}"
moveToOutput "$targetLibDir/lib*.dylib" "''${!outputLib}"
moveToOutput "$targetLibDir/lib*.dll.a" "''${!outputLib}"
moveToOutput "$targetLibDir/lib*.dll" "''${!outputLib}"
moveToOutput "share/gcc-*/python" "''${!outputLib}"
if [ -z "$enableShared" ]; then
moveToOutput "''${targetConfig+$targetConfig/}lib/lib*.a" "''${!outputLib}"
moveToOutput "$targetLibDir/lib*.a" "''${!outputLib}"
fi
for i in "''${!outputLib}/''${targetConfig}"/lib/*.{la,py}; do
for i in "''${!outputLib}"/$targetLibDir/*.{la,py}; do
substituteInPlace "$i" --replace "$out" "''${!outputLib}"
done
# Multilib and cross can't exist at the same time, so just use lib64 here
if [ -n "$enableMultilib" ]; then
moveToOutput "''${targetConfig+$targetConfig/}lib64/lib*.so*" "''${!outputLib}"
moveToOutput "''${targetConfig+$targetConfig/}lib64/lib*.la" "''${!outputLib}"
moveToOutput "''${targetConfig+$targetConfig/}lib64/lib*.dylib" "''${!outputLib}"
moveToOutput "''${targetConfig+$targetConfig/}lib64/lib*.dll.a" "''${!outputLib}"
moveToOutput "''${targetConfig+$targetConfig/}lib64/lib*.dll" "''${!outputLib}"
moveToOutput "lib64/lib*.so*" "''${!outputLib}"
moveToOutput "lib64/lib*.la" "''${!outputLib}"
moveToOutput "lib64/lib*.dylib" "''${!outputLib}"
moveToOutput "lib64/lib*.dll.a" "''${!outputLib}"
moveToOutput "lib64/lib*.dll" "''${!outputLib}"
for i in "''${!outputLib}/''${targetConfig}"/lib64/*.{la,py}; do
for i in "''${!outputLib}"/lib64/*.{la,py}; do
substituteInPlace "$i" --replace "$out" "''${!outputLib}"
done
fi
@@ -313,9 +346,15 @@ originalAttrs:
ln -sf "$man_prefix"gcc.1 "$i"
fi
done
''
# if cross-compiling, link from $lib/lib to $lib/${targetConfig}.
# since native-compiles have $lib/lib as a directory (not a
# symlink), this ensures that in every case we can assume that
# $lib/lib contains the .so files
+ lib.optionalString isCross ''
if [ -e "$lib/$targetConfig/lib" ]; then
ln -s "$lib/$targetConfig/lib" "$lib/lib"
fi
'';
}
// lib.optionalAttrs ((stdenv.targetPlatform.config != stdenv.hostPlatform.config) && withoutTargetLibc) {
dontCheckForBrokenSymlinks = true;
}
))

View File

@@ -391,13 +391,5 @@ pipe ((callFile ./common/builder.nix {}) ({
(callPackage ./common/libgcc.nix { inherit version langC langCC langJit targetPlatform hostPlatform withoutTargetLibc enableShared libcCross; })
] ++ optionals atLeast11 [
(callPackage ./common/checksum.nix { inherit langC langCC; })
]
# This symlink points to itself, and we disallow that now by noBrokenSymlinks (#370750)
# TODO: find how exactly this happens and solve it in a better way.
++ optional langJit (pkg: pkg.overrideAttrs (attrs: {
postInstall = attrs.postInstall or "" + ''
rm "$out/lib/lib"
'';
}))
)
])