at master 22 kB view raw
1# TODO(@Ericson2314): Remove `pkgs` param, which is only used for 2# `buildStackProject`, `justStaticExecutables` and `checkUnusedPackages` 3{ pkgs, lib }: 4 5rec { 6 7 /* 8 This function takes a file like `hackage-packages.nix` and constructs 9 a full package set out of that. 10 */ 11 makePackageSet = import ../make-package-set.nix; 12 13 /* 14 The function overrideCabal lets you alter the arguments to the 15 mkDerivation function. 16 17 Example: 18 19 First, note how the aeson package is constructed in hackage-packages.nix: 20 21 "aeson" = callPackage ({ mkDerivation, attoparsec, <snip> 22 }: 23 mkDerivation { 24 pname = "aeson"; 25 <snip> 26 homepage = "https://github.com/bos/aeson"; 27 }) 28 29 The mkDerivation function of haskellPackages will take care of putting 30 the homepage in the right place, in meta. 31 32 > haskellPackages.aeson.meta.homepage 33 "https://github.com/bos/aeson" 34 35 > x = haskell.lib.compose.overrideCabal (old: { homepage = old.homepage + "#readme"; }) haskellPackages.aeson 36 > x.meta.homepage 37 "https://github.com/bos/aeson#readme" 38 */ 39 overrideCabal = 40 f: drv: 41 (drv.override ( 42 args: 43 args 44 // { 45 mkDerivation = drv: (args.mkDerivation drv).override f; 46 } 47 )) 48 // { 49 overrideScope = scope: overrideCabal f (drv.overrideScope scope); 50 }; 51 52 # : Map Name (Either Path VersionNumber) -> HaskellPackageOverrideSet 53 # Given a set whose values are either paths or version strings, produces 54 # a package override set (i.e. (self: super: { etc. })) that sets 55 # the packages named in the input set to the corresponding versions 56 packageSourceOverrides = 57 overrides: self: super: 58 pkgs.lib.mapAttrs ( 59 name: src: 60 let 61 isPath = x: builtins.substring 0 1 (toString x) == "/"; 62 generateExprs = if isPath src then self.callCabal2nix else self.callHackage; 63 in 64 generateExprs name src { } 65 ) overrides; 66 67 /* 68 doCoverage modifies a haskell package to enable the generation 69 and installation of a coverage report. 70 71 See https://wiki.haskell.org/Haskell_program_coverage 72 */ 73 doCoverage = overrideCabal (drv: { 74 doCoverage = true; 75 }); 76 77 /* 78 dontCoverage modifies a haskell package to disable the generation 79 and installation of a coverage report. 80 */ 81 dontCoverage = overrideCabal (drv: { 82 doCoverage = false; 83 }); 84 85 /* 86 doHaddock modifies a haskell package to enable the generation and 87 installation of API documentation from code comments using the 88 haddock tool. 89 */ 90 doHaddock = overrideCabal (drv: { 91 doHaddock = true; 92 }); 93 94 /* 95 dontHaddock modifies a haskell package to disable the generation and 96 installation of API documentation from code comments using the 97 haddock tool. 98 */ 99 dontHaddock = overrideCabal (drv: { 100 doHaddock = false; 101 }); 102 103 /* 104 doJailbreak enables the removal of version bounds from the cabal 105 file. You may want to avoid this function. 106 107 This is useful when a package reports that it can not be built 108 due to version mismatches. In some cases, removing the version 109 bounds entirely is an easy way to make a package build, but at 110 the risk of breaking software in non-obvious ways now or in the 111 future. 112 113 Instead of jailbreaking, you can patch the cabal file. 114 115 Note that jailbreaking at this time, doesn't lift bounds on 116 conditional branches. 117 https://github.com/peti/jailbreak-cabal/issues/7 has further details. 118 */ 119 doJailbreak = overrideCabal (drv: { 120 jailbreak = true; 121 }); 122 123 /* 124 dontJailbreak restores the use of the version bounds the check 125 the use of dependencies in the package description. 126 */ 127 dontJailbreak = overrideCabal (drv: { 128 jailbreak = false; 129 }); 130 131 /* 132 doCheck enables dependency checking, compilation and execution 133 of test suites listed in the package description file. 134 */ 135 doCheck = overrideCabal (drv: { 136 doCheck = true; 137 }); 138 /* 139 dontCheck disables dependency checking, compilation and execution 140 of test suites listed in the package description file. 141 */ 142 dontCheck = overrideCabal (drv: { 143 doCheck = false; 144 }); 145 /* 146 The dontCheckIf variant sets doCheck = false if the condition 147 applies. In any other case the previously set/default value is used. 148 This prevents accidentally re-enabling tests in a later override. 149 */ 150 dontCheckIf = condition: if condition then dontCheck else lib.id; 151 152 /* 153 doBenchmark enables dependency checking and compilation 154 for benchmarks listed in the package description file. 155 Benchmarks are, however, not executed at the moment. 156 */ 157 doBenchmark = overrideCabal (drv: { 158 doBenchmark = true; 159 }); 160 /* 161 dontBenchmark disables dependency checking, compilation and execution 162 for benchmarks listed in the package description file. 163 */ 164 dontBenchmark = overrideCabal (drv: { 165 doBenchmark = false; 166 }); 167 168 /* 169 doDistribute enables the distribution of binaries for the package 170 via hydra. 171 */ 172 doDistribute = overrideCabal (drv: { 173 # lib.platforms.all is the default value for platforms (since GHC can cross-compile) 174 hydraPlatforms = lib.subtractLists (drv.badPlatforms or [ ]) (drv.platforms or lib.platforms.all); 175 }); 176 /* 177 dontDistribute disables the distribution of binaries for the package 178 via hydra. 179 */ 180 dontDistribute = overrideCabal (drv: { 181 hydraPlatforms = [ ]; 182 }); 183 184 /* 185 appendConfigureFlag adds a single argument that will be passed to the 186 cabal configure command, after the arguments that have been defined 187 in the initial declaration or previous overrides. 188 189 Example: 190 191 > haskell.lib.compose.appendConfigureFlag "--profiling-detail=all-functions" haskellPackages.servant 192 */ 193 appendConfigureFlag = x: appendConfigureFlags [ x ]; 194 appendConfigureFlags = 195 xs: 196 overrideCabal (drv: { 197 configureFlags = (drv.configureFlags or [ ]) ++ xs; 198 }); 199 200 appendBuildFlag = 201 x: 202 overrideCabal (drv: { 203 buildFlags = (drv.buildFlags or [ ]) ++ [ x ]; 204 }); 205 appendBuildFlags = 206 xs: 207 overrideCabal (drv: { 208 buildFlags = (drv.buildFlags or [ ]) ++ xs; 209 }); 210 211 /* 212 removeConfigureFlag drv x is a Haskell package like drv, but with 213 all cabal configure arguments that are equal to x removed. 214 215 > haskell.lib.compose.removeConfigureFlag "--verbose" haskellPackages.servant 216 */ 217 removeConfigureFlag = 218 x: 219 overrideCabal (drv: { 220 configureFlags = lib.remove x (drv.configureFlags or [ ]); 221 }); 222 223 addBuildTool = x: addBuildTools [ x ]; 224 addBuildTools = 225 xs: 226 overrideCabal (drv: { 227 buildTools = (drv.buildTools or [ ]) ++ xs; 228 }); 229 230 addExtraLibrary = x: addExtraLibraries [ x ]; 231 addExtraLibraries = 232 xs: 233 overrideCabal (drv: { 234 extraLibraries = (drv.extraLibraries or [ ]) ++ xs; 235 }); 236 237 addBuildDepend = x: addBuildDepends [ x ]; 238 addBuildDepends = 239 xs: 240 overrideCabal (drv: { 241 buildDepends = (drv.buildDepends or [ ]) ++ xs; 242 }); 243 244 addTestToolDepend = x: addTestToolDepends [ x ]; 245 addTestToolDepends = 246 xs: 247 overrideCabal (drv: { 248 testToolDepends = (drv.testToolDepends or [ ]) ++ xs; 249 }); 250 251 addPkgconfigDepend = x: addPkgconfigDepends [ x ]; 252 addPkgconfigDepends = 253 xs: 254 overrideCabal (drv: { 255 pkg-configDepends = (drv.pkg-configDepends or [ ]) ++ xs; 256 }); 257 258 addSetupDepend = x: addSetupDepends [ x ]; 259 addSetupDepends = 260 xs: 261 overrideCabal (drv: { 262 setupHaskellDepends = (drv.setupHaskellDepends or [ ]) ++ xs; 263 }); 264 265 enableCabalFlag = x: drv: appendConfigureFlag "-f${x}" (removeConfigureFlag "-f-${x}" drv); 266 disableCabalFlag = x: drv: appendConfigureFlag "-f-${x}" (removeConfigureFlag "-f${x}" drv); 267 268 markBroken = overrideCabal (drv: { 269 broken = true; 270 hydraPlatforms = [ ]; 271 }); 272 unmarkBroken = overrideCabal (drv: { 273 broken = false; 274 }); 275 markBrokenVersion = 276 version: drv: 277 assert drv.version == version; 278 markBroken drv; 279 markUnbroken = overrideCabal (drv: { 280 broken = false; 281 }); 282 283 /* 284 disableParallelBuilding drops the -j<n> option from the GHC 285 command line for the given package. This can be useful in rare 286 situations where parallel building of a package causes GHC to 287 fail for some reason. 288 */ 289 disableParallelBuilding = overrideCabal (drv: { 290 enableParallelBuilding = false; 291 }); 292 293 enableLibraryProfiling = overrideCabal (drv: { 294 enableLibraryProfiling = true; 295 }); 296 disableLibraryProfiling = overrideCabal (drv: { 297 enableLibraryProfiling = false; 298 }); 299 300 enableExecutableProfiling = overrideCabal (drv: { 301 enableExecutableProfiling = true; 302 }); 303 disableExecutableProfiling = overrideCabal (drv: { 304 enableExecutableProfiling = false; 305 }); 306 307 enableSharedExecutables = overrideCabal (drv: { 308 enableSharedExecutables = true; 309 }); 310 disableSharedExecutables = overrideCabal (drv: { 311 enableSharedExecutables = false; 312 }); 313 314 enableSharedLibraries = overrideCabal (drv: { 315 enableSharedLibraries = true; 316 }); 317 disableSharedLibraries = overrideCabal (drv: { 318 enableSharedLibraries = false; 319 }); 320 321 enableDeadCodeElimination = overrideCabal (drv: { 322 enableDeadCodeElimination = true; 323 }); 324 disableDeadCodeElimination = overrideCabal (drv: { 325 enableDeadCodeElimination = false; 326 }); 327 328 enableStaticLibraries = overrideCabal (drv: { 329 enableStaticLibraries = true; 330 }); 331 disableStaticLibraries = overrideCabal (drv: { 332 enableStaticLibraries = false; 333 }); 334 335 enableSeparateBinOutput = overrideCabal (drv: { 336 enableSeparateBinOutput = true; 337 }); 338 339 appendPatch = x: appendPatches [ x ]; 340 appendPatches = 341 xs: 342 overrideCabal (drv: { 343 patches = (drv.patches or [ ]) ++ xs; 344 }); 345 346 /* 347 Set a specific build target instead of compiling all targets in the package. 348 For example, imagine we have a .cabal file with a library, and 2 executables "dev" and "server". 349 We can build only "server" and not wait on the compilation of "dev" by using setBuildTarget as follows: 350 351 > setBuildTarget "server" (callCabal2nix "thePackageName" thePackageSrc {}) 352 */ 353 setBuildTargets = 354 xs: 355 overrideCabal (drv: { 356 buildTarget = lib.concatStringsSep " " xs; 357 }); 358 setBuildTarget = x: setBuildTargets [ x ]; 359 360 doHyperlinkSource = overrideCabal (drv: { 361 hyperlinkSource = true; 362 }); 363 dontHyperlinkSource = overrideCabal (drv: { 364 hyperlinkSource = false; 365 }); 366 367 disableHardening = 368 flags: 369 overrideCabal (drv: { 370 hardeningDisable = flags; 371 }); 372 373 /* 374 Let Nix strip the binary files. 375 This removes debugging symbols. 376 */ 377 doStrip = overrideCabal (drv: { 378 dontStrip = false; 379 }); 380 381 /* 382 Stop Nix from stripping the binary files. 383 This keeps debugging symbols. 384 */ 385 dontStrip = overrideCabal (drv: { 386 dontStrip = true; 387 }); 388 389 /* 390 Useful for debugging segfaults with gdb. 391 This includes dontStrip. 392 */ 393 enableDWARFDebugging = 394 drv: 395 # -g: enables debugging symbols 396 # --disable-*-stripping: tell GHC not to strip resulting binaries 397 # dontStrip: see above 398 appendConfigureFlag "--ghc-options=-g --disable-executable-stripping --disable-library-stripping" ( 399 dontStrip drv 400 ); 401 402 /* 403 Create a source distribution tarball like those found on hackage, 404 instead of building the package. 405 */ 406 sdistTarball = 407 pkg: 408 lib.overrideDerivation pkg (drv: { 409 name = "${drv.pname}-source-${drv.version}"; 410 # Since we disable the haddock phase, we also need to override the 411 # outputs since the separate doc output will not be produced. 412 outputs = [ "out" ]; 413 buildPhase = "./Setup sdist"; 414 haddockPhase = ":"; 415 checkPhase = ":"; 416 installPhase = "install -D dist/${drv.pname}-*.tar.gz $out/${drv.pname}-${drv.version}.tar.gz"; 417 fixupPhase = ":"; 418 }); 419 420 /* 421 Create a documentation tarball suitable for uploading to Hackage instead 422 of building the package. 423 */ 424 documentationTarball = 425 pkg: 426 pkgs.lib.overrideDerivation pkg (drv: { 427 name = "${drv.name}-docs"; 428 # Like sdistTarball, disable the "doc" output here. 429 outputs = [ "out" ]; 430 buildPhase = '' 431 runHook preHaddock 432 ./Setup haddock --for-hackage 433 runHook postHaddock 434 ''; 435 haddockPhase = ":"; 436 checkPhase = ":"; 437 installPhase = '' 438 runHook preInstall 439 mkdir -p "$out" 440 tar --format=ustar \ 441 -czf "$out/${drv.name}-docs.tar.gz" \ 442 -C dist/doc/html "${drv.name}-docs" 443 runHook postInstall 444 ''; 445 }); 446 447 /* 448 Use the gold linker. It is a linker for ELF that is designed 449 "to run as fast as possible on modern systems" 450 */ 451 linkWithGold = appendConfigureFlag "--ghc-option=-optl-fuse-ld=gold --ld-option=-fuse-ld=gold --with-ld=ld.gold"; 452 453 /* 454 link executables statically against haskell libs to reduce 455 closure size 456 */ 457 justStaticExecutables = overrideCabal (drv: { 458 enableSharedExecutables = false; 459 enableLibraryProfiling = drv.enableExecutableProfiling or false; 460 isLibrary = false; 461 doHaddock = false; 462 postFixup = drv.postFixup or "" + '' 463 464 # Remove every directory which could have links to other store paths. 465 rm -rf $out/lib $out/nix-support $out/share/doc 466 ''; 467 disallowGhcReference = true; 468 }); 469 470 /* 471 Build a source distribution tarball instead of using the source files 472 directly. The effect is that the package is built as if it were published 473 on hackage. This can be used as a test for the source distribution, 474 assuming the build fails when packaging mistakes are in the cabal file. 475 476 A faster implementation using `cabal-install` is available as 477 `buildFromCabalSdist` in your Haskell package set. 478 */ 479 buildFromSdist = 480 pkg: 481 overrideCabal (drv: { 482 src = "${sdistTarball pkg}/${pkg.pname}-${pkg.version}.tar.gz"; 483 484 # Revising and jailbreaking the cabal file has been handled in sdistTarball 485 revision = null; 486 editedCabalFile = null; 487 jailbreak = false; 488 }) pkg; 489 490 /* 491 Build the package in a strict way to uncover potential problems. 492 This includes buildFromSdist and failOnAllWarnings. 493 */ 494 buildStrictly = pkg: buildFromSdist (failOnAllWarnings pkg); 495 496 # Disable core optimizations, significantly speeds up build time 497 disableOptimization = appendConfigureFlag "--disable-optimization"; 498 499 /* 500 Turn on most of the compiler warnings and fail the build if any 501 of them occur. 502 */ 503 failOnAllWarnings = appendConfigureFlag "--ghc-option=-Wall --ghc-option=-Werror"; 504 505 /* 506 Add a post-build check to verify that dependencies declared in 507 the cabal file are actually used. 508 509 The first attrset argument can be used to configure the strictness 510 of this check and a list of ignored package names that would otherwise 511 cause false alarms. 512 */ 513 checkUnusedPackages = 514 { 515 ignoreEmptyImports ? false, 516 ignoreMainModule ? false, 517 ignorePackages ? [ ], 518 }: 519 drv: 520 overrideCabal (_drv: { 521 postBuild = 522 let 523 args = lib.concatStringsSep " " ( 524 lib.optional ignoreEmptyImports "--ignore-empty-imports" 525 ++ lib.optional ignoreMainModule "--ignore-main-module" 526 ++ map (pkg: "--ignore-package ${pkg}") ignorePackages 527 ); 528 in 529 "${pkgs.haskellPackages.packunused}/bin/packunused" + lib.optionalString (args != "") " ${args}"; 530 }) (appendConfigureFlag "--ghc-option=-ddump-minimal-imports" drv); 531 532 buildStackProject = pkgs.callPackage ../generic-stack-builder.nix { }; 533 534 /* 535 Add a dummy command to trigger a build despite an equivalent 536 earlier build that is present in the store or cache. 537 */ 538 triggerRebuild = 539 i: 540 overrideCabal (drv: { 541 postUnpack = drv.postUnpack or "" + '' 542 543 # trigger rebuild ${toString i} 544 ''; 545 }); 546 547 /* 548 Override the sources for the package and optionally the version. 549 This also takes of removing editedCabalFile. 550 */ 551 overrideSrc = 552 { 553 src, 554 version ? null, 555 }: 556 drv: 557 overrideCabal (_: { 558 inherit src; 559 version = if version == null then drv.version else version; 560 editedCabalFile = null; 561 }) drv; 562 563 # Get all of the build inputs of a haskell package, divided by category. 564 getBuildInputs = p: p.getBuildInputs; 565 566 # Extract the haskell build inputs of a haskell package. 567 # This is useful to build environments for developing on that 568 # package. 569 getHaskellBuildInputs = p: (getBuildInputs p).haskellBuildInputs; 570 571 # Under normal evaluation, simply return the original package. Under 572 # nix-shell evaluation, return a nix-shell optimized environment. 573 shellAware = p: if lib.inNixShell then p.env else p; 574 575 # Utility to convert a directory full of `cabal2nix`-generated files into a 576 # package override set 577 # 578 # packagesFromDirectory : { directory : Directory, ... } -> HaskellPackageOverrideSet 579 packagesFromDirectory = 580 { directory, ... }: 581 582 self: super: 583 let 584 haskellPaths = lib.filter (lib.hasSuffix ".nix") (builtins.attrNames (builtins.readDir directory)); 585 586 toKeyVal = file: { 587 name = builtins.replaceStrings [ ".nix" ] [ "" ] file; 588 589 value = self.callPackage (directory + "/${file}") { }; 590 }; 591 592 in 593 builtins.listToAttrs (map toKeyVal haskellPaths); 594 595 /* 596 INTERNAL function retained for backwards compatibility, use 597 haskell.packages.*.generateOptparseApplicativeCompletions instead! 598 */ 599 __generateOptparseApplicativeCompletion = 600 exeName: 601 overrideCabal (drv: { 602 postInstall = (drv.postInstall or "") + '' 603 bashCompDir="''${!outputBin}/share/bash-completion/completions" 604 zshCompDir="''${!outputBin}/share/zsh/vendor-completions" 605 fishCompDir="''${!outputBin}/share/fish/vendor_completions.d" 606 mkdir -p "$bashCompDir" "$zshCompDir" "$fishCompDir" 607 "''${!outputBin}/bin/${exeName}" --bash-completion-script "''${!outputBin}/bin/${exeName}" >"$bashCompDir/${exeName}" 608 "''${!outputBin}/bin/${exeName}" --zsh-completion-script "''${!outputBin}/bin/${exeName}" >"$zshCompDir/_${exeName}" 609 "''${!outputBin}/bin/${exeName}" --fish-completion-script "''${!outputBin}/bin/${exeName}" >"$fishCompDir/${exeName}.fish" 610 611 # Sanity check 612 grep -F ${exeName} <$bashCompDir/${exeName} >/dev/null || { 613 echo 'Could not find ${exeName} in completion script.' 614 exit 1 615 } 616 ''; 617 }); 618 619 /* 620 Retained for backwards compatibility. 621 Use haskell.packages.*.generateOptparseApplicativeCompletions 622 which is cross aware instead. 623 */ 624 generateOptparseApplicativeCompletions = 625 commands: pkg: 626 lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2211) 627 "haskellLib.generateOptparseApplicativeCompletions is deprecated in favor of haskellPackages.generateOptparseApplicativeCompletions. Please change ${pkg.name} to use the latter and make sure it uses its matching haskell.packages set!" 628 (pkgs.lib.foldr __generateOptparseApplicativeCompletion pkg commands); 629 630 /* 631 Retained for backwards compatibility. 632 Use haskell.packages.*.generateOptparseApplicativeCompletions 633 which is cross aware instead. 634 */ 635 generateOptparseApplicativeCompletion = 636 command: pkg: 637 lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2211) 638 "haskellLib.generateOptparseApplicativeCompletion is deprecated in favor of haskellPackages.generateOptparseApplicativeCompletions (plural!). Please change ${pkg.name} to use the latter and make sure it uses its matching haskell.packages set!" 639 (__generateOptparseApplicativeCompletion command pkg); 640 641 # Don't fail at configure time if there are multiple versions of the 642 # same package in the (recursive) dependencies of the package being 643 # built. Will delay failures, if any, to compile time. 644 allowInconsistentDependencies = overrideCabal (drv: { 645 allowInconsistentDependencies = true; 646 }); 647 648 # Work around a Cabal bug requiring pkg-config --static --libs to work even 649 # when linking dynamically, affecting Cabal 3.8 and 3.9. 650 # https://github.com/haskell/cabal/issues/8455 651 # 652 # For this, we treat the runtime system/pkg-config dependencies of a Haskell 653 # derivation as if they were propagated from their dependencies which allows 654 # pkg-config --static to work in most cases. 655 # 656 # Warning: This function may change or be removed at any time, e.g. if we find 657 # a different workaround, upstream fixes the bug or we patch Cabal. 658 __CabalEagerPkgConfigWorkaround = 659 let 660 # Take list of derivations and return list of the transitive dependency 661 # closure, only taking into account buildInputs. Loosely based on 662 # closePropagationFast. 663 propagatedPlainBuildInputs = 664 drvs: 665 builtins.map (i: i.val) ( 666 builtins.genericClosure { 667 startSet = builtins.map (drv: { 668 key = drv.outPath; 669 val = drv; 670 }) drvs; 671 operator = 672 { val, ... }: 673 if !lib.isDerivation val then 674 [ ] 675 else 676 builtins.concatMap ( 677 drv: 678 if !lib.isDerivation drv then 679 [ ] 680 else 681 [ 682 { 683 key = drv.outPath; 684 val = drv; 685 } 686 ] 687 ) (val.buildInputs or [ ] ++ val.propagatedBuildInputs or [ ]); 688 } 689 ); 690 in 691 overrideCabal (old: { 692 benchmarkPkgconfigDepends = propagatedPlainBuildInputs old.benchmarkPkgconfigDepends or [ ]; 693 executablePkgconfigDepends = propagatedPlainBuildInputs old.executablePkgconfigDepends or [ ]; 694 libraryPkgconfigDepends = propagatedPlainBuildInputs old.libraryPkgconfigDepends or [ ]; 695 testPkgconfigDepends = propagatedPlainBuildInputs old.testPkgconfigDepends or [ ]; 696 }); 697}