at master 20 kB view raw
1{ 2 lib, 3 stdenv, 4 fetchurl, 5 perl, 6 gcc, 7 ncurses5, 8 ncurses6, 9 gmp, 10 libiconv, 11 numactl, 12 libffi, 13 coreutils, 14 targetPackages, 15 16 # minimal = true; will remove files that aren't strictly necessary for 17 # regular builds and GHC bootstrapping. 18 # This is "useful" for staying within hydra's output limits for at least the 19 # aarch64-linux architecture. 20 minimal ? false, 21}: 22 23# Prebuilt only does native 24assert stdenv.targetPlatform == stdenv.hostPlatform; 25 26let 27 downloadsUrl = "https://downloads.haskell.org/ghc"; 28 29 # Copy sha256 from https://downloads.haskell.org/~ghc/9.2.4/SHA256SUMS 30 version = "9.2.4"; 31 32 # Information about available bindists that we use in the build. 33 # 34 # # Bindist library checking 35 # 36 # The field `archSpecificLibraries` also provides a way for us get notified 37 # early when the upstream bindist changes its dependencies (e.g. because a 38 # newer Debian version is used that uses a new `ncurses` version). 39 # 40 # Usage: 41 # 42 # * You can find the `fileToCheckFor` of libraries by running `readelf -d` 43 # on the compiler binary (`exePathForLibraryCheck`). 44 # * To skip library checking for an architecture, 45 # set `exePathForLibraryCheck = null`. 46 # * To skip file checking for a specific arch specific library, 47 # set `fileToCheckFor = null`. 48 ghcBinDists = { 49 # Binary distributions for the default libc (e.g. glibc, or libSystem on Darwin) 50 # nixpkgs uses for the respective system. 51 defaultLibc = { 52 i686-linux = { 53 variantSuffix = ""; 54 src = { 55 url = "${downloadsUrl}/${version}/ghc-${version}-i386-deb9-linux.tar.xz"; 56 sha256 = "5dc1eb9c65f01b1e5c5693af72af07a4e9e75c6920e620fd598daeefa804487a"; 57 }; 58 exePathForLibraryCheck = "ghc/stage2/build/tmp/ghc-stage2"; 59 archSpecificLibraries = [ 60 { 61 nixPackage = gmp; 62 fileToCheckFor = null; 63 } 64 # The i686-linux bindist provided by GHC HQ is currently built on Debian 9, 65 # which link it against `libtinfo.so.5` (ncurses 5). 66 # Other bindists are linked `libtinfo.so.6` (ncurses 6). 67 { 68 nixPackage = ncurses5; 69 fileToCheckFor = "libtinfo.so.5"; 70 } 71 ]; 72 }; 73 x86_64-linux = { 74 variantSuffix = ""; 75 src = { 76 url = "${downloadsUrl}/${version}/ghc-${version}-x86_64-deb10-linux.tar.xz"; 77 sha256 = "a77a91a39d9b0167124b7e97648b2b52973ae0978cb259e0d44f0752a75037cb"; 78 }; 79 exePathForLibraryCheck = "ghc/stage2/build/tmp/ghc-stage2"; 80 archSpecificLibraries = [ 81 { 82 nixPackage = gmp; 83 fileToCheckFor = null; 84 } 85 { 86 nixPackage = ncurses6; 87 fileToCheckFor = "libtinfo.so.6"; 88 } 89 ]; 90 }; 91 aarch64-linux = { 92 variantSuffix = ""; 93 src = { 94 url = "${downloadsUrl}/${version}/ghc-${version}-aarch64-deb10-linux.tar.xz"; 95 sha256 = "fc7dbc6bae36ea5ac30b7e9a263b7e5be3b45b0eb3e893ad0bc2c950a61f14ec"; 96 }; 97 exePathForLibraryCheck = "ghc/stage2/build/tmp/ghc-stage2"; 98 archSpecificLibraries = [ 99 { 100 nixPackage = gmp; 101 fileToCheckFor = null; 102 } 103 { 104 nixPackage = ncurses6; 105 fileToCheckFor = "libtinfo.so.6"; 106 } 107 { 108 nixPackage = numactl; 109 fileToCheckFor = null; 110 } 111 ]; 112 }; 113 x86_64-darwin = { 114 variantSuffix = ""; 115 src = { 116 url = "${downloadsUrl}/${version}/ghc-${version}-x86_64-apple-darwin.tar.xz"; 117 sha256 = "f2e8366fd3754dd9388510792aba2d2abecb1c2f7f1e5555f6065c3c5e2ffec4"; 118 }; 119 exePathForLibraryCheck = null; # we don't have a library check for darwin yet 120 archSpecificLibraries = [ 121 { 122 nixPackage = gmp; 123 fileToCheckFor = null; 124 } 125 { 126 nixPackage = ncurses6; 127 fileToCheckFor = null; 128 } 129 { 130 nixPackage = libiconv; 131 fileToCheckFor = null; 132 } 133 ]; 134 isHadrian = true; 135 }; 136 aarch64-darwin = { 137 variantSuffix = ""; 138 src = { 139 url = "${downloadsUrl}/${version}/ghc-${version}-aarch64-apple-darwin.tar.xz"; 140 sha256 = "8cf8408544a1a43adf1bbbb0dd6b074efadffc68bfa1a792947c52e825171224"; 141 }; 142 exePathForLibraryCheck = null; # we don't have a library check for darwin yet 143 archSpecificLibraries = [ 144 { 145 nixPackage = gmp; 146 fileToCheckFor = null; 147 } 148 { 149 nixPackage = ncurses6; 150 fileToCheckFor = null; 151 } 152 { 153 nixPackage = libiconv; 154 fileToCheckFor = null; 155 } 156 ]; 157 isHadrian = true; 158 }; 159 }; 160 # Binary distributions for the musl libc for the respective system. 161 musl = { 162 x86_64-linux = { 163 variantSuffix = "-musl"; 164 src = { 165 url = "${downloadsUrl}/${version}/ghc-${version}-x86_64-alpine3.12-linux-gmp.tar.xz"; 166 sha256 = "026348947d30a156b84de5d6afeaa48fdcb2795b47954cd8341db00d3263a481"; 167 }; 168 isStatic = true; 169 isHadrian = true; 170 # We can't check the RPATH for statically linked executable 171 exePathForLibraryCheck = null; 172 archSpecificLibraries = [ 173 { 174 nixPackage = gmp.override { withStatic = true; }; 175 fileToCheckFor = null; 176 } 177 ]; 178 }; 179 }; 180 }; 181 182 distSetName = if stdenv.hostPlatform.isMusl then "musl" else "defaultLibc"; 183 184 binDistUsed = 185 ghcBinDists.${distSetName}.${stdenv.hostPlatform.system} 186 or (throw "cannot bootstrap GHC on this platform ('${stdenv.hostPlatform.system}' with libc '${distSetName}')"); 187 188 gmpUsed = 189 (builtins.head ( 190 builtins.filter ( 191 drv: lib.hasPrefix "gmp" (drv.nixPackage.name or "") 192 ) binDistUsed.archSpecificLibraries 193 )).nixPackage; 194 195 libPath = lib.makeLibraryPath ( 196 # Add arch-specific libraries. 197 map ({ nixPackage, ... }: nixPackage) binDistUsed.archSpecificLibraries 198 ); 199 200 libEnvVar = lib.optionalString stdenv.hostPlatform.isDarwin "DY" + "LD_LIBRARY_PATH"; 201 202 runtimeDeps = [ 203 targetPackages.stdenv.cc 204 targetPackages.stdenv.cc.bintools 205 coreutils # for cat 206 ] 207 # On darwin, we need unwrapped bintools as well (for otool) 208 ++ lib.optionals (stdenv.targetPlatform.linker == "cctools") [ 209 targetPackages.stdenv.cc.bintools.bintools 210 ]; 211 212in 213 214stdenv.mkDerivation { 215 inherit version; 216 pname = "ghc-binary${binDistUsed.variantSuffix}"; 217 218 src = fetchurl binDistUsed.src; 219 220 nativeBuildInputs = [ perl ]; 221 222 # Set LD_LIBRARY_PATH or equivalent so that the programs running as part 223 # of the bindist installer can find the libraries they expect. 224 # Cannot patchelf beforehand due to relative RPATHs that anticipate 225 # the final install location. 226 ${libEnvVar} = libPath; 227 228 postUnpack = 229 # Verify our assumptions of which `libtinfo.so` (ncurses) version is used, 230 # so that we know when ghc bindists upgrade that and we need to update the 231 # version used in `libPath`. 232 lib.optionalString (binDistUsed.exePathForLibraryCheck != null) 233 # Note the `*` glob because some GHCs have a suffix when unpacked, e.g. 234 # the musl bindist has dir `ghc-VERSION-x86_64-unknown-linux/`. 235 # As a result, don't shell-quote this glob when splicing the string. 236 ( 237 let 238 buildExeGlob = ''ghc-${version}*/"${binDistUsed.exePathForLibraryCheck}"''; 239 in 240 lib.concatStringsSep "\n" [ 241 ('' 242 shopt -u nullglob 243 echo "Checking that ghc binary exists in bindist at ${buildExeGlob}" 244 if ! test -e ${buildExeGlob}; then 245 echo >&2 "GHC binary ${binDistUsed.exePathForLibraryCheck} could not be found in the bindist build directory (at ${buildExeGlob}) for arch ${stdenv.hostPlatform.system}, please check that ghcBinDists correctly reflect the bindist dependencies!"; exit 1; 246 fi 247 '') 248 (lib.concatMapStringsSep "\n" ( 249 { fileToCheckFor, nixPackage }: 250 lib.optionalString (fileToCheckFor != null) '' 251 echo "Checking bindist for ${fileToCheckFor} to ensure that is still used" 252 if ! readelf -d ${buildExeGlob} | grep "${fileToCheckFor}"; then 253 echo >&2 "File ${fileToCheckFor} could not be found in ${binDistUsed.exePathForLibraryCheck} for arch ${stdenv.hostPlatform.system}, please check that ghcBinDists correctly reflect the bindist dependencies!"; exit 1; 254 fi 255 256 echo "Checking that the nix package ${nixPackage} contains ${fileToCheckFor}" 257 if ! test -e "${lib.getLib nixPackage}/lib/${fileToCheckFor}"; then 258 echo >&2 "Nix package ${nixPackage} did not contain ${fileToCheckFor} for arch ${stdenv.hostPlatform.system}, please check that ghcBinDists correctly reflect the bindist dependencies!"; exit 1; 259 fi 260 '' 261 ) binDistUsed.archSpecificLibraries) 262 ] 263 ) 264 # GHC has dtrace probes, which causes ld to try to open /usr/lib/libdtrace.dylib 265 # during linking 266 + lib.optionalString stdenv.hostPlatform.isDarwin '' 267 export NIX_LDFLAGS+=" -no_dtrace_dof" 268 # not enough room in the object files for the full path to libiconv :( 269 for exe in $(find . -type f -executable); do 270 isScript $exe && continue 271 ln -fs ${libiconv}/lib/libiconv.dylib $(dirname $exe)/libiconv.dylib 272 install_name_tool -change /usr/lib/libiconv.2.dylib @executable_path/libiconv.dylib $exe 273 done 274 '' 275 + 276 277 # Some scripts used during the build need to have their shebangs patched 278 '' 279 patchShebangs ghc-${version}/utils/ 280 patchShebangs ghc-${version}/configure 281 test -d ghc-${version}/inplace/bin && \ 282 patchShebangs ghc-${version}/inplace/bin 283 '' 284 + 285 # We have to patch the GMP paths for the integer-gmp package. 286 '' 287 find . -name ghc-bignum.buildinfo \ 288 -exec sed -i "s@extra-lib-dirs: @extra-lib-dirs: ${lib.getLib gmpUsed}/lib@" {} \; 289 290 # we need to modify the package db directly for hadrian bindists 291 find . -name 'ghc-bignum*.conf' \ 292 -exec sed -e '/^[a-z-]*library-dirs/a \ ${lib.getLib gmpUsed}/lib' -i {} \; 293 '' 294 + lib.optionalString stdenv.hostPlatform.isDarwin '' 295 # we need to modify the package db directly for hadrian bindists 296 # (all darwin bindists are hadrian-based for 9.2.2) 297 find . -name 'base*.conf' \ 298 -exec sed -e '/^[a-z-]*library-dirs/a \ ${lib.getLib libiconv}/lib' -i {} \; 299 300 # To link RTS in the end we also need libffi now 301 find . -name 'rts*.conf' \ 302 -exec sed -e '/^[a-z-]*library-dirs/a \ ${lib.getLib libffi}/lib' \ 303 -e 's@/Library/Developer/.*/usr/include/ffi@${lib.getDev libffi}/include@' \ 304 -i {} \; 305 '' 306 + 307 # Some platforms do HAVE_NUMA so -lnuma requires it in library-dirs in rts/package.conf.in 308 # FFI_LIB_DIR is a good indication of places it must be needed. 309 lib.optionalString 310 ( 311 lib.meta.availableOn stdenv.hostPlatform numactl 312 && builtins.any ({ nixPackage, ... }: nixPackage == numactl) binDistUsed.archSpecificLibraries 313 ) 314 '' 315 find . -name package.conf.in \ 316 -exec sed -i "s@FFI_LIB_DIR@FFI_LIB_DIR ${numactl.out}/lib@g" {} \; 317 '' 318 + 319 # Rename needed libraries and binaries, fix interpreter 320 lib.optionalString stdenv.hostPlatform.isLinux '' 321 find . -type f -executable -exec patchelf \ 322 --interpreter ${stdenv.cc.bintools.dynamicLinker} {} \; 323 ''; 324 325 # fix for `configure: error: Your linker is affected by binutils #16177` 326 preConfigure = lib.optionalString stdenv.targetPlatform.isAarch32 "LD=ld.gold"; 327 328 configurePlatforms = [ ]; 329 configureFlags = [ 330 "--with-gmp-includes=${lib.getDev gmpUsed}/include" 331 # Note `--with-gmp-libraries` does nothing for GHC bindists: 332 # https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6124 333 ] 334 ++ lib.optional stdenv.hostPlatform.isDarwin "--with-gcc=${./gcc-clang-wrapper.sh}" 335 # From: https://github.com/NixOS/nixpkgs/pull/43369/commits 336 ++ lib.optional stdenv.hostPlatform.isMusl "--disable-ld-override"; 337 338 # No building is necessary, but calling make without flags ironically 339 # calls install-strip ... 340 dontBuild = true; 341 342 # GHC tries to remove xattrs when installing to work around Gatekeeper 343 # (see https://gitlab.haskell.org/ghc/ghc/-/issues/17418). This step normally 344 # succeeds in nixpkgs because xattrs are not allowed in the store, but it 345 # can fail when a file has the `com.apple.provenance` xattr, and it can’t be 346 # modified (such as target of the symlink to `libiconv.dylib`). 347 # The `com.apple.provenance` xattr is a new feature of macOS as of macOS 13. 348 # See: https://eclecticlight.co/2023/03/13/ventura-has-changed-app-quarantine-with-a-new-xattr/ 349 makeFlags = lib.optionals stdenv.buildPlatform.isDarwin [ "XATTR=/does-not-exist" ]; 350 351 # Patch scripts to include runtime dependencies in $PATH. 352 postInstall = '' 353 for i in "$out/bin/"*; do 354 test ! -h "$i" || continue 355 isScript "$i" || continue 356 sed -i -e '2i export PATH="${lib.makeBinPath runtimeDeps}:$PATH"' "$i" 357 done 358 ''; 359 360 # Apparently necessary for the ghc Alpine (musl) bindist: 361 # When we strip, and then run the 362 # patchelf --set-rpath "${libPath}:$(patchelf --print-rpath $p)" $p 363 # below, running ghc (e.g. during `installCheckPhase)` gives some apparently 364 # corrupted rpath or whatever makes the loader work on nonsensical strings: 365 # running install tests 366 # Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: : symbol not found 367 # Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: ir6zf6c9f86pfx8sr30n2vjy-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/../lib/x86_64-linux-ghc-8.10.5/libHSexceptions-0.10.4-ghc8.10.5.so: symbol not found 368 # Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: y/lib/ghc-8.10.5/bin/../lib/x86_64-linux-ghc-8.10.5/libHStemplate-haskell-2.16.0.0-ghc8.10.5.so: symbol not found 369 # Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: 8.10.5/libHStemplate-haskell-2.16.0.0-ghc8.10.5.so: symbol not found 370 # Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: �: symbol not found 371 # Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: �?: symbol not found 372 # Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: 64-linux-ghc-8.10.5/libHSexceptions-0.10.4-ghc8.10.5.so: symbol not found 373 # This is extremely bogus and should be investigated. 374 dontStrip = if stdenv.hostPlatform.isMusl then true else false; # `if` for explicitness 375 376 # On Linux, use patchelf to modify the executables so that they can 377 # find editline/gmp. 378 postFixup = 379 lib.optionalString (stdenv.hostPlatform.isLinux && !(binDistUsed.isStatic or false)) ( 380 if stdenv.hostPlatform.isAarch64 then 381 # Keep rpath as small as possible on aarch64 for patchelf#244. All Elfs 382 # are 2 directories deep from $out/lib, so pooling symlinks there makes 383 # a short rpath. 384 '' 385 (cd $out/lib; ln -s ${ncurses6.out}/lib/libtinfo.so.6) 386 (cd $out/lib; ln -s ${lib.getLib gmpUsed}/lib/libgmp.so.10) 387 (cd $out/lib; ln -s ${numactl.out}/lib/libnuma.so.1) 388 for p in $(find "$out/lib" -type f -name "*\.so*"); do 389 (cd $out/lib; ln -s $p) 390 done 391 392 for p in $(find "$out/lib" -type f -executable); do 393 if isELF "$p"; then 394 echo "Patchelfing $p" 395 patchelf --set-rpath "\$ORIGIN:\$ORIGIN/../.." $p 396 fi 397 done 398 '' 399 else 400 '' 401 for p in $(find "$out" -type f -executable); do 402 if isELF "$p"; then 403 echo "Patchelfing $p" 404 patchelf --set-rpath "${libPath}:$(patchelf --print-rpath $p)" $p 405 fi 406 done 407 '' 408 ) 409 + lib.optionalString stdenv.hostPlatform.isDarwin '' 410 # not enough room in the object files for the full path to libiconv :( 411 for exe in $(find "$out" -type f -executable); do 412 isScript $exe && continue 413 ln -fs ${libiconv}/lib/libiconv.dylib $(dirname $exe)/libiconv.dylib 414 install_name_tool -change /usr/lib/libiconv.2.dylib @executable_path/libiconv.dylib $exe 415 done 416 417 for file in $(find "$out" -name setup-config); do 418 substituteInPlace $file --replace /usr/bin/ranlib "$(type -P ranlib)" 419 done 420 '' 421 + lib.optionalString minimal '' 422 # Remove profiling files 423 find $out -type f -name '*.p_o' -delete 424 find $out -type f -name '*.p_hi' -delete 425 find $out -type f -name '*_p.a' -delete 426 # `-f` because e.g. musl bindist does not have this file. 427 rm -f $out/lib/ghc-*/bin/ghc-iserv-prof 428 # Hydra will redistribute this derivation, so we have to keep the docs for 429 # legal reasons (retaining the legal notices etc) 430 # As a last resort we could unpack the docs separately and symlink them in. 431 # They're in $out/share/{doc,man}. 432 '' 433 # Recache package db which needs to happen for Hadrian bindists 434 # where we modify the package db before installing 435 + '' 436 shopt -s nullglob 437 package_db=("$out"/lib/ghc-*/lib/package.conf.d "$out"/lib/ghc-*/package.conf.d) 438 "$out/bin/ghc-pkg" --package-db="$package_db" recache 439 ''; 440 441 # GHC cannot currently produce outputs that are ready for `-pie` linking. 442 # Thus, disable `pie` hardening, otherwise `recompile with -fPIE` errors appear. 443 # See: 444 # * https://github.com/NixOS/nixpkgs/issues/129247 445 # * https://gitlab.haskell.org/ghc/ghc/-/issues/19580 446 hardeningDisable = [ "pie" ]; 447 448 doInstallCheck = true; 449 installCheckPhase = '' 450 # Sanity check, can ghc create executables? 451 cd $TMP 452 mkdir test-ghc; cd test-ghc 453 cat > main.hs << EOF 454 {-# LANGUAGE TemplateHaskell #-} 455 module Main where 456 main = putStrLn \$([|"yes"|]) 457 EOF 458 env -i $out/bin/ghc --make main.hs || exit 1 459 echo compilation ok 460 [ $(./main) == "yes" ] 461 ''; 462 463 passthru = { 464 targetPrefix = ""; 465 enableShared = true; 466 467 llvmPackages = null; 468 469 # Our Cabal compiler name 470 haskellCompilerName = "ghc-${version}"; 471 } 472 # We duplicate binDistUsed here since we have a sensible default even if no bindist is available, 473 # this makes sure that getting the `meta` attribute doesn't throw even on unsupported platforms. 474 // lib.optionalAttrs (ghcBinDists.${distSetName}.${stdenv.hostPlatform.system}.isHadrian or false) { 475 # Normal GHC derivations expose the hadrian derivation used to build them 476 # here. In the case of bindists we just make sure that the attribute exists, 477 # as it is used for checking if a GHC derivation has been built with hadrian. 478 # The isHadrian mechanism will become obsolete with GHCs that use hadrian 479 # exclusively, i.e. 9.6 (and 9.4?). 480 hadrian = null; 481 }; 482 483 meta = rec { 484 homepage = "http://haskell.org/ghc"; 485 description = "Glasgow Haskell Compiler"; 486 license = lib.licenses.bsd3; 487 # HACK: since we can't encode the libc / abi in platforms, we need 488 # to make the platform list dependent on the evaluation platform 489 # in order to avoid eval errors with musl which supports less 490 # platforms than the default libcs (i. e. glibc / libSystem). 491 # This is done for the benefit of Hydra, so `packagePlatforms` 492 # won't return any platforms that would cause an evaluation 493 # failure for `pkgsMusl.haskell.compiler.ghc922Binary`, as 494 # long as the evaluator runs on a platform that supports 495 # `pkgsMusl`. 496 platforms = builtins.attrNames ghcBinDists.${distSetName}; 497 teams = [ lib.teams.haskell ]; 498 broken = !(import ./common-have-ncg.nix { inherit lib stdenv version; }); 499 }; 500}