lol

gcc: rework, clean up, and document the cursed symlink hack (#378569)

authored by

K900 and committed by
GitHub
ceb3ac5f eafe4723

+120 -96
+113 -90
pkgs/development/compilers/gcc/common/builder.nix
··· 3 3 stdenv, 4 4 enableMultilib, 5 5 targetConfig, 6 - withoutTargetLibc, 7 6 }: 8 7 9 8 let ··· 210 209 ''; 211 210 212 211 preInstall = 212 + # What follows is a horribly cursed hack. 213 + # 214 + # GCC will install its libraries to $out/lib, $out/lib32, $out/lib64, 215 + # $out/$targetConfig/lib, $out/$targetConfig/lib32 or $out/$targetConfig/lib64, 216 + # depending on whether it's built as native or cross, and the exact target spec. 217 + # 218 + # We can't predict what it's actually going to do, and we also can't just tell it 219 + # to always install to $out/lib, but we want everything to end up in $out/lib 220 + # for consistency (multilib weirdness aside). 221 + # 222 + # So, we create a bunch of symlinks before we run GCC's install phase, 223 + # redirecting every possible directory it may want to write to to the place 224 + # we actually want things to be installed. 225 + # We will then nuke the symlinks in postInstall. 226 + # 227 + # FIXME: there must be a better way to do this. 213 228 '' 214 - mkdir -p "$out/''${targetConfig}/lib" 215 - mkdir -p "''${!outputLib}/''${targetConfig}/lib" 229 + declare -ga compatibilitySymlinks=() 230 + 231 + makeCompatibilitySymlink() { 232 + for output in "$out" "''${!outputLib}"; do 233 + local linkTarget="$1" 234 + local linkName="$output/$2" 235 + 236 + echo "Creating compatibility symlink: $linkTarget -> $linkName" 237 + 238 + mkdir -p "$(dirname "$linkName")" 239 + ln -s "$linkTarget" "$linkName" 240 + compatibilitySymlinks+=("$linkName") 241 + done 242 + } 216 243 '' 217 244 + 218 - # if cross-compiling, link from $lib/lib to $lib/${targetConfig}. 219 - # since native-compiles have $lib/lib as a directory (not a 220 - # symlink), this ensures that in every case we can assume that 221 - # $lib/lib contains the .so files 222 - lib.optionalString (with stdenv; targetPlatform.config != hostPlatform.config) '' 223 - ln -Ts "''${!outputLib}/''${targetConfig}/lib" $lib/lib 245 + # This will redirect $output/lib{32,64} to $output/lib. 246 + # Multilib is special, because it creates $out/lib (for 32-bit) 247 + # and $out/lib64 (for 64-bit). No other targets can have both. 248 + lib.optionalString (!enableMultilib) '' 249 + makeCompatibilitySymlink lib lib32 250 + makeCompatibilitySymlink lib lib64 224 251 '' 225 252 + 226 - # Make `lib64` symlinks to `lib`. 227 - lib.optionalString 228 - (!enableMultilib && stdenv.hostPlatform.is64bit && !stdenv.hostPlatform.isMips64n32) 229 - '' 230 - ln -s lib "$out/''${targetConfig}/lib64" 231 - ln -s lib "''${!outputLib}/''${targetConfig}/lib64" 232 - '' 233 - + 234 - # On mips platforms, gcc follows the IRIX naming convention: 235 - # 236 - # $PREFIX/lib = mips32 237 - # $PREFIX/lib32 = mips64n32 238 - # $PREFIX/lib64 = mips64 239 - # 240 - # Make `lib32` symlinks to `lib`. 241 - lib.optionalString (!enableMultilib && stdenv.targetPlatform.isMips64n32) '' 242 - ln -s lib "$out/''${targetConfig}/lib32" 243 - ln -s lib "''${!outputLib}/''${targetConfig}/lib32" 253 + # This will redirect $output/$targetConfig/lib{,32,64} to $output/lib. 254 + lib.optionalString (with stdenv; targetPlatform.config != hostPlatform.config) '' 255 + makeCompatibilitySymlink lib $targetConfig/lib32 256 + makeCompatibilitySymlink lib $targetConfig/lib64 257 + makeCompatibilitySymlink ../lib $targetConfig/lib 244 258 ''; 245 259 246 - postInstall = '' 247 - # Move runtime libraries to lib output. 248 - moveToOutput "''${targetConfig+$targetConfig/}lib/lib*.so*" "''${!outputLib}" 249 - moveToOutput "''${targetConfig+$targetConfig/}lib/lib*.la" "''${!outputLib}" 250 - moveToOutput "''${targetConfig+$targetConfig/}lib/lib*.dylib" "''${!outputLib}" 251 - moveToOutput "''${targetConfig+$targetConfig/}lib/lib*.dll.a" "''${!outputLib}" 252 - moveToOutput "''${targetConfig+$targetConfig/}lib/lib*.dll" "''${!outputLib}" 253 - moveToOutput "share/gcc-*/python" "''${!outputLib}" 260 + postInstall = 261 + '' 262 + # Clean up our compatibility symlinks (see above) 263 + for link in "''${compatibilitySymlinks[@]}"; do 264 + echo "Removing compatibility symlink: $link" 265 + rm -f "$link" 266 + done 254 267 255 - if [ -z "$enableShared" ]; then 256 - moveToOutput "''${targetConfig+$targetConfig/}lib/lib*.a" "''${!outputLib}" 257 - fi 268 + # Move runtime libraries to lib output. 269 + moveToOutput "lib/lib*.so*" "''${!outputLib}" 270 + moveToOutput "lib/lib*.la" "''${!outputLib}" 271 + moveToOutput "lib/lib*.dylib" "''${!outputLib}" 272 + moveToOutput "lib/lib*.dll.a" "''${!outputLib}" 273 + moveToOutput "lib/lib*.dll" "''${!outputLib}" 274 + moveToOutput "share/gcc-*/python" "''${!outputLib}" 258 275 259 - for i in "''${!outputLib}/''${targetConfig}"/lib/*.{la,py}; do 260 - substituteInPlace "$i" --replace "$out" "''${!outputLib}" 261 - done 276 + if [ -z "$enableShared" ]; then 277 + moveToOutput "lib/lib*.a" "''${!outputLib}" 278 + fi 262 279 263 - if [ -n "$enableMultilib" ]; then 264 - moveToOutput "''${targetConfig+$targetConfig/}lib64/lib*.so*" "''${!outputLib}" 265 - moveToOutput "''${targetConfig+$targetConfig/}lib64/lib*.la" "''${!outputLib}" 266 - moveToOutput "''${targetConfig+$targetConfig/}lib64/lib*.dylib" "''${!outputLib}" 267 - moveToOutput "''${targetConfig+$targetConfig/}lib64/lib*.dll.a" "''${!outputLib}" 268 - moveToOutput "''${targetConfig+$targetConfig/}lib64/lib*.dll" "''${!outputLib}" 280 + for i in "''${!outputLib}"/lib/*.{la,py}; do 281 + substituteInPlace "$i" --replace "$out" "''${!outputLib}" 282 + done 269 283 270 - for i in "''${!outputLib}/''${targetConfig}"/lib64/*.{la,py}; do 271 - substituteInPlace "$i" --replace "$out" "''${!outputLib}" 272 - done 273 - fi 284 + if [ -n "$enableMultilib" ]; then 285 + moveToOutput "lib64/lib*.so*" "''${!outputLib}" 286 + moveToOutput "lib64/lib*.la" "''${!outputLib}" 287 + moveToOutput "lib64/lib*.dylib" "''${!outputLib}" 288 + moveToOutput "lib64/lib*.dll.a" "''${!outputLib}" 289 + moveToOutput "lib64/lib*.dll" "''${!outputLib}" 274 290 275 - # Remove `fixincl' to prevent a retained dependency on the 276 - # previous gcc. 277 - rm -rf $out/libexec/gcc/*/*/install-tools 278 - rm -rf $out/lib/gcc/*/*/install-tools 291 + for i in "''${!outputLib}"/lib64/*.{la,py}; do 292 + substituteInPlace "$i" --replace "$out" "''${!outputLib}" 293 + done 294 + fi 295 + 296 + # Remove `fixincl' to prevent a retained dependency on the 297 + # previous gcc. 298 + rm -rf $out/libexec/gcc/*/*/install-tools 299 + rm -rf $out/lib/gcc/*/*/install-tools 279 300 280 - # More dependencies with the previous gcc or some libs (gccbug stores the build command line) 281 - rm -rf $out/bin/gccbug 301 + # More dependencies with the previous gcc or some libs (gccbug stores the build command line) 302 + rm -rf $out/bin/gccbug 282 303 283 - if type "install_name_tool"; then 284 - for i in "''${!outputLib}"/lib/*.*.dylib "''${!outputLib}"/lib/*.so.[0-9]; do 285 - install_name_tool -id "$i" "$i" || true 286 - for old_path in $(otool -L "$i" | grep "$out" | awk '{print $1}'); do 287 - new_path=`echo "$old_path" | sed "s,$out,''${!outputLib},"` 288 - install_name_tool -change "$old_path" "$new_path" "$i" || true 289 - done 290 - done 291 - fi 304 + if type "install_name_tool"; then 305 + for i in "''${!outputLib}"/lib/*.*.dylib "''${!outputLib}"/lib/*.so.[0-9]; do 306 + install_name_tool -id "$i" "$i" || true 307 + for old_path in $(otool -L "$i" | grep "$out" | awk '{print $1}'); do 308 + new_path=`echo "$old_path" | sed "s,$out,''${!outputLib},"` 309 + install_name_tool -change "$old_path" "$new_path" "$i" || true 310 + done 311 + done 312 + fi 292 313 293 - # Get rid of some "fixed" header files 294 - rm -rfv $out/lib/gcc/*/*/include-fixed/{root,linux,sys/mount.h,bits/statx.h,pthread.h} 314 + # Get rid of some "fixed" header files 315 + rm -rfv $out/lib/gcc/*/*/include-fixed/{root,linux,sys/mount.h,bits/statx.h,pthread.h} 295 316 296 - # Replace hard links for i686-pc-linux-gnu-gcc etc. with symlinks. 297 - for i in $out/bin/*-gcc*; do 298 - if cmp -s $out/bin/gcc $i; then 299 - ln -sfn gcc $i 300 - fi 301 - done 317 + # Replace hard links for i686-pc-linux-gnu-gcc etc. with symlinks. 318 + for i in $out/bin/*-gcc*; do 319 + if cmp -s $out/bin/gcc $i; then 320 + ln -sfn gcc $i 321 + fi 322 + done 302 323 303 - for i in $out/bin/c++ $out/bin/*-c++* $out/bin/*-g++*; do 304 - if cmp -s $out/bin/g++ $i; then 305 - ln -sfn g++ $i 306 - fi 307 - done 324 + for i in $out/bin/c++ $out/bin/*-c++* $out/bin/*-g++*; do 325 + if cmp -s $out/bin/g++ $i; then 326 + ln -sfn g++ $i 327 + fi 328 + done 308 329 309 - # Two identical man pages are shipped (moving and compressing is done later) 310 - for i in "$out"/share/man/man1/*g++.1; do 311 - if test -e "$i"; then 312 - man_prefix=`echo "$i" | sed "s,.*/\(.*\)g++.1,\1,"` 313 - ln -sf "$man_prefix"gcc.1 "$i" 314 - fi 315 - done 316 - ''; 317 - } 318 - // lib.optionalAttrs ((stdenv.targetPlatform.config != stdenv.hostPlatform.config) && withoutTargetLibc) { 319 - dontCheckForBrokenSymlinks = true; 330 + # Two identical man pages are shipped (moving and compressing is done later) 331 + for i in "$out"/share/man/man1/*g++.1; do 332 + if test -e "$i"; then 333 + man_prefix=`echo "$i" | sed "s,.*/\(.*\)g++.1,\1,"` 334 + ln -sf "$man_prefix"gcc.1 "$i" 335 + fi 336 + done 337 + '' 338 + + 339 + # Recreate the target symlink so GCC can find libgcc_s on non-split builds. 340 + lib.optionalString (with stdenv; targetPlatform.config != hostPlatform.config) '' 341 + ln -s $lib/lib $lib/$targetConfig/lib 342 + ''; 320 343 } 321 344 ))
+7 -6
pkgs/development/compilers/gcc/common/libgcc.nix
··· 105 105 + lib.optionalString enableLibGccOutput ( 106 106 '' 107 107 # move libgcc from lib to its own output (libgcc) 108 - mkdir -p $libgcc/${targetPlatformSlash}lib 109 - mv $lib/${targetPlatformSlash}lib/libgcc_s.so $libgcc/${targetPlatformSlash}lib/ 110 - mv $lib/${targetPlatformSlash}lib/libgcc_s.so.${libgcc_s-version-major} $libgcc/${targetPlatformSlash}lib/ 111 - ln -s $libgcc/${targetPlatformSlash}lib/libgcc_s.so $lib/${targetPlatformSlash}lib/ 112 - ln -s $libgcc/${targetPlatformSlash}lib/libgcc_s.so.${libgcc_s-version-major} $lib/${targetPlatformSlash}lib/ 108 + mkdir -p $libgcc/lib 109 + mv $lib/lib/libgcc_s.so $libgcc/lib/ 110 + mv $lib/lib/libgcc_s.so.${libgcc_s-version-major} $libgcc/lib/ 111 + ln -s $libgcc/lib/libgcc_s.so $lib/lib/ 112 + ln -s $libgcc/lib/libgcc_s.so.${libgcc_s-version-major} $lib/lib/ 113 113 '' 114 114 + lib.optionalString (targetPlatformSlash != "") '' 115 - ln -s ${targetPlatformSlash}lib $libgcc/lib 115 + mkdir -p $libgcc/${targetPlatformSlash} 116 + ln -s $libgcc/lib $libgcc/${targetPlatformSlash}lib 116 117 '' 117 118 # 118 119 # Nixpkgs ordinarily turns dynamic linking into pseudo-static linking: