at master 19 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.6.3/SHA256SUMS 30 version = "9.6.3"; 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 = "58be26f8b8f6b5bd8baf5c32abb03e2c4621646b2142fab10e5c7de5af5c50f8"; 57 }; 58 exePathForLibraryCheck = "bin/ghc"; 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-deb11-linux.tar.xz"; 77 sha256 = "c4c0124857265926f1cf22a09d950d7ba989ff94053a4ddf3dcdab5359f4cab7"; 78 }; 79 exePathForLibraryCheck = "bin/ghc"; 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 = "03c389859319f09452081310fc13af7525063ea8930830ef76be2a14b312271e"; 96 }; 97 exePathForLibraryCheck = "bin/ghc"; 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 = "dde46118ab8388fb1066312c097123e93b1dcf6ae366e3370f88ea456382c9db"; 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 }; 135 aarch64-darwin = { 136 variantSuffix = ""; 137 src = { 138 url = "${downloadsUrl}/${version}/ghc-${version}-aarch64-apple-darwin.tar.xz"; 139 sha256 = "e1cdf458926b2eaf52d2a8287d99a965040ff9051171f5c3b7467049cf0eb213"; 140 }; 141 exePathForLibraryCheck = null; # we don't have a library check for darwin yet 142 archSpecificLibraries = [ 143 { 144 nixPackage = gmp; 145 fileToCheckFor = null; 146 } 147 { 148 nixPackage = ncurses6; 149 fileToCheckFor = null; 150 } 151 { 152 nixPackage = libiconv; 153 fileToCheckFor = null; 154 } 155 ]; 156 }; 157 }; 158 # Binary distributions for the musl libc for the respective system. 159 musl = { 160 x86_64-linux = { 161 variantSuffix = "-musl"; 162 src = { 163 url = "${downloadsUrl}/${version}/ghc-${version}-x86_64-alpine3_12-linux.tar.xz"; 164 sha256 = "8f457af0aa40127049c11134c8793f64351a446e87da1f8ec256e1279b5ab61f"; 165 }; 166 exePathForLibraryCheck = "bin/ghc"; 167 archSpecificLibraries = [ 168 { 169 nixPackage = gmp; 170 fileToCheckFor = null; 171 } 172 { 173 nixPackage = ncurses6; 174 fileToCheckFor = "libncursesw.so.6"; 175 } 176 ]; 177 }; 178 }; 179 }; 180 181 distSetName = if stdenv.hostPlatform.isMusl then "musl" else "defaultLibc"; 182 183 binDistUsed = 184 ghcBinDists.${distSetName}.${stdenv.hostPlatform.system} 185 or (throw "cannot bootstrap GHC on this platform ('${stdenv.hostPlatform.system}' with libc '${distSetName}')"); 186 187 gmpUsed = 188 (builtins.head ( 189 builtins.filter ( 190 drv: lib.hasPrefix "gmp" (drv.nixPackage.name or "") 191 ) binDistUsed.archSpecificLibraries 192 )).nixPackage; 193 194 libPath = lib.makeLibraryPath ( 195 # Add arch-specific libraries. 196 map ({ nixPackage, ... }: nixPackage) binDistUsed.archSpecificLibraries 197 ); 198 199 libEnvVar = lib.optionalString stdenv.hostPlatform.isDarwin "DY" + "LD_LIBRARY_PATH"; 200 201 runtimeDeps = [ 202 targetPackages.stdenv.cc 203 targetPackages.stdenv.cc.bintools 204 coreutils # for cat 205 ] 206 # On darwin, we need unwrapped bintools as well (for otool) 207 ++ lib.optionals (stdenv.targetPlatform.linker == "cctools") [ 208 targetPackages.stdenv.cc.bintools.bintools 209 ]; 210 211in 212 213stdenv.mkDerivation { 214 inherit version; 215 pname = "ghc-binary${binDistUsed.variantSuffix}"; 216 217 src = fetchurl binDistUsed.src; 218 219 nativeBuildInputs = [ perl ]; 220 221 # Set LD_LIBRARY_PATH or equivalent so that the programs running as part 222 # of the bindist installer can find the libraries they expect. 223 # Cannot patchelf beforehand due to relative RPATHs that anticipate 224 # the final install location. 225 ${libEnvVar} = libPath; 226 227 postUnpack = 228 # Verify our assumptions of which `libtinfo.so` (ncurses) version is used, 229 # so that we know when ghc bindists upgrade that and we need to update the 230 # version used in `libPath`. 231 lib.optionalString (binDistUsed.exePathForLibraryCheck != null) 232 # Note the `*` glob because some GHCs have a suffix when unpacked, e.g. 233 # the musl bindist has dir `ghc-VERSION-x86_64-unknown-linux/`. 234 # As a result, don't shell-quote this glob when splicing the string. 235 ( 236 let 237 buildExeGlob = ''ghc-${version}*/"${binDistUsed.exePathForLibraryCheck}"''; 238 in 239 lib.concatStringsSep "\n" [ 240 ('' 241 shopt -u nullglob 242 echo "Checking that ghc binary exists in bindist at ${buildExeGlob}" 243 if ! test -e ${buildExeGlob}; then 244 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; 245 fi 246 '') 247 (lib.concatMapStringsSep "\n" ( 248 { fileToCheckFor, nixPackage }: 249 lib.optionalString (fileToCheckFor != null) '' 250 echo "Checking bindist for ${fileToCheckFor} to ensure that is still used" 251 if ! readelf -d ${buildExeGlob} | grep "${fileToCheckFor}"; then 252 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; 253 fi 254 255 echo "Checking that the nix package ${nixPackage} contains ${fileToCheckFor}" 256 if ! test -e "${lib.getLib nixPackage}/lib/${fileToCheckFor}"; then 257 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; 258 fi 259 '' 260 ) binDistUsed.archSpecificLibraries) 261 ] 262 ) 263 # GHC has dtrace probes, which causes ld to try to open /usr/lib/libdtrace.dylib 264 # during linking 265 + lib.optionalString stdenv.hostPlatform.isDarwin '' 266 export NIX_LDFLAGS+=" -no_dtrace_dof" 267 # not enough room in the object files for the full path to libiconv :( 268 for exe in $(find . -type f -executable); do 269 isMachO $exe || continue 270 ln -fs ${libiconv}/lib/libiconv.dylib $(dirname $exe)/libiconv.dylib 271 install_name_tool -change /usr/lib/libiconv.2.dylib @executable_path/libiconv.dylib $exe 272 done 273 '' 274 275 # We have to patch the GMP paths for the ghc-bignum package, for hadrian by 276 # modifying the package-db directly 277 + '' 278 find . -name 'ghc-bignum*.conf' \ 279 -exec sed -e '/^[a-z-]*library-dirs/a \ ${lib.getLib gmpUsed}/lib' -i {} \; 280 '' 281 # Similar for iconv and libffi on darwin 282 + lib.optionalString stdenv.hostPlatform.isDarwin '' 283 find . -name 'base*.conf' \ 284 -exec sed -e '/^[a-z-]*library-dirs/a \ ${lib.getLib libiconv}/lib' -i {} \; 285 286 # To link RTS in the end we also need libffi now 287 find . -name 'rts*.conf' \ 288 -exec sed -e '/^[a-z-]*library-dirs/a \ ${lib.getLib libffi}/lib' \ 289 -e 's@/Library/Developer/.*/usr/include/ffi@${lib.getDev libffi}/include@' \ 290 -i {} \; 291 '' 292 + 293 # Some platforms do HAVE_NUMA so -lnuma requires it in library-dirs in rts/package.conf.in 294 # FFI_LIB_DIR is a good indication of places it must be needed. 295 lib.optionalString 296 ( 297 lib.meta.availableOn stdenv.hostPlatform numactl 298 && builtins.any ({ nixPackage, ... }: nixPackage == numactl) binDistUsed.archSpecificLibraries 299 ) 300 '' 301 find . -name package.conf.in \ 302 -exec sed -i "s@FFI_LIB_DIR@FFI_LIB_DIR ${numactl.out}/lib@g" {} \; 303 '' 304 + 305 # Rename needed libraries and binaries, fix interpreter 306 lib.optionalString stdenv.hostPlatform.isLinux '' 307 find . -type f -executable -exec patchelf \ 308 --interpreter ${stdenv.cc.bintools.dynamicLinker} {} \; 309 ''; 310 311 # fix for `configure: error: Your linker is affected by binutils #16177` 312 preConfigure = lib.optionalString stdenv.targetPlatform.isAarch32 "LD=ld.gold"; 313 314 # GHC has a patched config.sub and bindists' platforms should always work 315 dontUpdateAutotoolsGnuConfigScripts = true; 316 317 configurePlatforms = [ ]; 318 configureFlags = 319 lib.optional stdenv.hostPlatform.isDarwin "--with-gcc=${./gcc-clang-wrapper.sh}" 320 # From: https://github.com/NixOS/nixpkgs/pull/43369/commits 321 ++ lib.optional stdenv.hostPlatform.isMusl "--disable-ld-override"; 322 323 # No building is necessary, but calling make without flags ironically 324 # calls install-strip ... 325 dontBuild = true; 326 327 # GHC tries to remove xattrs when installing to work around Gatekeeper 328 # (see https://gitlab.haskell.org/ghc/ghc/-/issues/17418). This step normally 329 # succeeds in nixpkgs because xattrs are not allowed in the store, but it 330 # can fail when a file has the `com.apple.provenance` xattr, and it can’t be 331 # modified (such as target of the symlink to `libiconv.dylib`). 332 # The `com.apple.provenance` xattr is a new feature of macOS as of macOS 13. 333 # See: https://eclecticlight.co/2023/03/13/ventura-has-changed-app-quarantine-with-a-new-xattr/ 334 makeFlags = lib.optionals stdenv.buildPlatform.isDarwin [ "XATTR=/does-not-exist" ]; 335 336 # Patch scripts to include runtime dependencies in $PATH. 337 postInstall = '' 338 for i in "$out/bin/"*; do 339 test ! -h "$i" || continue 340 isScript "$i" || continue 341 sed -i -e '2i export PATH="${lib.makeBinPath runtimeDeps}:$PATH"' "$i" 342 done 343 '' 344 + lib.optionalString stdenv.targetPlatform.isDarwin '' 345 # Work around building with binary GHC on Darwin due to GHCs use of `ar -L` when it 346 # detects `llvm-ar` even though the resulting archives are not supported by ld64. 347 # https://gitlab.haskell.org/ghc/ghc/-/issues/23188 348 # https://github.com/haskell/cabal/issues/8882 349 sed -i -e 's/,("ar supports -L", "YES")/,("ar supports -L", "NO")/' "$out/lib/ghc-${version}/lib/settings" 350 ''; 351 352 # Apparently necessary for the ghc Alpine (musl) bindist: 353 # When we strip, and then run the 354 # patchelf --set-rpath "${libPath}:$(patchelf --print-rpath $p)" $p 355 # below, running ghc (e.g. during `installCheckPhase)` gives some apparently 356 # corrupted rpath or whatever makes the loader work on nonsensical strings: 357 # running install tests 358 # Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: : symbol not found 359 # 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 360 # 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 361 # 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 362 # Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: �: symbol not found 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: 64-linux-ghc-8.10.5/libHSexceptions-0.10.4-ghc8.10.5.so: symbol not found 365 # This is extremely bogus and should be investigated. 366 dontStrip = if stdenv.hostPlatform.isMusl then true else false; # `if` for explicitness 367 368 # On Linux, use patchelf to modify the executables so that they can 369 # find editline/gmp. 370 postFixup = 371 lib.optionalString (stdenv.hostPlatform.isLinux && !(binDistUsed.isStatic or false)) ( 372 if stdenv.hostPlatform.isAarch64 then 373 # Keep rpath as small as possible on aarch64 for patchelf#244. All Elfs 374 # are 2 directories deep from $out/lib, so pooling symlinks there makes 375 # a short rpath. 376 '' 377 (cd $out/lib; ln -s ${ncurses6.out}/lib/libtinfo.so.6) 378 (cd $out/lib; ln -s ${lib.getLib gmpUsed}/lib/libgmp.so.10) 379 (cd $out/lib; ln -s ${numactl.out}/lib/libnuma.so.1) 380 for p in $(find "$out/lib" -type f -name "*\.so*"); do 381 (cd $out/lib; ln -s $p) 382 done 383 384 for p in $(find "$out/lib" -type f -executable); do 385 if isELF "$p"; then 386 echo "Patchelfing $p" 387 patchelf --set-rpath "\$ORIGIN:\$ORIGIN/../.." $p 388 fi 389 done 390 '' 391 else 392 '' 393 for p in $(find "$out" -type f -executable); do 394 if isELF "$p"; then 395 echo "Patchelfing $p" 396 patchelf --set-rpath "${libPath}:$(patchelf --print-rpath $p)" $p 397 fi 398 done 399 '' 400 ) 401 + lib.optionalString stdenv.hostPlatform.isDarwin '' 402 # not enough room in the object files for the full path to libiconv :( 403 for exe in $(find "$out" -type f -executable); do 404 isMachO $exe || continue 405 ln -fs ${libiconv}/lib/libiconv.dylib $(dirname $exe)/libiconv.dylib 406 install_name_tool -change /usr/lib/libiconv.2.dylib @executable_path/libiconv.dylib $exe 407 done 408 409 for file in $(find "$out" -name setup-config); do 410 substituteInPlace $file --replace /usr/bin/ranlib "$(type -P ranlib)" 411 done 412 '' 413 # Recache package db which needs to happen for Hadrian bindists 414 # where we modify the package db before installing 415 + '' 416 package_db=("$out"/lib/ghc-*/lib/package.conf.d) 417 "$out/bin/ghc-pkg" --package-db="$package_db" recache 418 ''; 419 420 # GHC cannot currently produce outputs that are ready for `-pie` linking. 421 # Thus, disable `pie` hardening, otherwise `recompile with -fPIE` errors appear. 422 # See: 423 # * https://github.com/NixOS/nixpkgs/issues/129247 424 # * https://gitlab.haskell.org/ghc/ghc/-/issues/19580 425 hardeningDisable = [ "pie" ]; 426 427 doInstallCheck = true; 428 installCheckPhase = '' 429 # Sanity check, can ghc create executables? 430 cd $TMP 431 mkdir test-ghc; cd test-ghc 432 cat > main.hs << EOF 433 {-# LANGUAGE TemplateHaskell #-} 434 module Main where 435 main = putStrLn \$([|"yes"|]) 436 EOF 437 env -i $out/bin/ghc --make main.hs || exit 1 438 echo compilation ok 439 [ $(./main) == "yes" ] 440 ''; 441 442 passthru = { 443 targetPrefix = ""; 444 enableShared = true; 445 446 llvmPackages = null; 447 448 # Our Cabal compiler name 449 haskellCompilerName = "ghc-${version}"; 450 451 # Normal GHC derivations expose the hadrian derivation used to build them 452 # here. In the case of bindists we just make sure that the attribute exists, 453 # as it is used for checking if a GHC derivation has been built with hadrian. 454 hadrian = null; 455 }; 456 457 meta = rec { 458 homepage = "http://haskell.org/ghc"; 459 description = "Glasgow Haskell Compiler"; 460 license = lib.licenses.bsd3; 461 # HACK: since we can't encode the libc / abi in platforms, we need 462 # to make the platform list dependent on the evaluation platform 463 # in order to avoid eval errors with musl which supports less 464 # platforms than the default libcs (i. e. glibc / libSystem). 465 # This is done for the benefit of Hydra, so `packagePlatforms` 466 # won't return any platforms that would cause an evaluation 467 # failure for `pkgsMusl.haskell.compiler.ghc922Binary`, as 468 # long as the evaluator runs on a platform that supports 469 # `pkgsMusl`. 470 platforms = builtins.attrNames ghcBinDists.${distSetName}; 471 teams = [ lib.teams.haskell ]; 472 broken = !(import ./common-have-ncg.nix { inherit lib stdenv version; }); 473 }; 474}