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