nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at python-updates 1146 lines 44 kB view raw
1{ 2 lib, 3 stdenv, 4 buildPackages, 5 buildHaskellPackages, 6 ghc, 7 jailbreak-cabal, 8 hscolour, 9 cpphs, 10 runCommandCC, 11 ghcWithHoogle, 12 ghcWithPackages, 13 haskellLib, 14 iserv-proxy, 15 nodejs, 16 writeShellScriptBin, 17}: 18 19let 20 isCross = stdenv.buildPlatform != stdenv.hostPlatform; 21 22 crossSupport = rec { 23 emulator = stdenv.hostPlatform.emulator buildPackages; 24 25 canProxyTH = 26 # iserv-proxy currently does not build on GHC 9.6 27 lib.versionAtLeast ghc.version "9.8" && stdenv.hostPlatform.emulatorAvailable buildPackages; 28 29 iservWrapper = 30 let 31 wrapperScript = 32 enableProfiling: 33 let 34 overrides = haskellLib.overrideCabal { 35 enableLibraryProfiling = enableProfiling; 36 enableExecutableProfiling = enableProfiling; 37 }; 38 buildProxy = lib.getExe' iserv-proxy.build "iserv-proxy"; 39 hostProxy = lib.getExe' (overrides iserv-proxy.host) "iserv-proxy-interpreter"; 40 in 41 buildPackages.writeShellScriptBin ("iserv-wrapper" + lib.optionalString enableProfiling "-prof") '' 42 set -euo pipefail 43 PORT=$((5000 + $RANDOM % 5000)) 44 (>&2 echo "---> Starting interpreter on port $PORT") 45 ${emulator} ${hostProxy} tmp $PORT & 46 RISERV_PID="$!" 47 trap "kill $RISERV_PID" EXIT # Needs cleanup when building without sandbox 48 ${buildProxy} $@ 127.0.0.1 "$PORT" 49 (>&2 echo "---> killing interpreter...") 50 ''; 51 52 # GHC will add `-prof` to the external interpreter when doing a profiled build. 53 # Since a single derivation can build with both profiling and non-profiling versions 54 # we need both versions made available 55 both = buildPackages.symlinkJoin { 56 name = "iserv-wrapper-both"; 57 paths = map wrapperScript [ 58 false 59 true 60 ]; 61 }; 62 63 in 64 "${both}/bin/iserv-wrapper"; 65 }; 66 67 # Pass the "wrong" C compiler rather than none at all so packages that just 68 # use the C preproccessor still work, see 69 # https://github.com/haskell/cabal/issues/6466 for details. 70 cc = 71 if stdenv.hasCC then 72 "$CC" 73 else if stdenv.hostPlatform.isGhcjs then 74 "${emscripten}/bin/emcc" 75 else 76 "$CC_FOR_BUILD"; 77 78 inherit (buildPackages) 79 fetchurl 80 removeReferencesTo 81 pkg-config 82 coreutils 83 glibcLocales 84 emscripten 85 ; 86 87in 88 89{ 90 pname, 91 dontStrip ? stdenv.hostPlatform.isGhcjs, 92 version, 93 revision ? null, 94 sha256 ? null, 95 src ? fetchurl { 96 url = "mirror://hackage/${pname}-${version}.tar.gz"; 97 inherit sha256; 98 }, 99 sourceRoot ? null, 100 setSourceRoot ? null, 101 # Extra environment variables to set during the build. 102 # See: `../../../doc/languages-frameworks/haskell.section.md` 103 env ? { }, 104 buildDepends ? [ ], 105 setupHaskellDepends ? [ ], 106 libraryHaskellDepends ? [ ], 107 executableHaskellDepends ? [ ], 108 buildTarget ? "", 109 buildTools ? [ ], 110 libraryToolDepends ? [ ], 111 executableToolDepends ? [ ], 112 testToolDepends ? [ ], 113 benchmarkToolDepends ? [ ], 114 configureFlags ? [ ], 115 buildFlags ? [ ], 116 haddockFlags ? [ ], 117 description ? null, 118 doCheck ? !isCross, 119 doBenchmark ? false, 120 doHoogle ? true, 121 doHaddockQuickjump ? doHoogle, 122 doInstallIntermediates ? false, 123 editedCabalFile ? null, 124 enableLibraryProfiling ? !stdenv.hostPlatform.isGhcjs, 125 enableExecutableProfiling ? false, 126 profilingDetail ? "exported-functions", 127 # TODO enable shared libs for cross-compiling 128 enableSharedExecutables ? false, 129 enableSharedLibraries ? 130 !stdenv.hostPlatform.isStatic 131 && (ghc.enableShared or false) 132 && !stdenv.hostPlatform.useAndroidPrebuilt, # TODO: figure out why /build leaks into RPATH 133 enableDeadCodeElimination ? (!stdenv.hostPlatform.isDarwin), # TODO: use -dead_strip for darwin 134 # Disabling this for JS prevents this crash: https://gitlab.haskell.org/ghc/ghc/-/issues/23235 135 enableStaticLibraries ? 136 !(stdenv.hostPlatform.isWindows || stdenv.hostPlatform.isWasm || stdenv.hostPlatform.isGhcjs), 137 enableHsc2hsViaAsm ? stdenv.hostPlatform.isWindows, 138 extraLibraries ? [ ], 139 librarySystemDepends ? [ ], 140 executableSystemDepends ? [ ], 141 # On macOS, statically linking against system frameworks is not supported; 142 # see https://developer.apple.com/library/content/qa/qa1118/_index.html 143 # They must be propagated to the environment of any executable linking with the library 144 libraryFrameworkDepends ? [ ], 145 executableFrameworkDepends ? [ ], 146 homepage ? "https://hackage.haskell.org/package/${pname}", 147 platforms ? lib.platforms.all, # GHC can cross-compile 148 badPlatforms ? lib.platforms.none, 149 hydraPlatforms ? null, 150 hyperlinkSource ? true, 151 isExecutable ? false, 152 isLibrary ? !isExecutable, 153 jailbreak ? false, 154 license ? null, 155 enableParallelBuilding ? true, 156 maintainers ? null, 157 teams ? null, 158 changelog ? null, 159 mainProgram ? null, 160 doCoverage ? false, 161 doHaddock ? !(ghc.isHaLVM or false) && (ghc.hasHaddock or true), 162 doHaddockInterfaces ? doHaddock && lib.versionAtLeast ghc.version "9.0.1", 163 passthru ? { }, 164 pkg-configDepends ? [ ], 165 libraryPkgconfigDepends ? [ ], 166 executablePkgconfigDepends ? [ ], 167 testPkgconfigDepends ? [ ], 168 benchmarkPkgconfigDepends ? [ ], 169 testDepends ? [ ], 170 testHaskellDepends ? [ ], 171 testSystemDepends ? [ ], 172 testFrameworkDepends ? [ ], 173 benchmarkDepends ? [ ], 174 benchmarkHaskellDepends ? [ ], 175 benchmarkSystemDepends ? [ ], 176 benchmarkFrameworkDepends ? [ ], 177 # testTarget is deprecated. Use testTargets instead. 178 testTarget ? "", 179 testTargets ? lib.strings.splitString " " testTarget, 180 testFlags ? [ ], 181 broken ? false, 182 preCompileBuildDriver ? null, 183 postCompileBuildDriver ? null, 184 preUnpack ? null, 185 postUnpack ? null, 186 patches ? null, 187 patchPhase ? null, 188 prePatch ? "", 189 postPatch ? "", 190 preConfigure ? null, 191 postConfigure ? null, 192 preBuild ? null, 193 postBuild ? null, 194 preHaddock ? null, 195 postHaddock ? null, 196 installPhase ? null, 197 preInstall ? null, 198 postInstall ? null, 199 checkPhase ? null, 200 preCheck ? null, 201 postCheck ? null, 202 preFixup ? null, 203 postFixup ? null, 204 shellHook ? "", 205 coreSetup ? false, # Use only core packages to build Setup.hs. 206 useCpphs ? false, 207 hardeningDisable ? null, 208 enableObjectDeterminism ? lib.versionAtLeast ghc.version "9.12", 209 enableSeparateBinOutput ? false, 210 enableSeparateDataOutput ? false, 211 enableSeparateDocOutput ? doHaddock, 212 enableSeparateIntermediatesOutput ? false, 213 # Don't fail at configure time if there are multiple versions of the 214 # same package in the (recursive) dependencies of the package being 215 # built. Will delay failures, if any, to compile time. 216 allowInconsistentDependencies ? false, 217 maxBuildCores ? 16, # more cores usually don't improve performance: https://ghc.haskell.org/trac/ghc/ticket/9221 218 # If set to true, this builds a pre-linked .o file for this Haskell library. 219 # This can make it slightly faster to load this library into GHCi, but takes 220 # extra disk space and compile time. 221 enableLibraryForGhci ? false, 222 # Set this to a previous build of this same package to reuse the intermediate 223 # build products from that prior build as a starting point for accelerating 224 # this build 225 previousIntermediates ? null, 226 # References to these store paths are forbidden in the produced output. 227 disallowedRequisites ? [ ], 228 # Whether to allow the produced output to refer to `ghc`. 229 # 230 # This is used by `haskell.lib.justStaticExecutables` to help prevent static 231 # Haskell binaries from having erroneous dependencies on GHC. 232 # 233 # See https://nixos.org/manual/nixpkgs/unstable/#haskell-packaging-helpers 234 # or its source doc/languages-frameworks/haskell.section.md 235 disallowGhcReference ? false, 236 # By default we convert the `.cabal` file to Unix line endings to work around 237 # Hackage converting them to DOS line endings when revised, see 238 # <https://github.com/haskell/hackage-server/issues/316>. 239 # Pass `true` to disable this behavior. 240 dontConvertCabalFileToUnix ? false, 241 # Cabal 3.8 which is shipped by default for GHC >= 9.3 always calls 242 # `pkg-config --libs --static` as part of the configure step. This requires 243 # Requires.private dependencies of pkg-config dependencies to be present in 244 # PKG_CONFIG_PATH which is normally not the case in nixpkgs (except in pkgsStatic). 245 # Since there is no patch or upstream patch yet, we replicate the automatic 246 # propagation of dependencies in pkgsStatic for allPkgConfigDepends for 247 # GHC >= 9.3 by default. This option allows overriding this behavior manually 248 # if mismatching Cabal and GHC versions are used. 249 # See also <https://github.com/haskell/cabal/issues/8455>. 250 __propagatePkgConfigDepends ? lib.versionAtLeast ghc.version "9.3", 251 # Propagation can easily lead to the argv limit being exceeded in linker or C 252 # compiler invocations. To work around this we can only propagate derivations 253 # that are known to provide pkg-config modules, as indicated by the presence 254 # of `meta.pkgConfigModules`. This option defaults to false for now, since 255 # this metadata is far from complete in nixpkgs. 256 __onlyPropagateKnownPkgConfigModules ? false, 257 258 enableExternalInterpreter ? isCross && crossSupport.canProxyTH, 259}@args: 260 261assert editedCabalFile != null -> revision != null; 262 263# We only use iserv-proxy for the external interpreter 264assert enableExternalInterpreter -> crossSupport.canProxyTH; 265 266# --enable-static does not work on windows. This is a bug in GHC. 267# --enable-static will pass -staticlib to ghc, which only works for mach-o and elf. 268assert stdenv.hostPlatform.isWindows -> enableStaticLibraries == false; 269assert stdenv.hostPlatform.isWasm -> enableStaticLibraries == false; 270 271let 272 273 inherit (lib) 274 optional 275 optionals 276 optionalString 277 versionAtLeast 278 concatStringsSep 279 enableFeature 280 optionalAttrs 281 ; 282 283 isHaLVM = ghc.isHaLVM or false; 284 285 # GHC used for building Setup.hs 286 # 287 # Same as our GHC, unless we're cross, in which case it is native GHC with the 288 # same version. 289 nativeGhc = buildHaskellPackages.ghc; 290 291 # the target dir for haddock documentation 292 docdir = docoutput: docoutput + "/share/doc/" + pname + "-" + version; 293 294 binDir = if enableSeparateBinOutput then "$bin/bin" else "$out/bin"; 295 296 newCabalFileUrl = "mirror://hackage/${pname}-${version}/revision/${revision}.cabal"; 297 newCabalFile = fetchurl { 298 url = newCabalFileUrl; 299 sha256 = editedCabalFile; 300 name = "${pname}-${version}-r${revision}.cabal"; 301 }; 302 303 defaultSetupHs = builtins.toFile "Setup.hs" '' 304 import Distribution.Simple 305 main = defaultMain 306 ''; 307 308 # This awk expression transforms a package conf file like 309 # 310 # author: John Doe <john-doe@example.com> 311 # description: 312 # The purpose of this library is to do 313 # foo and bar among other things 314 # 315 # into a more easily processeable form: 316 # 317 # author: John Doe <john-doe@example.com> 318 # description: The purpose of this library is to do foo and bar among other things 319 unprettyConf = builtins.toFile "unpretty-cabal-conf.awk" '' 320 /^[^ ]+:/ { 321 # When the line starts with a new field, terminate the previous one with a newline 322 if (started == 1) print "" 323 # to strip leading spaces 324 $1=$1 325 printf "%s", $0 326 started=1 327 } 328 329 /^ +/ { 330 # to strip leading spaces 331 $1=$1 332 printf " %s", $0 333 } 334 335 # Terminate the final field with a newline 336 END { print "" } 337 ''; 338 339 crossCabalFlags = [ 340 "--with-ghc=${ghcCommand}" 341 "--with-ghc-pkg=${ghc.targetPrefix}ghc-pkg" 342 "--with-gcc=${cc}" 343 ] 344 ++ optionals stdenv.hasCC [ 345 "--with-ld=${stdenv.cc.bintools.targetPrefix}ld" 346 "--with-ar=${stdenv.cc.bintools.targetPrefix}ar" 347 # use the one that comes with the cross compiler. 348 "--with-hsc2hs=${ghc.targetPrefix}hsc2hs" 349 "--with-strip=${stdenv.cc.bintools.targetPrefix}strip" 350 ] 351 ++ optionals (!isHaLVM) [ 352 "--hsc2hs-option=--cross-compile" 353 (optionalString enableHsc2hsViaAsm "--hsc2hs-option=--via-asm") 354 ] 355 ++ optional (allPkgconfigDepends != [ ]) "--with-pkg-config=${pkg-config.targetPrefix}pkg-config" 356 357 ++ optionals enableExternalInterpreter ( 358 map (opt: "--ghc-option=${opt}") [ 359 "-fexternal-interpreter" 360 "-pgmi" 361 crossSupport.iservWrapper 362 ] 363 ); 364 365 makeGhcOptions = opts: lib.concatStringsSep " " (map (opt: "--ghc-option=${opt}") opts); 366 367 defaultConfigureFlags = [ 368 "--verbose" 369 "--prefix=$out" 370 # Note: This must be kept in sync manually with mkGhcLibdir 371 ("--libdir=\\$prefix/lib/\\$compiler" + lib.optionalString (ghc ? hadrian) "/lib") 372 "--libsubdir=\\$abi/\\$libname" 373 (optionalString enableSeparateDataOutput "--datadir=$data/share/${ghcNameWithPrefix}") 374 (optionalString enableSeparateDocOutput "--docdir=${docdir "$doc"}") 375 ] 376 ++ optionals stdenv.hasCC [ 377 "--with-gcc=$CC" # Clang won't work without that extra information. 378 ] 379 ++ [ 380 "--package-db=$packageConfDir" 381 (optionalString ( 382 enableSharedExecutables && stdenv.hostPlatform.isLinux 383 ) "--ghc-option=-optl=-Wl,-rpath=$out/${ghcLibdir}/${pname}-${version}") 384 (optionalString ( 385 enableSharedExecutables && stdenv.hostPlatform.isDarwin 386 ) "--ghc-option=-optl=-Wl,-headerpad_max_install_names") 387 (optionalString enableParallelBuilding (makeGhcOptions [ 388 "-j$NIX_BUILD_CORES" 389 "+RTS" 390 "-A64M" 391 "-RTS" 392 ])) 393 (optionalString useCpphs ( 394 "--with-cpphs=${cpphs}/bin/cpphs " 395 + (makeGhcOptions [ 396 "-cpp" 397 "-pgmP${cpphs}/bin/cpphs" 398 "-optP--cpp" 399 ]) 400 )) 401 (enableFeature enableLibraryProfiling "library-profiling") 402 (optionalString ( 403 enableExecutableProfiling || enableLibraryProfiling 404 ) "--profiling-detail=${profilingDetail}") 405 (enableFeature enableExecutableProfiling "profiling") 406 (enableFeature enableSharedLibraries "shared") 407 (enableFeature doCoverage "coverage") 408 (enableFeature enableStaticLibraries "static") 409 (enableFeature enableSharedExecutables "executable-dynamic") 410 (enableFeature doCheck "tests") 411 (enableFeature doBenchmark "benchmarks") 412 "--enable-library-vanilla" # TODO: Should this be configurable? 413 (enableFeature enableLibraryForGhci "library-for-ghci") 414 (enableFeature enableDeadCodeElimination "split-sections") 415 (enableFeature (!dontStrip) "library-stripping") 416 (enableFeature (!dontStrip) "executable-stripping") 417 ] 418 ++ optionals enableObjectDeterminism [ 419 "--ghc-option=-fobject-determinism" 420 ] 421 ++ optionals isCross ( 422 [ 423 "--configure-option=--host=${stdenv.hostPlatform.config}" 424 ] 425 ++ crossCabalFlags 426 ) 427 ++ optionals enableSeparateBinOutput [ 428 "--bindir=${binDir}" 429 ] 430 ++ optionals (doHaddockInterfaces && isLibrary) [ 431 "--ghc-option=-haddock" 432 ]; 433 434 postPhases = optional doInstallIntermediates "installIntermediatesPhase"; 435 436 setupCompileFlags = [ 437 (optionalString (!coreSetup) "-package-db=$setupPackageConfDir") 438 "-threaded" # https://github.com/haskell/cabal/issues/2398 439 ]; 440 441 isHaskellPkg = x: x ? isHaskellLibrary; 442 443 # Work around a Cabal bug requiring pkg-config --static --libs to work even 444 # when linking dynamically, affecting Cabal 3.8 and 3.9. 445 # https://github.com/haskell/cabal/issues/8455 446 # 447 # For this, we treat the runtime system/pkg-config dependencies of a Haskell 448 # derivation as if they were propagated from their dependencies which allows 449 # pkg-config --static to work in most cases. 450 allPkgconfigDepends = 451 let 452 # If __onlyPropagateKnownPkgConfigModules is set, packages without 453 # meta.pkgConfigModules will be filtered out, otherwise all packages in 454 # buildInputs and propagatePlainBuildInputs are propagated. 455 propagateValue = 456 drv: lib.isDerivation drv && (__onlyPropagateKnownPkgConfigModules -> drv ? meta.pkgConfigModules); 457 458 # Take list of derivations and return list of the transitive dependency 459 # closure, only taking into account buildInputs. Loosely based on 460 # closePropagationFast. 461 propagatePlainBuildInputs = 462 drvs: 463 map (i: i.val) ( 464 builtins.genericClosure { 465 startSet = map (drv: { 466 key = drv.outPath; 467 val = drv; 468 }) (builtins.filter propagateValue drvs); 469 operator = 470 { val, ... }: 471 builtins.concatMap ( 472 drv: 473 if propagateValue drv then 474 [ 475 { 476 key = drv.outPath; 477 val = drv; 478 } 479 ] 480 else 481 [ ] 482 ) (val.buildInputs or [ ] ++ val.propagatedBuildInputs or [ ]); 483 } 484 ); 485 in 486 487 if __propagatePkgConfigDepends then 488 propagatePlainBuildInputs allPkgconfigDepends' 489 else 490 allPkgconfigDepends'; 491 allPkgconfigDepends' = 492 pkg-configDepends 493 ++ libraryPkgconfigDepends 494 ++ executablePkgconfigDepends 495 ++ optionals doCheck testPkgconfigDepends 496 ++ optionals doBenchmark benchmarkPkgconfigDepends; 497 498 depsBuildBuild = [ 499 nativeGhc 500 ] 501 # CC_FOR_BUILD may be necessary if we have no C preprocessor for the host 502 # platform. See crossCabalFlags above for more details. 503 ++ lib.optionals (!stdenv.hasCC) [ buildPackages.stdenv.cc ]; 504 collectedToolDepends = 505 buildTools 506 ++ libraryToolDepends 507 ++ executableToolDepends 508 ++ optionals doCheck testToolDepends 509 ++ optionals doBenchmark benchmarkToolDepends; 510 nativeBuildInputs = [ 511 ghc 512 removeReferencesTo 513 ] 514 ++ optional (allPkgconfigDepends != [ ]) ( 515 assert pkg-config != null; 516 pkg-config 517 ) 518 ++ setupHaskellDepends 519 ++ collectedToolDepends 520 ++ optional stdenv.hostPlatform.isGhcjs nodejs; 521 propagatedBuildInputs = 522 buildDepends ++ libraryHaskellDepends ++ executableHaskellDepends ++ libraryFrameworkDepends; 523 otherBuildInputsHaskell = 524 optionals doCheck (testDepends ++ testHaskellDepends) 525 ++ optionals doBenchmark (benchmarkDepends ++ benchmarkHaskellDepends); 526 otherBuildInputsSystem = 527 extraLibraries 528 ++ librarySystemDepends 529 ++ executableSystemDepends 530 ++ executableFrameworkDepends 531 ++ allPkgconfigDepends 532 ++ optionals doCheck (testSystemDepends ++ testFrameworkDepends) 533 ++ optionals doBenchmark (benchmarkSystemDepends ++ benchmarkFrameworkDepends); 534 # TODO next rebuild just define as `otherBuildInputsHaskell ++ otherBuildInputsSystem` 535 otherBuildInputs = 536 extraLibraries 537 ++ librarySystemDepends 538 ++ executableSystemDepends 539 ++ executableFrameworkDepends 540 ++ allPkgconfigDepends 541 ++ optionals doCheck ( 542 testDepends ++ testHaskellDepends ++ testSystemDepends ++ testFrameworkDepends 543 ) 544 ++ optionals doBenchmark ( 545 benchmarkDepends ++ benchmarkHaskellDepends ++ benchmarkSystemDepends ++ benchmarkFrameworkDepends 546 ); 547 548 setupCommand = "./Setup"; 549 550 ghcCommand' = "ghc"; 551 ghcCommand = "${ghc.targetPrefix}${ghcCommand'}"; 552 553 ghcNameWithPrefix = "${ghc.targetPrefix}${ghc.haskellCompilerName}"; 554 mkGhcLibdir = 555 ghc: 556 "lib/${ghc.targetPrefix}${ghc.haskellCompilerName}" + lib.optionalString (ghc ? hadrian) "/lib"; 557 ghcLibdir = mkGhcLibdir ghc; 558 559 nativeGhcCommand = "${nativeGhc.targetPrefix}ghc"; 560 561 buildPkgDb = thisGhc: packageConfDir: '' 562 # If this dependency has a package database, then copy the contents of it, 563 # unless it is one of our GHCs. These can appear in our dependencies when 564 # we are doing native builds, and they have package databases in them, but 565 # we do not want to copy them over. 566 # 567 # We don't need to, since those packages will be provided by the GHC when 568 # we compile with it, and doing so can result in having multiple copies of 569 # e.g. Cabal in the database with the same name and version, which is 570 # ambiguous. 571 if [ -d "$p/${mkGhcLibdir thisGhc}/package.conf.d" ] && [ "$p" != "${ghc}" ] && [ "$p" != "${nativeGhc}" ]; then 572 cp -f "$p/${mkGhcLibdir thisGhc}/package.conf.d/"*.conf ${packageConfDir}/ 573 continue 574 fi 575 ''; 576 577 intermediatesDir = "share/haskell/${ghc.version}/${pname}-${version}/dist"; 578 579 jsexe = rec { 580 shouldAdd = stdenv.hostPlatform.isGhcjs && isExecutable; 581 shouldCopy = shouldAdd && !doInstallIntermediates; 582 shouldSymlink = shouldAdd && doInstallIntermediates; 583 }; 584 585 # This is a script suitable for --test-wrapper of Setup.hs' test command 586 # (https://cabal.readthedocs.io/en/3.12/setup-commands.html#cmdoption-runhaskell-Setup.hs-test-test-wrapper). 587 # We use it to set some environment variables that the test suite may need, 588 # e.g. GHC_PACKAGE_PATH to invoke GHC(i) at runtime with build dependencies 589 # available. See the comment accompanying checkPhase below on how to customize 590 # this behavior. We need to use a wrapper script since Cabal forbids setting 591 # certain environment variables since they can alter GHC's behavior (e.g. 592 # GHC_PACKAGE_PATH) and cause failures. While building, Cabal will set 593 # GHC_ENVIRONMENT to make the packages picked at configure time available to 594 # GHC, but unfortunately not at test time. The test wrapper script will be 595 # executed after such environment checks, so we can take some liberties which 596 # is unproblematic since we know our synthetic package db matches what Cabal 597 # will see at configure time exactly. See also 598 # <https://github.com/haskell/cabal/issues/7792>. 599 testWrapperScript = buildPackages.writeShellScript "haskell-generic-builder-test-wrapper.sh" '' 600 set -eu 601 602 # We expect this to be either empty or set by checkPhase 603 if [[ -n "''${NIX_GHC_PACKAGE_PATH_FOR_TEST}" ]]; then 604 export GHC_PACKAGE_PATH="''${NIX_GHC_PACKAGE_PATH_FOR_TEST}" 605 fi 606 607 exec "$@" 608 ''; 609 610 testTargetsString = 611 lib.warnIf (testTarget != "") 612 "haskellPackages.mkDerivation: testTarget is deprecated. Use testTargets instead" 613 (lib.concatStringsSep " " testTargets); 614 615 env' = { 616 LANG = "en_US.UTF-8"; # GHC needs the locale configured during the Haddock phase. 617 } 618 // env 619 # Implicit pointer to integer conversions are errors by default since clang 15. 620 # Works around https://gitlab.haskell.org/ghc/ghc/-/issues/23456. krank:ignore-line 621 # A fix was included in GHC 9.10.* and backported to 9.6.5 and 9.8.2 (but we no longer 622 # ship 9.8.1). 623 // optionalAttrs (lib.versionOlder ghc.version "9.6.5" && stdenv.hasCC && stdenv.cc.isClang) { 624 NIX_CFLAGS_COMPILE = 625 "-Wno-error=int-conversion" 626 + lib.optionalString (env ? NIX_CFLAGS_COMPILE) (" " + env.NIX_CFLAGS_COMPILE); 627 }; 628 629in 630lib.fix ( 631 drv: 632 633 stdenv.mkDerivation ( 634 { 635 inherit pname version; 636 637 outputs = [ 638 "out" 639 ] 640 ++ (optional enableSeparateDataOutput "data") 641 ++ (optional enableSeparateDocOutput "doc") 642 ++ (optional enableSeparateBinOutput "bin") 643 ++ (optional enableSeparateIntermediatesOutput "intermediates"); 644 645 setOutputFlags = false; 646 647 pos = builtins.unsafeGetAttrPos "pname" args; 648 649 prePhases = [ "setupCompilerEnvironmentPhase" ]; 650 preConfigurePhases = [ "compileBuildDriverPhase" ]; 651 preInstallPhases = [ "haddockPhase" ]; 652 653 inherit src; 654 655 inherit depsBuildBuild nativeBuildInputs; 656 buildInputs = 657 otherBuildInputs 658 ++ optionals (!isLibrary) propagatedBuildInputs 659 # For patchShebangsAuto in fixupPhase 660 ++ optionals stdenv.hostPlatform.isGhcjs [ nodejs ]; 661 propagatedBuildInputs = optionals isLibrary propagatedBuildInputs; 662 663 env = 664 optionalAttrs (stdenv.buildPlatform.libc == "glibc") { 665 LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive"; 666 } 667 // env'; 668 669 prePatch = 670 optionalString (editedCabalFile != null) '' 671 echo "Replace Cabal file with edited version from ${newCabalFileUrl}." 672 cp ${newCabalFile} ${pname}.cabal 673 '' 674 + prePatch 675 + "\n" 676 # cabal2nix-generated expressions run hpack not until prePatch to create 677 # the .cabal file (if necessary) 678 + lib.optionalString (!dontConvertCabalFileToUnix) '' 679 sed -i -e 's/\r$//' *.cabal 680 ''; 681 682 postPatch = 683 optionalString jailbreak '' 684 echo "Run jailbreak-cabal to lift version restrictions on build inputs." 685 ${jailbreak-cabal}/bin/jailbreak-cabal *.cabal 686 '' 687 + postPatch; 688 689 setupCompilerEnvironmentPhase = '' 690 NIX_BUILD_CORES=$(( NIX_BUILD_CORES < ${toString maxBuildCores} ? NIX_BUILD_CORES : ${toString maxBuildCores} )) 691 runHook preSetupCompilerEnvironment 692 693 echo "Build with ${ghc}." 694 ${optionalString (isLibrary && hyperlinkSource) "export PATH=${hscolour}/bin:$PATH"} 695 696 builddir="$(mktemp -d)" 697 setupPackageConfDir="$builddir/setup-package.conf.d" 698 mkdir -p $setupPackageConfDir 699 packageConfDir="$builddir/package.conf.d" 700 mkdir -p $packageConfDir 701 702 setupCompileFlags="${concatStringsSep " " setupCompileFlags}" 703 configureFlags="${concatStringsSep " " defaultConfigureFlags} $configureFlags" 704 '' 705 # We build the Setup.hs on the *build* machine, and as such should only add 706 # dependencies for the build machine. 707 # 708 # pkgs* arrays defined in stdenv/setup.hs 709 + '' 710 for p in "''${pkgsBuildBuild[@]}" "''${pkgsBuildHost[@]}" "''${pkgsBuildTarget[@]}"; do 711 ${buildPkgDb nativeGhc "$setupPackageConfDir"} 712 done 713 ${nativeGhcCommand}-pkg --package-db="$setupPackageConfDir" recache 714 '' 715 # For normal components 716 + '' 717 for p in "''${pkgsHostHost[@]}" "''${pkgsHostTarget[@]}"; do 718 ${buildPkgDb ghc "$packageConfDir"} 719 if [ -d "$p/include" ]; then 720 appendToVar configureFlags "--extra-include-dirs=$p/include" 721 fi 722 if [ -d "$p/lib" ]; then 723 appendToVar configureFlags "--extra-lib-dirs=$p/lib" 724 fi 725 if [[ -d "$p/Library/Frameworks" ]]; then 726 appendToVar configureFlags "--extra-framework-dirs=$p/Library/Frameworks" 727 fi 728 '' 729 + '' 730 done 731 '' 732 + (optionalString stdenv.hostPlatform.isGhcjs '' 733 export EM_CACHE="$(realpath "$(mktemp -d emcache.XXXXXXXXXX)")" 734 cp -Lr ${emscripten}/share/emscripten/cache/* "$EM_CACHE/" 735 chmod u+rwX -R "$EM_CACHE" 736 '') 737 # only use the links hack if we're actually building dylibs. otherwise, the 738 # "dynamic-library-dirs" point to nonexistent paths, and the ln command becomes 739 # "ln -s $out/lib/links", which tries to recreate the links dir and fails 740 # 741 # Note: We need to disable this work-around when using intermediate build 742 # products from a prior build because otherwise Nix will change permissions on 743 # the `$out/lib/links` directory to read-only when the build is done after the 744 # dist directory has already been exported, which triggers an unnecessary 745 # rebuild of modules included in the exported dist directory. 746 + (optionalString 747 ( 748 stdenv.hostPlatform.isDarwin 749 && (enableSharedLibraries || enableSharedExecutables) 750 && !enableSeparateIntermediatesOutput 751 ) 752 '' 753 # Work around a limit in the macOS Sierra linker on the number of paths 754 # referenced by any one dynamic library: 755 # 756 # Create a local directory with symlinks of the *.dylib (macOS shared 757 # libraries) from all the dependencies. 758 local dynamicLinksDir="$out/lib/links" 759 mkdir -p $dynamicLinksDir 760 761 # Unprettify all package conf files before reading/writing them 762 for d in "$packageConfDir/"*; do 763 # gawk -i inplace seems to strip the last newline 764 gawk -f ${unprettyConf} "$d" > tmp 765 mv tmp "$d" 766 done 767 768 for d in $(grep '^dynamic-library-dirs:' "$packageConfDir"/* | cut -d' ' -f2- | tr ' ' '\n' | sort -u); do 769 for lib in "$d/"*.{dylib,so}; do 770 # Allow overwriting because C libs can be pulled in multiple times. 771 ln -sf "$lib" "$dynamicLinksDir" 772 done 773 done 774 # Edit the local package DB to reference the links directory. 775 for f in "$packageConfDir/"*.conf; do 776 sed -i "s,dynamic-library-dirs: .*,dynamic-library-dirs: $dynamicLinksDir," "$f" 777 done 778 '' 779 ) 780 + '' 781 ${ghcCommand}-pkg --package-db="$packageConfDir" recache 782 783 runHook postSetupCompilerEnvironment 784 ''; 785 786 compileBuildDriverPhase = '' 787 runHook preCompileBuildDriver 788 789 for i in Setup.hs Setup.lhs ${defaultSetupHs}; do 790 test -f $i && break 791 done 792 793 echo setupCompileFlags: $setupCompileFlags 794 ${nativeGhcCommand} $setupCompileFlags --make -o Setup -odir $builddir -hidir $builddir $i 795 796 runHook postCompileBuildDriver 797 ''; 798 799 # Cabal takes flags like `--configure-option=--host=...` instead 800 configurePlatforms = [ ]; 801 inherit configureFlags buildFlags; 802 803 # Note: the options here must be always added, regardless of whether the 804 # package specifies `hardeningDisable`. 805 hardeningDisable = 806 lib.optionals (args ? hardeningDisable) hardeningDisable 807 ++ lib.optional (ghc.isHaLVM or false) "all"; 808 809 configurePhase = '' 810 runHook preConfigure 811 812 echo configureFlags: $configureFlags 813 ${setupCommand} configure $configureFlags 2>&1 | ${coreutils}/bin/tee "$NIX_BUILD_TOP/cabal-configure.log" 814 ${lib.optionalString (!allowInconsistentDependencies) '' 815 if grep -E -q -z 'Warning:.*depends on multiple versions' "$NIX_BUILD_TOP/cabal-configure.log"; then 816 echo >&2 "*** abort because of serious configure-time warning from Cabal" 817 exit 1 818 fi 819 ''} 820 821 runHook postConfigure 822 ''; 823 824 buildPhase = '' 825 runHook preBuild 826 '' 827 + lib.optionalString (previousIntermediates != null) '' 828 mkdir -p dist; 829 rm -r dist/build 830 cp -r ${previousIntermediates}/${intermediatesDir}/build dist/build 831 find dist/build -exec chmod u+w {} + 832 find dist/build -exec touch -d '1970-01-01T00:00:00Z' {} + 833 '' 834 + '' 835 ${setupCommand} build ${buildTarget} $buildFlags 836 runHook postBuild 837 ''; 838 839 inherit doCheck; 840 841 # Run test suite(s) and pass `checkFlags` as well as `checkFlagsArray`. 842 # `testFlags` are added to `checkFlagsArray` each prefixed with 843 # `--test-option`, so Cabal passes it to the underlying test suite binary. 844 # 845 # We also take care of setting GHC_PACKAGE_PATH during test suite execution, 846 # so it can run GHC(i) with build dependencies available: 847 # - If NIX_GHC_PACKAGE_PATH_FOR_TEST is set, it become the value of GHC_PACKAGE_PATH 848 # while the test suite is executed. 849 # - If it is empty, it'll be unset during test suite execution. 850 # - Otherwise GHC_PACKAGE_PATH will have the package db used for configuring 851 # plus GHC's core packages. 852 checkPhase = '' 853 runHook preCheck 854 checkFlagsArray+=( 855 "--show-details=streaming" 856 "--test-wrapper=${testWrapperScript}" 857 ${lib.escapeShellArgs (map (opt: "--test-option=${opt}") testFlags)} 858 ) 859 export NIX_GHC_PACKAGE_PATH_FOR_TEST="''${NIX_GHC_PACKAGE_PATH_FOR_TEST:-$packageConfDir:}" 860 ${setupCommand} test ${testTargetsString} $checkFlags ''${checkFlagsArray:+"''${checkFlagsArray[@]}"} 861 runHook postCheck 862 ''; 863 864 haddockPhase = '' 865 runHook preHaddock 866 ${optionalString (doHaddock && isLibrary) '' 867 ${setupCommand} haddock --html \ 868 ${optionalString doHoogle "--hoogle"} \ 869 ${optionalString doHaddockQuickjump "--quickjump"} \ 870 ${optionalString (isLibrary && hyperlinkSource) "--hyperlink-source"} \ 871 ${optionalString enableParallelBuilding "--haddock-option=-j$NIX_BUILD_CORES"} \ 872 --haddock-option=--no-tmp-comp-dir \ 873 ${lib.concatStringsSep " " haddockFlags} 874 ''} 875 runHook postHaddock 876 ''; 877 878 installPhase = '' 879 runHook preInstall 880 881 ${ 882 if !isLibrary && buildTarget == "" then 883 "${setupCommand} install" 884 # ^^ if the project is not a library, and no build target is specified, we can just use "install". 885 else if !isLibrary then 886 "${setupCommand} copy ${buildTarget}" 887 # ^^ if the project is not a library, and we have a build target, then use "copy" to install 888 # just the target specified; "install" will error here, since not all targets have been built. 889 else 890 '' 891 ${setupCommand} copy ${buildTarget} 892 local packageConfDir="$out/${ghcLibdir}/package.conf.d" 893 local packageConfFile="$packageConfDir/${pname}-${version}.conf" 894 mkdir -p "$packageConfDir" 895 ${setupCommand} register --gen-pkg-config=$packageConfFile 896 if [ -d "$packageConfFile" ]; then 897 mv "$packageConfFile/"* "$packageConfDir" 898 rmdir "$packageConfFile" 899 fi 900 for packageConfFile in "$packageConfDir/"*; do 901 local pkgId=$(gawk -f ${unprettyConf} "$packageConfFile" \ 902 | grep '^id:' | cut -d' ' -f2) 903 mv "$packageConfFile" "$packageConfDir/$pkgId.conf" 904 done 905 906 # delete confdir if there are no libraries 907 find $packageConfDir -maxdepth 0 -empty -delete; 908 '' 909 } 910 911 912 ${optionalString doCoverage "mkdir -p $out/share && cp -r dist/hpc $out/share"} 913 914 ${optionalString jsexe.shouldCopy '' 915 for jsexeDir in dist/build/*/*.jsexe; do 916 bn=$(basename $jsexeDir) 917 exe="''${bn%.jsexe}" 918 cp -r dist/build/$exe/$exe.jsexe ${binDir} 919 done 920 ''} 921 922 ${optionalString enableSeparateDocOutput '' 923 for x in ${docdir "$doc"}"/html/src/"*.html; do 924 remove-references-to -t $out $x 925 done 926 mkdir -p $doc 927 ''} 928 ${optionalString enableSeparateDataOutput "mkdir -p $data"} 929 930 runHook postInstall 931 ''; 932 933 ${if doInstallIntermediates then "installIntermediatesPhase" else null} = '' 934 runHook preInstallIntermediates 935 intermediatesOutput=${if enableSeparateIntermediatesOutput then "$intermediates" else "$out"} 936 installIntermediatesDir="$intermediatesOutput/${intermediatesDir}" 937 mkdir -p "$installIntermediatesDir" 938 cp -r dist/build "$installIntermediatesDir" 939 runHook postInstallIntermediates 940 941 ${optionalString jsexe.shouldSymlink '' 942 for jsexeDir in $installIntermediatesDir/build/*/*.jsexe; do 943 bn=$(basename $jsexeDir) 944 exe="''${bn%.jsexe}" 945 (cd ${binDir} && ln -s $installIntermediatesDir/build/$exe/$exe.jsexe) 946 done 947 ''} 948 ''; 949 950 passthru = passthru // rec { 951 952 inherit pname version disallowGhcReference; 953 954 compiler = ghc; 955 956 # All this information is intended just for `shellFor`. It should be 957 # considered unstable and indeed we knew how to keep it private we would. 958 getCabalDeps = { 959 inherit 960 buildDepends 961 buildTools 962 executableFrameworkDepends 963 executableHaskellDepends 964 executablePkgconfigDepends 965 executableSystemDepends 966 executableToolDepends 967 extraLibraries 968 libraryFrameworkDepends 969 libraryHaskellDepends 970 libraryPkgconfigDepends 971 librarySystemDepends 972 libraryToolDepends 973 pkg-configDepends 974 setupHaskellDepends 975 ; 976 } 977 // lib.optionalAttrs doCheck { 978 inherit 979 testDepends 980 testFrameworkDepends 981 testHaskellDepends 982 testPkgconfigDepends 983 testSystemDepends 984 testToolDepends 985 ; 986 } 987 // lib.optionalAttrs doBenchmark { 988 inherit 989 benchmarkDepends 990 benchmarkFrameworkDepends 991 benchmarkHaskellDepends 992 benchmarkPkgconfigDepends 993 benchmarkSystemDepends 994 benchmarkToolDepends 995 ; 996 }; 997 998 # Attributes for the old definition of `shellFor`. Should be removed but 999 # this predates the warning at the top of `getCabalDeps`. 1000 getBuildInputs = rec { 1001 inherit propagatedBuildInputs otherBuildInputs allPkgconfigDepends; 1002 haskellBuildInputs = isHaskellPartition.right; 1003 systemBuildInputs = isHaskellPartition.wrong; 1004 isHaskellPartition = lib.partition isHaskellPkg ( 1005 propagatedBuildInputs ++ otherBuildInputs ++ depsBuildBuild ++ nativeBuildInputs 1006 ); 1007 }; 1008 1009 isHaskellLibrary = isLibrary; 1010 1011 # TODO: ask why the split outputs are configurable at all? 1012 # TODO: include tests for split if possible 1013 # Given the haskell package, returns 1014 # the directory containing the haddock documentation. 1015 # `null' if no haddock documentation was built. 1016 # TODO: fetch the self from the fixpoint instead 1017 haddockDir = self: if doHaddock then "${docdir self.doc}/html" else null; 1018 1019 # Creates a derivation containing all of the necessary dependencies for building the 1020 # parent derivation. The attribute set that it takes as input can be viewed as: 1021 # 1022 # { withHoogle } 1023 # 1024 # The derivation that it builds contains no outpaths because it is meant for use 1025 # as an environment 1026 # 1027 # # Example use 1028 # # Creates a shell with all of the dependencies required to build the "hello" package, 1029 # # and with python: 1030 # 1031 # > nix-shell -E 'with (import <nixpkgs> {}); \ 1032 # > haskellPackages.hello.envFunc { buildInputs = [ python ]; }' 1033 envFunc = 1034 { 1035 withHoogle ? false, 1036 }: 1037 let 1038 name = "ghc-shell-for-${drv.name}"; 1039 1040 withPackages = if withHoogle then ghcWithHoogle else ghcWithPackages; 1041 1042 # We use the `ghcWithPackages` function from `buildHaskellPackages` if we 1043 # want a shell for the sake of cross compiling a package. In the native case 1044 # we don't use this at all, and instead put the setupDepends in the main 1045 # `ghcWithPackages`. This way we don't have two wrapper scripts called `ghc` 1046 # shadowing each other on the PATH. 1047 ghcEnvForBuild = 1048 assert isCross; 1049 buildHaskellPackages.ghcWithPackages (_: setupHaskellDepends); 1050 1051 ghcEnv = withPackages ( 1052 _: otherBuildInputsHaskell ++ propagatedBuildInputs ++ lib.optionals (!isCross) setupHaskellDepends 1053 ); 1054 1055 ghcCommandCaps = lib.toUpper ghcCommand'; 1056 in 1057 runCommandCC name { 1058 inherit shellHook; 1059 1060 depsBuildBuild = lib.optional isCross ghcEnvForBuild; 1061 nativeBuildInputs = [ 1062 ghcEnv 1063 ] 1064 ++ optional (allPkgconfigDepends != [ ]) pkg-config 1065 ++ collectedToolDepends; 1066 buildInputs = otherBuildInputsSystem; 1067 1068 env = { 1069 "NIX_${ghcCommandCaps}" = "${ghcEnv}/bin/${ghcCommand}"; 1070 "NIX_${ghcCommandCaps}PKG" = "${ghcEnv}/bin/${ghcCommand}-pkg"; 1071 # TODO: is this still valid? 1072 "NIX_${ghcCommandCaps}_DOCDIR" = "${ghcEnv}/share/doc/ghc/html"; 1073 "NIX_${ghcCommandCaps}_LIBDIR" = 1074 if ghc.isHaLVM or false then "${ghcEnv}/lib/HaLVM-${ghc.version}" else "${ghcEnv}/${ghcLibdir}"; 1075 } 1076 // optionalAttrs (stdenv.buildPlatform.libc == "glibc") { 1077 # TODO: Why is this written in terms of `buildPackages`, unlike 1078 # the outer `env`? 1079 # 1080 # According to @sternenseemann [1]: 1081 # 1082 # > The condition is based on `buildPlatform`, so it needs to 1083 # > match. `LOCALE_ARCHIVE` is set to accompany `LANG` which 1084 # > concerns things we execute on the build platform like 1085 # > `haddock`. 1086 # > 1087 # > Arguably the outer non `buildPackages` one is incorrect and 1088 # > probably works by accident in most cases since the locale 1089 # > archive is not platform specific (the trouble is that it 1090 # > may sometimes be impossible to cross-compile). At least 1091 # > that would be my assumption. 1092 # 1093 # [1]: https://github.com/NixOS/nixpkgs/pull/424368#discussion_r2202683378 1094 LOCALE_ARCHIVE = "${buildPackages.glibcLocales}/lib/locale/locale-archive"; 1095 } 1096 // env'; 1097 } "echo $nativeBuildInputs $buildInputs > $out"; 1098 1099 env = envFunc { }; 1100 1101 }; 1102 1103 meta = { 1104 inherit homepage platforms; 1105 } 1106 // optionalAttrs (args ? broken) { inherit broken; } 1107 // optionalAttrs (args ? description) { inherit description; } 1108 // optionalAttrs (args ? license) { inherit license; } 1109 // optionalAttrs (args ? maintainers) { inherit maintainers; } 1110 // optionalAttrs (args ? teams) { inherit teams; } 1111 // optionalAttrs (args ? hydraPlatforms) { inherit hydraPlatforms; } 1112 // optionalAttrs (args ? badPlatforms) { inherit badPlatforms; } 1113 // optionalAttrs (args ? changelog) { inherit changelog; } 1114 // optionalAttrs (args ? mainProgram) { inherit mainProgram; }; 1115 1116 } 1117 // optionalAttrs (args ? sourceRoot) { inherit sourceRoot; } 1118 // optionalAttrs (args ? setSourceRoot) { inherit setSourceRoot; } 1119 // optionalAttrs (args ? preCompileBuildDriver) { inherit preCompileBuildDriver; } 1120 // optionalAttrs (args ? postCompileBuildDriver) { inherit postCompileBuildDriver; } 1121 // optionalAttrs (args ? preUnpack) { inherit preUnpack; } 1122 // optionalAttrs (args ? postUnpack) { inherit postUnpack; } 1123 // optionalAttrs (args ? patches) { inherit patches; } 1124 // optionalAttrs (args ? patchPhase) { inherit patchPhase; } 1125 // optionalAttrs (args ? preConfigure) { inherit preConfigure; } 1126 // optionalAttrs (args ? postConfigure) { inherit postConfigure; } 1127 // optionalAttrs (args ? preBuild) { inherit preBuild; } 1128 // optionalAttrs (args ? postBuild) { inherit postBuild; } 1129 // optionalAttrs (args ? doBenchmark) { inherit doBenchmark; } 1130 // optionalAttrs (args ? checkPhase) { inherit checkPhase; } 1131 // optionalAttrs (args ? preCheck) { inherit preCheck; } 1132 // optionalAttrs (args ? postCheck) { inherit postCheck; } 1133 // optionalAttrs (args ? preHaddock) { inherit preHaddock; } 1134 // optionalAttrs (args ? postHaddock) { inherit postHaddock; } 1135 // optionalAttrs (args ? preInstall) { inherit preInstall; } 1136 // optionalAttrs (args ? installPhase) { inherit installPhase; } 1137 // optionalAttrs (args ? postInstall) { inherit postInstall; } 1138 // optionalAttrs (args ? preFixup) { inherit preFixup; } 1139 // optionalAttrs (args ? postFixup) { inherit postFixup; } 1140 // optionalAttrs (args ? dontStrip) { inherit dontStrip; } 1141 // optionalAttrs (postPhases != [ ]) { inherit postPhases; } 1142 // optionalAttrs (disallowedRequisites != [ ] || disallowGhcReference) { 1143 disallowedRequisites = disallowedRequisites ++ (if disallowGhcReference then [ ghc ] else [ ]); 1144 } 1145 ) 1146)