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