From 17c01aad84c52457a5dd20fa609d872d156fa5be Mon Sep 17 00:00:00 2001 From: K900 Date: Sat, 8 Feb 2025 12:07:15 +0300 Subject: [PATCH 1/4] gcc: explicitly disallow cross + multilib, extract targetLibDir to variable --- .../compilers/gcc/common/builder.nix | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/pkgs/development/compilers/gcc/common/builder.nix b/pkgs/development/compilers/gcc/common/builder.nix index 633251910dbe..0b3847f8a167 100644 --- a/pkgs/development/compilers/gcc/common/builder.nix +++ b/pkgs/development/compilers/gcc/common/builder.nix @@ -8,8 +8,12 @@ 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: @@ -244,30 +248,34 @@ originalAttrs: ''; 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}" + # 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 From 5e2e98f3b71f1b7e0168e5c071bc9dff029287cb Mon Sep 17 00:00:00 2001 From: K900 Date: Sat, 8 Feb 2025 12:09:49 +0300 Subject: [PATCH 2/4] gcc: document, clean up, undangle install symlink hacks --- .../compilers/gcc/common/builder.nix | 87 +++++++++++++------ 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/pkgs/development/compilers/gcc/common/builder.nix b/pkgs/development/compilers/gcc/common/builder.nix index 0b3847f8a167..e7cc919cdeb2 100644 --- a/pkgs/development/compilers/gcc/common/builder.nix +++ b/pkgs/development/compilers/gcc/common/builder.nix @@ -214,40 +214,66 @@ 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 = '' + # 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" @@ -321,6 +347,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) { From a820a1b67b71c2d6c5f2e0d922acf06f4fae8244 Mon Sep 17 00:00:00 2001 From: K900 Date: Sun, 2 Feb 2025 09:49:23 +0300 Subject: [PATCH 3/4] Revert "gcc: disable symlink checks on cross + nolibc for now" This reverts commit 3fd43d5d7494068b2c8a9d904406f64d430dd029. The proper fix is now in. --- pkgs/development/compilers/gcc/common/builder.nix | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkgs/development/compilers/gcc/common/builder.nix b/pkgs/development/compilers/gcc/common/builder.nix index e7cc919cdeb2..47b3ed1d3adc 100644 --- a/pkgs/development/compilers/gcc/common/builder.nix +++ b/pkgs/development/compilers/gcc/common/builder.nix @@ -3,7 +3,6 @@ stdenv, enableMultilib, targetConfig, - withoutTargetLibc, }: let @@ -358,7 +357,4 @@ originalAttrs: fi ''; } - // lib.optionalAttrs ((stdenv.targetPlatform.config != stdenv.hostPlatform.config) && withoutTargetLibc) { - dontCheckForBrokenSymlinks = true; - } )) From 50319982e02a215128107b5b30ad310fd4dc5ee3 Mon Sep 17 00:00:00 2001 From: K900 Date: Sat, 8 Feb 2025 13:43:37 +0300 Subject: [PATCH 4/4] Revert "libgccjit, gccgo*: remove a reflexive symlink" This reverts commit c3c1643d8af3092f2defffa138dc907ddfcff803. Fixed properly now. --- pkgs/development/compilers/gcc/default.nix | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/pkgs/development/compilers/gcc/default.nix b/pkgs/development/compilers/gcc/default.nix index 66affd84a593..91d27aba7e2b 100644 --- a/pkgs/development/compilers/gcc/default.nix +++ b/pkgs/development/compilers/gcc/default.nix @@ -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" - ''; - })) -) +])