at 18.09-beta 410 lines 18 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 doJailbreak = drv: overrideCabal drv (drv: { jailbreak = true; }); 91 92 /* dontJailbreak restores the use of the version bounds the check 93 the use of dependencies in the package description. 94 */ 95 dontJailbreak = drv: overrideCabal drv (drv: { jailbreak = false; }); 96 97 /* doCheck enables dependency checking, compilation and execution 98 of test suites listed in the package description file. 99 */ 100 doCheck = drv: overrideCabal drv (drv: { doCheck = true; }); 101 /* dontCheck disables dependency checking, compilation and execution 102 of test suites listed in the package description file. 103 */ 104 dontCheck = drv: overrideCabal drv (drv: { doCheck = false; }); 105 106 /* doBenchmark enables dependency checking, compilation and execution 107 for benchmarks listed in the package description file. 108 */ 109 doBenchmark = drv: overrideCabal drv (drv: { doBenchmark = true; }); 110 /* dontBenchmark disables dependency checking, compilation and execution 111 for benchmarks listed in the package description file. 112 */ 113 dontBenchmark = drv: overrideCabal drv (drv: { doBenchmark = false; }); 114 115 /* doDistribute enables the distribution of binaries for the package 116 via hydra. 117 */ 118 doDistribute = drv: overrideCabal drv (drv: { hydraPlatforms = drv.platforms or ["i686-linux" "x86_64-linux" "x86_64-darwin"]; }); 119 /* dontDistribute disables the distribution of binaries for the package 120 via hydra. 121 */ 122 dontDistribute = drv: overrideCabal drv (drv: { hydraPlatforms = []; }); 123 124 /* appendConfigureFlag adds a single argument that will be passed to the 125 cabal configure command, after the arguments that have been defined 126 in the initial declaration or previous overrides. 127 128 Example: 129 130 > haskell.lib.appendConfigureFlag haskellPackages.servant "--profiling-detail=all-functions" 131 */ 132 appendConfigureFlag = drv: x: appendConfigureFlags drv [x]; 133 appendConfigureFlags = drv: xs: overrideCabal drv (drv: { configureFlags = (drv.configureFlags or []) ++ xs; }); 134 135 appendBuildFlag = drv: x: overrideCabal drv (drv: { buildFlags = (drv.buildFlags or []) ++ [x]; }); 136 appendBuildFlags = drv: xs: overrideCabal drv (drv: { buildFlags = (drv.buildFlags or []) ++ xs; }); 137 138 /* removeConfigureFlag drv x is a Haskell package like drv, but with 139 all cabal configure arguments that are equal to x removed. 140 141 > haskell.lib.removeConfigureFlag haskellPackages.servant "--verbose" 142 */ 143 removeConfigureFlag = drv: x: overrideCabal drv (drv: { configureFlags = lib.remove x (drv.configureFlags or []); }); 144 145 addBuildTool = drv: x: addBuildTools drv [x]; 146 addBuildTools = drv: xs: overrideCabal drv (drv: { buildTools = (drv.buildTools or []) ++ xs; }); 147 148 addExtraLibrary = drv: x: addExtraLibraries drv [x]; 149 addExtraLibraries = drv: xs: overrideCabal drv (drv: { extraLibraries = (drv.extraLibraries or []) ++ xs; }); 150 151 addBuildDepend = drv: x: addBuildDepends drv [x]; 152 addBuildDepends = drv: xs: overrideCabal drv (drv: { buildDepends = (drv.buildDepends or []) ++ xs; }); 153 154 addPkgconfigDepend = drv: x: addPkgconfigDepends drv [x]; 155 addPkgconfigDepends = drv: xs: overrideCabal drv (drv: { pkgconfigDepends = (drv.pkgconfigDepends or []) ++ xs; }); 156 157 addSetupDepend = drv: x: addSetupDepends drv [x]; 158 addSetupDepends = drv: xs: overrideCabal drv (drv: { setupHaskellDepends = (drv.setupHaskellDepends or []) ++ xs; }); 159 160 enableCabalFlag = drv: x: appendConfigureFlag (removeConfigureFlag drv "-f-${x}") "-f${x}"; 161 disableCabalFlag = drv: x: appendConfigureFlag (removeConfigureFlag drv "-f${x}") "-f-${x}"; 162 163 markBroken = drv: overrideCabal drv (drv: { broken = true; hydraPlatforms = []; }); 164 markBrokenVersion = version: drv: assert drv.version == version; markBroken drv; 165 166 enableLibraryProfiling = drv: overrideCabal drv (drv: { enableLibraryProfiling = true; }); 167 disableLibraryProfiling = drv: overrideCabal drv (drv: { enableLibraryProfiling = false; }); 168 169 enableExecutableProfiling = drv: overrideCabal drv (drv: { enableExecutableProfiling = true; }); 170 disableExecutableProfiling = drv: overrideCabal drv (drv: { enableExecutableProfiling = false; }); 171 172 enableSharedExecutables = drv: overrideCabal drv (drv: { enableSharedExecutables = true; }); 173 disableSharedExecutables = drv: overrideCabal drv (drv: { enableSharedExecutables = false; }); 174 175 enableSharedLibraries = drv: overrideCabal drv (drv: { enableSharedLibraries = true; }); 176 disableSharedLibraries = drv: overrideCabal drv (drv: { enableSharedLibraries = false; }); 177 178 enableDeadCodeElimination = drv: overrideCabal drv (drv: { enableDeadCodeElimination = true; }); 179 disableDeadCodeElimination = drv: overrideCabal drv (drv: { enableDeadCodeElimination = false; }); 180 181 enableStaticLibraries = drv: overrideCabal drv (drv: { enableStaticLibraries = true; }); 182 disableStaticLibraries = drv: overrideCabal drv (drv: { enableStaticLibraries = false; }); 183 184 appendPatch = drv: x: appendPatches drv [x]; 185 appendPatches = drv: xs: overrideCabal drv (drv: { patches = (drv.patches or []) ++ xs; }); 186 187 doHyperlinkSource = drv: overrideCabal drv (drv: { hyperlinkSource = true; }); 188 dontHyperlinkSource = drv: overrideCabal drv (drv: { hyperlinkSource = false; }); 189 190 disableHardening = drv: flags: overrideCabal drv (drv: { hardeningDisable = flags; }); 191 192 /* Let Nix strip the binary files. 193 * This removes debugging symbols. 194 */ 195 doStrip = drv: overrideCabal drv (drv: { dontStrip = false; }); 196 197 /* Stop Nix from stripping the binary files. 198 * This keeps debugging symbols. 199 */ 200 dontStrip = drv: overrideCabal drv (drv: { dontStrip = true; }); 201 202 /* Useful for debugging segfaults with gdb. 203 * This includes dontStrip. 204 */ 205 enableDWARFDebugging = drv: 206 # -g: enables debugging symbols 207 # --disable-*-stripping: tell GHC not to strip resulting binaries 208 # dontStrip: see above 209 appendConfigureFlag (dontStrip drv) "--ghc-options=-g --disable-executable-stripping --disable-library-stripping"; 210 211 /* Create a source distribution tarball like those found on hackage, 212 instead of building the package. 213 */ 214 sdistTarball = pkg: lib.overrideDerivation pkg (drv: { 215 name = "${drv.pname}-source-${drv.version}"; 216 # Since we disable the haddock phase, we also need to override the 217 # outputs since the separate doc output will not be produced. 218 outputs = ["out"]; 219 buildPhase = "./Setup sdist"; 220 haddockPhase = ":"; 221 checkPhase = ":"; 222 installPhase = "install -D dist/${drv.pname}-*.tar.gz $out/${drv.pname}-${drv.version}.tar.gz"; 223 fixupPhase = ":"; 224 }); 225 226 /* Use the gold linker. It is a linker for ELF that is designed 227 "to run as fast as possible on modern systems" 228 */ 229 linkWithGold = drv : appendConfigureFlag drv 230 "--ghc-option=-optl-fuse-ld=gold --ld-option=-fuse-ld=gold --with-ld=ld.gold"; 231 232 /* link executables statically against haskell libs to reduce 233 closure size 234 */ 235 justStaticExecutables = drv: overrideCabal drv (drv: { 236 enableSharedExecutables = false; 237 enableLibraryProfiling = false; 238 isLibrary = false; 239 doHaddock = false; 240 postFixup = "rm -rf $out/lib $out/nix-support $out/share/doc"; 241 }); 242 243 /* Build a source distribution tarball instead of using the source files 244 directly. The effect is that the package is built as if it were published 245 on hackage. This can be used as a test for the source distribution, 246 assuming the build fails when packaging mistakes are in the cabal file. 247 */ 248 buildFromSdist = pkg: lib.overrideDerivation pkg (drv: { 249 unpackPhase = let src = sdistTarball pkg; tarname = "${pkg.pname}-${pkg.version}"; in '' 250 echo "Source tarball is at ${src}/${tarname}.tar.gz" 251 tar xf ${src}/${tarname}.tar.gz 252 cd ${pkg.pname}-* 253 ''; 254 }); 255 256 /* Build the package in a strict way to uncover potential problems. 257 This includes buildFromSdist and failOnAllWarnings. 258 */ 259 buildStrictly = pkg: buildFromSdist (failOnAllWarnings pkg); 260 261 /* Turn on most of the compiler warnings and fail the build if any 262 of them occur. */ 263 failOnAllWarnings = drv: appendConfigureFlag drv "--ghc-option=-Wall --ghc-option=-Werror"; 264 265 /* Add a post-build check to verify that dependencies declared in 266 the cabal file are actually used. 267 268 The first attrset argument can be used to configure the strictness 269 of this check and a list of ignored package names that would otherwise 270 cause false alarms. 271 */ 272 checkUnusedPackages = 273 { ignoreEmptyImports ? false 274 , ignoreMainModule ? false 275 , ignorePackages ? [] 276 } : drv : 277 overrideCabal (appendConfigureFlag drv "--ghc-option=-ddump-minimal-imports") (_drv: { 278 postBuild = with lib; 279 let args = concatStringsSep " " ( 280 optional ignoreEmptyImports "--ignore-empty-imports" ++ 281 optional ignoreMainModule "--ignore-main-module" ++ 282 map (pkg: "--ignore-package ${pkg}") ignorePackages 283 ); 284 in "${pkgs.haskellPackages.packunused}/bin/packunused" + 285 optionalString (args != "") " ${args}"; 286 }); 287 288 buildStackProject = pkgs.callPackage ./generic-stack-builder.nix { }; 289 290 /* Add a dummy command to trigger a build despite an equivalent 291 earlier build that is present in the store or cache. 292 */ 293 triggerRebuild = drv: i: overrideCabal drv (drv: { postUnpack = ": trigger rebuild ${toString i}"; }); 294 295 /* Override the sources for the package and optionaly the version. 296 This also takes of removing editedCabalFile. 297 */ 298 overrideSrc = drv: { src, version ? drv.version }: 299 overrideCabal drv (_: { inherit src version; editedCabalFile = null; }); 300 301 # Get all of the build inputs of a haskell package, divided by category. 302 getBuildInputs = p: 303 (overrideCabal p (args: { 304 passthru = (args.passthru or {}) // { 305 _getBuildInputs = extractBuildInputs p.compiler args; 306 }; 307 }))._getBuildInputs; 308 309 # Extract the haskell build inputs of a haskell package. 310 # This is useful to build environments for developing on that 311 # package. 312 getHaskellBuildInputs = p: (getBuildInputs p).haskellBuildInputs; 313 314 # Under normal evaluation, simply return the original package. Under 315 # nix-shell evaluation, return a nix-shell optimized environment. 316 shellAware = p: if lib.inNixShell then p.env else p; 317 318 ghcInfo = ghc: 319 rec { isCross = (ghc.cross or null) != null; 320 isGhcjs = ghc.isGhcjs or false; 321 nativeGhc = if isCross || isGhcjs 322 then ghc.bootPkgs.ghc 323 else ghc; 324 }; 325 326 ### mkDerivation helpers 327 # These allow external users of a haskell package to extract 328 # information about how it is built in the same way that the 329 # generic haskell builder does, by reusing the same functions. 330 # Each function here has the same interface as mkDerivation and thus 331 # can be called for a given package simply by overriding the 332 # mkDerivation argument it used. See getHaskellBuildInputs above for 333 # an example of this. 334 335 # Some information about which phases should be run. 336 controlPhases = ghc: let inherit (ghcInfo ghc) isCross; in 337 { doCheck ? !isCross && (lib.versionOlder "7.4" ghc.version) 338 , doBenchmark ? false 339 , ... 340 }: { inherit doCheck doBenchmark; }; 341 342 # Divide the build inputs of the package into useful sets. 343 extractBuildInputs = ghc: 344 { setupHaskellDepends ? [], extraLibraries ? [] 345 , librarySystemDepends ? [], executableSystemDepends ? [] 346 , pkgconfigDepends ? [], libraryPkgconfigDepends ? [] 347 , executablePkgconfigDepends ? [], testPkgconfigDepends ? [] 348 , benchmarkPkgconfigDepends ? [], testDepends ? [] 349 , testHaskellDepends ? [], testSystemDepends ? [] 350 , testToolDepends ? [], benchmarkDepends ? [] 351 , benchmarkHaskellDepends ? [], benchmarkSystemDepends ? [] 352 , benchmarkToolDepends ? [], buildDepends ? [] 353 , libraryHaskellDepends ? [], executableHaskellDepends ? [] 354 , ... 355 }@args: 356 let inherit (ghcInfo ghc) isGhcjs nativeGhc; 357 inherit (controlPhases ghc args) doCheck doBenchmark; 358 isHaskellPkg = x: x ? isHaskellLibrary; 359 allPkgconfigDepends = 360 pkgconfigDepends ++ libraryPkgconfigDepends ++ 361 executablePkgconfigDepends ++ 362 lib.optionals doCheck testPkgconfigDepends ++ 363 lib.optionals doBenchmark benchmarkPkgconfigDepends; 364 otherBuildInputs = 365 setupHaskellDepends ++ extraLibraries ++ 366 librarySystemDepends ++ executableSystemDepends ++ 367 allPkgconfigDepends ++ 368 lib.optionals doCheck ( testDepends ++ testHaskellDepends ++ 369 testSystemDepends ++ testToolDepends 370 ) ++ 371 # ghcjs's hsc2hs calls out to the native hsc2hs 372 lib.optional isGhcjs nativeGhc ++ 373 lib.optionals doBenchmark ( benchmarkDepends ++ 374 benchmarkHaskellDepends ++ 375 benchmarkSystemDepends ++ 376 benchmarkToolDepends 377 ); 378 propagatedBuildInputs = 379 buildDepends ++ libraryHaskellDepends ++ 380 executableHaskellDepends; 381 allBuildInputs = propagatedBuildInputs ++ otherBuildInputs; 382 isHaskellPartition = 383 lib.partition isHaskellPkg allBuildInputs; 384 in 385 { haskellBuildInputs = isHaskellPartition.right; 386 systemBuildInputs = isHaskellPartition.wrong; 387 inherit propagatedBuildInputs otherBuildInputs 388 allPkgconfigDepends; 389 }; 390 391 # Utility to convert a directory full of `cabal2nix`-generated files into a 392 # package override set 393 # 394 # packagesFromDirectory : { directory : Directory, ... } -> HaskellPackageOverrideSet 395 packagesFromDirectory = 396 { directory, ... }: 397 398 self: super: 399 let 400 haskellPaths = builtins.attrNames (builtins.readDir directory); 401 402 toKeyVal = file: { 403 name = builtins.replaceStrings [ ".nix" ] [ "" ] file; 404 405 value = self.callPackage (directory + "/${file}") { }; 406 }; 407 408 in 409 builtins.listToAttrs (map toKeyVal haskellPaths); 410}