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