lol
at 23.05-pre 466 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 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 112 /* doBenchmark enables dependency checking, compilation and execution 113 for benchmarks listed in the package description file. 114 */ 115 doBenchmark = overrideCabal (drv: { doBenchmark = true; }); 116 /* dontBenchmark disables dependency checking, compilation and execution 117 for benchmarks listed in the package description file. 118 */ 119 dontBenchmark = overrideCabal (drv: { doBenchmark = false; }); 120 121 /* doDistribute enables the distribution of binaries for the package 122 via hydra. 123 */ 124 doDistribute = overrideCabal (drv: { 125 # lib.platforms.all is the default value for platforms (since GHC can cross-compile) 126 hydraPlatforms = lib.subtractLists (drv.badPlatforms or []) 127 (drv.platforms or lib.platforms.all); 128 }); 129 /* dontDistribute disables the distribution of binaries for the package 130 via hydra. 131 */ 132 dontDistribute = overrideCabal (drv: { hydraPlatforms = []; }); 133 134 /* appendConfigureFlag adds a single argument that will be passed to the 135 cabal configure command, after the arguments that have been defined 136 in the initial declaration or previous overrides. 137 138 Example: 139 140 > haskell.lib.compose.appendConfigureFlag "--profiling-detail=all-functions" haskellPackages.servant 141 */ 142 appendConfigureFlag = x: appendConfigureFlags [x]; 143 appendConfigureFlags = xs: overrideCabal (drv: { configureFlags = (drv.configureFlags or []) ++ xs; }); 144 145 appendBuildFlag = x: overrideCabal (drv: { buildFlags = (drv.buildFlags or []) ++ [x]; }); 146 appendBuildFlags = xs: overrideCabal (drv: { buildFlags = (drv.buildFlags or []) ++ xs; }); 147 148 /* removeConfigureFlag drv x is a Haskell package like drv, but with 149 all cabal configure arguments that are equal to x removed. 150 151 > haskell.lib.compose.removeConfigureFlag "--verbose" haskellPackages.servant 152 */ 153 removeConfigureFlag = x: overrideCabal (drv: { configureFlags = lib.remove x (drv.configureFlags or []); }); 154 155 addBuildTool = x: addBuildTools [x]; 156 addBuildTools = xs: overrideCabal (drv: { buildTools = (drv.buildTools or []) ++ xs; }); 157 158 addExtraLibrary = x: addExtraLibraries [x]; 159 addExtraLibraries = xs: overrideCabal (drv: { extraLibraries = (drv.extraLibraries or []) ++ xs; }); 160 161 addBuildDepend = x: addBuildDepends [x]; 162 addBuildDepends = xs: overrideCabal (drv: { buildDepends = (drv.buildDepends or []) ++ xs; }); 163 164 addTestToolDepend = x: addTestToolDepends [x]; 165 addTestToolDepends = xs: overrideCabal (drv: { testToolDepends = (drv.testToolDepends or []) ++ xs; }); 166 167 addPkgconfigDepend = x: addPkgconfigDepends [x]; 168 addPkgconfigDepends = xs: overrideCabal (drv: { pkg-configDepends = (drv.pkg-configDepends or []) ++ xs; }); 169 170 addSetupDepend = x: addSetupDepends [x]; 171 addSetupDepends = xs: overrideCabal (drv: { setupHaskellDepends = (drv.setupHaskellDepends or []) ++ xs; }); 172 173 enableCabalFlag = x: drv: appendConfigureFlag "-f${x}" (removeConfigureFlag "-f-${x}" drv); 174 disableCabalFlag = x: drv: appendConfigureFlag "-f-${x}" (removeConfigureFlag "-f${x}" drv); 175 176 markBroken = overrideCabal (drv: { broken = true; hydraPlatforms = []; }); 177 unmarkBroken = overrideCabal (drv: { broken = false; }); 178 markBrokenVersion = version: drv: assert drv.version == version; markBroken drv; 179 markUnbroken = overrideCabal (drv: { broken = false; }); 180 181 enableLibraryProfiling = overrideCabal (drv: { enableLibraryProfiling = true; }); 182 disableLibraryProfiling = overrideCabal (drv: { enableLibraryProfiling = false; }); 183 184 enableExecutableProfiling = overrideCabal (drv: { enableExecutableProfiling = true; }); 185 disableExecutableProfiling = overrideCabal (drv: { enableExecutableProfiling = false; }); 186 187 enableSharedExecutables = overrideCabal (drv: { enableSharedExecutables = true; }); 188 disableSharedExecutables = overrideCabal (drv: { enableSharedExecutables = false; }); 189 190 enableSharedLibraries = overrideCabal (drv: { enableSharedLibraries = true; }); 191 disableSharedLibraries = overrideCabal (drv: { enableSharedLibraries = false; }); 192 193 enableDeadCodeElimination = overrideCabal (drv: { enableDeadCodeElimination = true; }); 194 disableDeadCodeElimination = overrideCabal (drv: { enableDeadCodeElimination = false; }); 195 196 enableStaticLibraries = overrideCabal (drv: { enableStaticLibraries = true; }); 197 disableStaticLibraries = overrideCabal (drv: { enableStaticLibraries = false; }); 198 199 enableSeparateBinOutput = overrideCabal (drv: { enableSeparateBinOutput = true; }); 200 201 appendPatch = x: appendPatches [x]; 202 appendPatches = xs: overrideCabal (drv: { patches = (drv.patches or []) ++ xs; }); 203 204 /* Set a specific build target instead of compiling all targets in the package. 205 * For example, imagine we have a .cabal file with a library, and 2 executables "dev" and "server". 206 * We can build only "server" and not wait on the compilation of "dev" by using setBuildTarget as follows: 207 * 208 * > setBuildTarget "server" (callCabal2nix "thePackageName" thePackageSrc {}) 209 * 210 */ 211 setBuildTargets = xs: overrideCabal (drv: { buildTarget = lib.concatStringsSep " " xs; }); 212 setBuildTarget = x: setBuildTargets [x]; 213 214 doHyperlinkSource = overrideCabal (drv: { hyperlinkSource = true; }); 215 dontHyperlinkSource = overrideCabal (drv: { hyperlinkSource = false; }); 216 217 disableHardening = flags: overrideCabal (drv: { hardeningDisable = flags; }); 218 219 /* Let Nix strip the binary files. 220 * This removes debugging symbols. 221 */ 222 doStrip = overrideCabal (drv: { dontStrip = false; }); 223 224 /* Stop Nix from stripping the binary files. 225 * This keeps debugging symbols. 226 */ 227 dontStrip = overrideCabal (drv: { dontStrip = true; }); 228 229 /* Useful for debugging segfaults with gdb. 230 * This includes dontStrip. 231 */ 232 enableDWARFDebugging = drv: 233 # -g: enables debugging symbols 234 # --disable-*-stripping: tell GHC not to strip resulting binaries 235 # dontStrip: see above 236 appendConfigureFlag "--ghc-options=-g --disable-executable-stripping --disable-library-stripping" (dontStrip drv); 237 238 /* Create a source distribution tarball like those found on hackage, 239 instead of building the package. 240 */ 241 sdistTarball = pkg: lib.overrideDerivation pkg (drv: { 242 name = "${drv.pname}-source-${drv.version}"; 243 # Since we disable the haddock phase, we also need to override the 244 # outputs since the separate doc output will not be produced. 245 outputs = ["out"]; 246 buildPhase = "./Setup sdist"; 247 haddockPhase = ":"; 248 checkPhase = ":"; 249 installPhase = "install -D dist/${drv.pname}-*.tar.gz $out/${drv.pname}-${drv.version}.tar.gz"; 250 fixupPhase = ":"; 251 }); 252 253 /* Create a documentation tarball suitable for uploading to Hackage instead 254 of building the package. 255 */ 256 documentationTarball = pkg: 257 pkgs.lib.overrideDerivation pkg (drv: { 258 name = "${drv.name}-docs"; 259 # Like sdistTarball, disable the "doc" output here. 260 outputs = [ "out" ]; 261 buildPhase = '' 262 runHook preHaddock 263 ./Setup haddock --for-hackage 264 runHook postHaddock 265 ''; 266 haddockPhase = ":"; 267 checkPhase = ":"; 268 installPhase = '' 269 runHook preInstall 270 mkdir -p "$out" 271 tar --format=ustar \ 272 -czf "$out/${drv.name}-docs.tar.gz" \ 273 -C dist/doc/html "${drv.name}-docs" 274 runHook postInstall 275 ''; 276 }); 277 278 /* Use the gold linker. It is a linker for ELF that is designed 279 "to run as fast as possible on modern systems" 280 */ 281 linkWithGold = appendConfigureFlag 282 "--ghc-option=-optl-fuse-ld=gold --ld-option=-fuse-ld=gold --with-ld=ld.gold"; 283 284 /* link executables statically against haskell libs to reduce 285 closure size 286 */ 287 justStaticExecutables = overrideCabal (drv: { 288 enableSharedExecutables = false; 289 enableLibraryProfiling = false; 290 isLibrary = false; 291 doHaddock = false; 292 postFixup = drv.postFixup or "" + '' 293 294 # Remove every directory which could have links to other store paths. 295 rm -rf $out/lib $out/nix-support $out/share/doc 296 ''; 297 }); 298 299 /* Build a source distribution tarball instead of using the source files 300 directly. The effect is that the package is built as if it were published 301 on hackage. This can be used as a test for the source distribution, 302 assuming the build fails when packaging mistakes are in the cabal file. 303 304 A faster implementation using `cabal-install` is available as 305 `buildFromCabalSdist` in your Haskell package set. 306 */ 307 buildFromSdist = pkg: overrideCabal (drv: { 308 src = "${sdistTarball pkg}/${pkg.pname}-${pkg.version}.tar.gz"; 309 310 # Revising and jailbreaking the cabal file has been handled in sdistTarball 311 revision = null; 312 editedCabalFile = null; 313 jailbreak = false; 314 }) pkg; 315 316 /* Build the package in a strict way to uncover potential problems. 317 This includes buildFromSdist and failOnAllWarnings. 318 */ 319 buildStrictly = pkg: buildFromSdist (failOnAllWarnings pkg); 320 321 /* Disable core optimizations, significantly speeds up build time */ 322 disableOptimization = appendConfigureFlag "--disable-optimization"; 323 324 /* Turn on most of the compiler warnings and fail the build if any 325 of them occur. */ 326 failOnAllWarnings = appendConfigureFlag "--ghc-option=-Wall --ghc-option=-Werror"; 327 328 /* Add a post-build check to verify that dependencies declared in 329 the cabal file are actually used. 330 331 The first attrset argument can be used to configure the strictness 332 of this check and a list of ignored package names that would otherwise 333 cause false alarms. 334 */ 335 checkUnusedPackages = 336 { ignoreEmptyImports ? false 337 , ignoreMainModule ? false 338 , ignorePackages ? [] 339 } : drv : 340 overrideCabal (_drv: { 341 postBuild = with lib; 342 let args = concatStringsSep " " ( 343 optional ignoreEmptyImports "--ignore-empty-imports" ++ 344 optional ignoreMainModule "--ignore-main-module" ++ 345 map (pkg: "--ignore-package ${pkg}") ignorePackages 346 ); 347 in "${pkgs.haskellPackages.packunused}/bin/packunused" + 348 optionalString (args != "") " ${args}"; 349 }) (appendConfigureFlag "--ghc-option=-ddump-minimal-imports" drv); 350 351 buildStackProject = pkgs.callPackage ../generic-stack-builder.nix { }; 352 353 /* Add a dummy command to trigger a build despite an equivalent 354 earlier build that is present in the store or cache. 355 */ 356 triggerRebuild = i: overrideCabal (drv: { postUnpack = ": trigger rebuild ${toString i}"; }); 357 358 /* Override the sources for the package and optionaly the version. 359 This also takes of removing editedCabalFile. 360 */ 361 overrideSrc = { src, version ? null }: drv: 362 overrideCabal (_: { inherit src; version = if version == null then drv.version else version; editedCabalFile = null; }) drv; 363 364 # Get all of the build inputs of a haskell package, divided by category. 365 getBuildInputs = p: p.getBuildInputs; 366 367 # Extract the haskell build inputs of a haskell package. 368 # This is useful to build environments for developing on that 369 # package. 370 getHaskellBuildInputs = p: (getBuildInputs p).haskellBuildInputs; 371 372 # Under normal evaluation, simply return the original package. Under 373 # nix-shell evaluation, return a nix-shell optimized environment. 374 shellAware = p: if lib.inNixShell then p.env else p; 375 376 ghcInfo = ghc: 377 rec { isCross = (ghc.cross or null) != null; 378 isGhcjs = ghc.isGhcjs or false; 379 nativeGhc = if isCross || isGhcjs 380 then ghc.bootPkgs.ghc 381 else ghc; 382 }; 383 384 ### mkDerivation helpers 385 # These allow external users of a haskell package to extract 386 # information about how it is built in the same way that the 387 # generic haskell builder does, by reusing the same functions. 388 # Each function here has the same interface as mkDerivation and thus 389 # can be called for a given package simply by overriding the 390 # mkDerivation argument it used. See getHaskellBuildInputs above for 391 # an example of this. 392 393 # Some information about which phases should be run. 394 controlPhases = ghc: let inherit (ghcInfo ghc) isCross; in 395 { doCheck ? !isCross && (lib.versionOlder "7.4" ghc.version) 396 , doBenchmark ? false 397 , ... 398 }: { inherit doCheck doBenchmark; }; 399 400 # Utility to convert a directory full of `cabal2nix`-generated files into a 401 # package override set 402 # 403 # packagesFromDirectory : { directory : Directory, ... } -> HaskellPackageOverrideSet 404 packagesFromDirectory = 405 { directory, ... }: 406 407 self: super: 408 let 409 haskellPaths = builtins.attrNames (builtins.readDir directory); 410 411 toKeyVal = file: { 412 name = builtins.replaceStrings [ ".nix" ] [ "" ] file; 413 414 value = self.callPackage (directory + "/${file}") { }; 415 }; 416 417 in 418 builtins.listToAttrs (map toKeyVal haskellPaths); 419 420 /* 421 INTERNAL function retained for backwards compatibility, use 422 haskell.packages.*.generateOptparseApplicativeCompletions instead! 423 */ 424 __generateOptparseApplicativeCompletion = exeName: overrideCabal (drv: { 425 postInstall = (drv.postInstall or "") + '' 426 bashCompDir="''${!outputBin}/share/bash-completion/completions" 427 zshCompDir="''${!outputBin}/share/zsh/vendor-completions" 428 fishCompDir="''${!outputBin}/share/fish/vendor_completions.d" 429 mkdir -p "$bashCompDir" "$zshCompDir" "$fishCompDir" 430 "''${!outputBin}/bin/${exeName}" --bash-completion-script "''${!outputBin}/bin/${exeName}" >"$bashCompDir/${exeName}" 431 "''${!outputBin}/bin/${exeName}" --zsh-completion-script "''${!outputBin}/bin/${exeName}" >"$zshCompDir/_${exeName}" 432 "''${!outputBin}/bin/${exeName}" --fish-completion-script "''${!outputBin}/bin/${exeName}" >"$fishCompDir/${exeName}.fish" 433 434 # Sanity check 435 grep -F ${exeName} <$bashCompDir/${exeName} >/dev/null || { 436 echo 'Could not find ${exeName} in completion script.' 437 exit 1 438 } 439 ''; 440 }); 441 442 /* 443 Retained for backwards compatibility. 444 Use haskell.packages.*.generateOptparseApplicativeCompletions 445 which is cross aware instead. 446 */ 447 generateOptparseApplicativeCompletions = commands: pkg: 448 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!" 449 (pkgs.lib.foldr __generateOptparseApplicativeCompletion pkg commands); 450 451 /* 452 Retained for backwards compatibility. 453 Use haskell.packages.*.generateOptparseApplicativeCompletions 454 which is cross aware instead. 455 */ 456 generateOptparseApplicativeCompletion = command: pkg: 457 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!" 458 (__generateOptparseApplicativeCompletion command pkg); 459 460 # Don't fail at configure time if there are multiple versions of the 461 # same package in the (recursive) dependencies of the package being 462 # built. Will delay failures, if any, to compile time. 463 allowInconsistentDependencies = overrideCabal (drv: { 464 allowInconsistentDependencies = true; 465 }); 466}