Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1# This expression takes a file like `hackage-packages.nix` and constructs 2# a full package set out of that. 3 4{ # package-set used for build tools (all of nixpkgs) 5 buildPackages 6 7, # A haskell package set for Setup.hs, compiler plugins, and similar 8 # build-time uses. 9 buildHaskellPackages 10 11, # package-set used for non-haskell dependencies (all of nixpkgs) 12 pkgs 13 14, # stdenv provides our build and host platforms 15 stdenv 16 17, # this module provides the list of known licenses and maintainers 18 lib 19 20 # needed for overrideCabal & packageSourceOverrides 21, haskellLib 22 23, # hashes for downloading Hackage packages 24 all-cabal-hashes 25 26, # compiler to use 27 ghc 28 29, # A function that takes `{ pkgs, lib, callPackage }` as the first arg and 30 # `self` as second, and returns a set of haskell packages 31 package-set 32 33, # The final, fully overriden package set usable with the nixpkgs fixpoint 34 # overriding functionality 35 extensible-self 36}: 37 38# return value: a function from self to the package set 39self: 40 41let 42 inherit (stdenv) buildPlatform hostPlatform; 43 44 inherit (lib) fix' extends makeOverridable; 45 inherit (haskellLib) overrideCabal; 46 47 mkDerivationImpl = pkgs.callPackage ./generic-builder.nix { 48 inherit stdenv; 49 nodejs = buildPackages.nodejs-slim; 50 inherit (self) buildHaskellPackages ghc ghcWithHoogle ghcWithPackages; 51 inherit (self.buildHaskellPackages) jailbreak-cabal; 52 hscolour = overrideCabal (drv: { 53 isLibrary = false; 54 doHaddock = false; 55 hyperlinkSource = false; # Avoid depending on hscolour for this build. 56 postFixup = "rm -rf $out/lib $out/share $out/nix-support"; 57 }) self.buildHaskellPackages.hscolour; 58 cpphs = overrideCabal (drv: { 59 isLibrary = false; 60 postFixup = "rm -rf $out/lib $out/share $out/nix-support"; 61 }) (self.cpphs.overrideScope (self: super: { 62 mkDerivation = drv: super.mkDerivation (drv // { 63 enableSharedExecutables = false; 64 enableSharedLibraries = false; 65 doHaddock = false; 66 useCpphs = false; 67 }); 68 })); 69 }; 70 71 mkDerivation = makeOverridable mkDerivationImpl; 72 73 # manualArgs are the arguments that were explictly passed to `callPackage`, like: 74 # 75 # callPackage foo { bar = null; }; 76 # 77 # here `bar` is a manual argument. 78 callPackageWithScope = scope: fn: manualArgs: 79 let 80 # this code is copied from callPackage in lib/customisation.nix 81 # 82 # we cannot use `callPackage` here because we want to call `makeOverridable` 83 # on `drvScope` (we cannot add `overrideScope` after calling `callPackage` because then it is 84 # lost on `.override`) but determine the auto-args based on `drv` (the problem here 85 # is that nix has no way to "passthrough" args while preserving the reflection 86 # info that callPackage uses to determine the arguments). 87 drv = if lib.isFunction fn then fn else import fn; 88 auto = builtins.intersectAttrs (lib.functionArgs drv) scope; 89 90 # Converts a returned function to a functor attribute set if necessary 91 ensureAttrs = v: if builtins.isFunction v then { __functor = _: v; } else v; 92 93 # this wraps the `drv` function to add a `overrideScope` function to the result. 94 drvScope = allArgs: ensureAttrs (drv allArgs) // { 95 overrideScope = f: 96 let newScope = mkScope (fix' (extends f scope.__unfix__)); 97 # note that we have to be careful here: `allArgs` includes the auto-arguments that 98 # weren't manually specified. If we would just pass `allArgs` to the recursive call here, 99 # then we wouldn't look up any packages in the scope in the next interation, because it 100 # appears as if all arguments were already manually passed, so the scope change would do 101 # nothing. 102 in callPackageWithScope newScope drv manualArgs; 103 }; 104 in lib.makeOverridable drvScope (auto // manualArgs); 105 106 mkScope = scope: let 107 ps = pkgs.__splicedPackages; 108 scopeSpliced = pkgs.splicePackages { 109 pkgsBuildBuild = scope.buildHaskellPackages.buildHaskellPackages; 110 pkgsBuildHost = scope.buildHaskellPackages; 111 pkgsBuildTarget = {}; 112 pkgsHostHost = {}; 113 pkgsHostTarget = scope; 114 pkgsTargetTarget = {}; 115 } // { 116 # Don't splice these 117 inherit (scope) ghc buildHaskellPackages; 118 }; 119 in ps // ps.xorg // ps.gnome2 // { inherit stdenv; } // scopeSpliced; 120 defaultScope = mkScope self; 121 callPackage = drv: args: callPackageWithScope defaultScope drv args; 122 123 # Use cabal2nix to create a default.nix for the package sources found at 'src'. 124 haskellSrc2nix = { name, src, sha256 ? null, extraCabal2nixOptions ? "" }: 125 let 126 sha256Arg = if sha256 == null then "--sha256=" else ''--sha256="${sha256}"''; 127 in buildPackages.runCommand "cabal2nix-${name}" { 128 nativeBuildInputs = [ buildPackages.cabal2nix-unwrapped ]; 129 preferLocalBuild = true; 130 allowSubstitutes = false; 131 LANG = "en_US.UTF-8"; 132 LOCALE_ARCHIVE = pkgs.lib.optionalString (buildPlatform.libc == "glibc") "${buildPackages.glibcLocales}/lib/locale/locale-archive"; 133 } '' 134 export HOME="$TMP" 135 mkdir -p "$out" 136 cabal2nix --compiler=${self.ghc.haskellCompilerName} --system=${hostPlatform.config} ${sha256Arg} "${src}" ${extraCabal2nixOptions} > "$out/default.nix" 137 ''; 138 139 all-cabal-hashes-component = name: version: buildPackages.runCommand "all-cabal-hashes-component-${name}-${version}" {} '' 140 tar --wildcards -xzvf ${all-cabal-hashes} \*/${name}/${version}/${name}.{json,cabal} 141 mkdir -p $out 142 mv */${name}/${version}/${name}.{json,cabal} $out 143 ''; 144 145 hackage2nix = name: version: let component = all-cabal-hashes-component name version; in self.haskellSrc2nix { 146 name = "${name}-${version}"; 147 sha256 = ''$(sed -e 's/.*"SHA256":"//' -e 's/".*$//' "${component}/${name}.json")''; 148 src = "${component}/${name}.cabal"; 149 }; 150 151 # Adds a nix file as an input to the haskell derivation it 152 # produces. This is useful for callHackage / callCabal2nix to 153 # prevent the generated default.nix from being garbage collected 154 # (requiring it to be frequently rebuilt), which can be an 155 # annoyance. 156 callPackageKeepDeriver = src: args: 157 overrideCabal (orig: { 158 preConfigure = '' 159 # Generated from ${src} 160 ${orig.preConfigure or ""} 161 ''; 162 passthru = orig.passthru or {} // { 163 # When using callCabal2nix or callHackage, it is often useful 164 # to debug a failure by inspecting the Nix expression 165 # generated by cabal2nix. This can be accessed via this 166 # cabal2nixDeriver field. 167 cabal2nixDeriver = src; 168 }; 169 }) (self.callPackage src args); 170 171in package-set { inherit pkgs lib callPackage; } self // { 172 173 inherit mkDerivation callPackage haskellSrc2nix hackage2nix buildHaskellPackages; 174 175 inherit (haskellLib) packageSourceOverrides; 176 177 # callHackage :: Text -> Text -> AttrSet -> HaskellPackage 178 # 179 # e.g., while overriding a package set: 180 # '... foo = self.callHackage "foo" "1.5.3" {}; ...' 181 callHackage = name: version: callPackageKeepDeriver (self.hackage2nix name version); 182 183 # callHackageDirect 184 # :: { pkg :: Text, ver :: Text, sha256 :: Text } 185 # -> AttrSet 186 # -> HaskellPackage 187 # 188 # This function does not depend on all-cabal-hashes and therefore will work 189 # for any version that has been released on hackage as opposed to only 190 # versions released before whatever version of all-cabal-hashes you happen 191 # to be currently using. 192 callHackageDirect = {pkg, ver, sha256}: 193 let pkgver = "${pkg}-${ver}"; 194 in self.callCabal2nix pkg (pkgs.fetchzip { 195 url = "mirror://hackage/${pkgver}/${pkgver}.tar.gz"; 196 inherit sha256; 197 }); 198 199 # Creates a Haskell package from a source package by calling cabal2nix on the source. 200 callCabal2nixWithOptions = name: src: extraCabal2nixOptions: args: 201 let 202 filter = path: type: 203 pkgs.lib.hasSuffix ".cabal" path || 204 baseNameOf path == "package.yaml"; 205 expr = self.haskellSrc2nix { 206 inherit name extraCabal2nixOptions; 207 src = if pkgs.lib.canCleanSource src 208 then pkgs.lib.cleanSourceWith { inherit src filter; } 209 else src; 210 }; 211 in overrideCabal (orig: { 212 inherit src; 213 }) (callPackageKeepDeriver expr args); 214 215 callCabal2nix = name: src: args: self.callCabal2nixWithOptions name src "" args; 216 217 # : { root : Path 218 # , name : Defaulted String 219 # , source-overrides : Defaulted (Either Path VersionNumber) 220 # , overrides : Defaulted (HaskellPackageOverrideSet) 221 # , modifier : Defaulted 222 # , returnShellEnv : Defaulted 223 # , withHoogle : Defaulted 224 # , cabal2nixOptions : Defaulted 225 # } -> NixShellAwareDerivation 226 # 227 # Given a path to a haskell package directory, an optional package name 228 # which defaults to the base name of the path, an optional set of source 229 # overrides as appropriate for the 'packageSourceOverrides' function, an 230 # optional set of arbitrary overrides, and an optional haskell package 231 # modifier, return a derivation appropriate for nix-build or nix-shell to 232 # build that package. 233 # 234 # If 'returnShellEnv' is true this returns a derivation which will give you 235 # an environment suitable for developing the listed packages with an 236 # incremental tool like cabal-install. 237 # 238 # If 'withHoogle' is true (the default if a shell environment is requested) 239 # then 'ghcWithHoogle' is used to generate the derivation (instead of 240 # 'ghcWithPackages'), see the documentation there for more information. 241 # 242 # 'cabal2nixOptions' can contain extra command line arguments to pass to 243 # 'cabal2nix' when generating the package derivation, for example setting 244 # a cabal flag with '--flag=myflag'. 245 developPackage = 246 { root 247 , name ? if builtins.typeOf root == "path" then builtins.baseNameOf root else "" 248 , source-overrides ? {} 249 , overrides ? self: super: {} 250 , modifier ? drv: drv 251 , returnShellEnv ? pkgs.lib.inNixShell 252 , withHoogle ? returnShellEnv 253 , cabal2nixOptions ? "" }: 254 let drv = 255 (extensible-self.extend 256 (pkgs.lib.composeExtensions 257 (self.packageSourceOverrides source-overrides) 258 overrides)) 259 .callCabal2nixWithOptions name root cabal2nixOptions {}; 260 in if returnShellEnv 261 then (modifier drv).envFunc {inherit withHoogle;} 262 else modifier drv; 263 264 # This can be used to easily create a derivation containing GHC and the specified set of Haskell packages. 265 # 266 # Example: 267 # $ nix-shell -p 'haskellPackages.ghcWithPackages (hpkgs: [ hpkgs.mtl hpkgs.lens ])' 268 # $ ghci # in the nix-shell 269 # Prelude > import Control.Lens 270 # 271 # GHC is setup with a package database with all the specified Haskell packages. 272 # 273 # ghcWithPackages :: (HaskellPkgSet -> [ HaskellPkg ]) -> Derivation 274 ghcWithPackages = self.callPackage ./with-packages-wrapper.nix { 275 haskellPackages = self; 276 }; 277 278 279 # Put 'hoogle' into the derivation's PATH with a database containing all 280 # the package's dependencies; run 'hoogle server --local' in a shell to 281 # host a search engine for the dependencies. 282 # 283 # Example usage: 284 # $ nix-shell -p 'haskellPackages.hoogleWithPackages (p: [ p.mtl p.lens ])' 285 # [nix-shell] $ hoogle server 286 # 287 # hoogleWithPackages :: (HaskellPkgSet -> [ HaskellPkg ]) -> Derivation 288 # 289 # To reload the Hoogle server automatically on .cabal file changes try 290 # this: 291 # echo *.cabal | entr -r -- nix-shell --run 'hoogle server --local' 292 hoogleWithPackages = self.callPackage ./hoogle.nix { 293 haskellPackages = self; 294 }; 295 hoogleLocal = 296 { packages ? [] }: 297 lib.warn "hoogleLocal is deprecated, use hoogleWithPackages instead" ( 298 self.hoogleWithPackages (_: packages) 299 ); 300 # This is like a combination of ghcWithPackages and hoogleWithPackages. 301 # It provides a derivation containing both GHC and Hoogle with an index of 302 # the given Haskell package database. 303 # 304 # Example: 305 # $ nix-shell -p 'haskellPackages.ghcWithHoogle (hpkgs: [ hpkgs.conduit hpkgs.lens ])' 306 # 307 # ghcWithHoogle :: (HaskellPkgSet -> [ HaskellPkg ]) -> Derivation 308 ghcWithHoogle = self.ghcWithPackages.override { 309 withHoogle = true; 310 }; 311 312 # Returns a derivation whose environment contains a GHC with only 313 # the dependencies of packages listed in `packages`, not the 314 # packages themselves. Using nix-shell on this derivation will 315 # give you an environment suitable for developing the listed 316 # packages with an incremental tool like cabal-install. 317 # 318 # In addition to the "packages" arg and "withHoogle" arg, anything that 319 # can be passed into stdenv.mkDerivation can be included in the input attrset 320 # 321 # # default.nix 322 # with import <nixpkgs> {}; 323 # haskellPackages.extend (haskell.lib.compose.packageSourceOverrides { 324 # frontend = ./frontend; 325 # backend = ./backend; 326 # common = ./common; 327 # }) 328 # 329 # # shell.nix 330 # let pkgs = import <nixpkgs> {} in 331 # (import ./.).shellFor { 332 # packages = p: [p.frontend p.backend p.common]; 333 # withHoogle = true; 334 # buildInputs = [ pkgs.python pkgs.cabal-install ]; 335 # } 336 # 337 # -- cabal.project 338 # packages: 339 # frontend/ 340 # backend/ 341 # common/ 342 # 343 # bash$ nix-shell --run "cabal new-build all" 344 # bash$ nix-shell --run "python" 345 shellFor = 346 { # Packages to create this development shell for. These are usually 347 # your local packages. 348 packages 349 , # Whether or not to generate a Hoogle database for all the 350 # dependencies. 351 withHoogle ? false 352 , # Whether or not to include benchmark dependencies of your local 353 # packages. You should set this to true if you have benchmarks defined 354 # in your local packages that you want to be able to run with cabal benchmark 355 doBenchmark ? false 356 # An optional function that can modify the generic builder arguments 357 # for the fake package that shellFor uses to construct its environment. 358 # 359 # Example: 360 # let 361 # # elided... 362 # haskellPkgs = pkgs.haskell.packages.ghc884.override (hpArgs: { 363 # overrides = pkgs.lib.composeExtensions (hpArgs.overrides or (_: _: { })) ( 364 # _hfinal: hprev: { 365 # mkDerivation = args: hprev.mkDerivation ({ 366 # doCheck = false; 367 # doBenchmark = false; 368 # doHoogle = true; 369 # doHaddock = true; 370 # enableLibraryProfiling = false; 371 # enableExecutableProfiling = false; 372 # } // args); 373 # } 374 # ); 375 # }); 376 # in 377 # haskellPkgs.shellFor { 378 # packages = p: [ p.foo ]; 379 # genericBuilderArgsModifier = args: args // { doCheck = true; doBenchmark = true }; 380 # } 381 # 382 # This will disable tests and benchmarks for everything in "haskellPkgs" 383 # (which will invalidate the binary cache), and then re-enable them 384 # for the "shellFor" environment (ensuring that any test/benchmark 385 # dependencies for "foo" will be available within the nix-shell). 386 , genericBuilderArgsModifier ? (args: args) 387 388 # Extra dependencies, in the form of cabal2nix build attributes. 389 # 390 # An example use case is when you have Haskell scripts that use 391 # libraries that don't occur in your packages' dependencies. 392 # 393 # Example: 394 # 395 # extraDependencies = p: { 396 # libraryHaskellDepends = [ p.releaser ]; 397 # }; 398 , extraDependencies ? p: {} 399 , ... 400 } @ args: 401 let 402 # A list of the packages we want to build a development shell for. 403 # This is a list of Haskell package derivations. 404 selected = packages self; 405 406 # This is a list of attribute sets, where each attribute set 407 # corresponds to the build inputs of one of the packages input to shellFor. 408 # 409 # Each attribute has keys like buildDepends, executableHaskellDepends, 410 # testPkgconfigDepends, etc. The values for the keys of the attribute 411 # set are lists of dependencies. 412 # 413 # Example: 414 # cabalDepsForSelected 415 # => [ 416 # # This may be the attribute set corresponding to the `backend` 417 # # package in the example above. 418 # { buildDepends = [ gcc ... ]; 419 # libraryHaskellDepends = [ lens conduit ... ]; 420 # ... 421 # } 422 # # This may be the attribute set corresponding to the `common` 423 # # package in the example above. 424 # { testHaskellDepends = [ tasty hspec ... ]; 425 # libraryHaskellDepends = [ lens aeson ]; 426 # benchmarkHaskellDepends = [ criterion ... ]; 427 # ... 428 # } 429 # ... 430 # ] 431 cabalDepsForSelected = map (p: p.getCabalDeps) selected; 432 433 # A predicate that takes a derivation as input, and tests whether it is 434 # the same as any of the `selected` packages. 435 # 436 # Returns true if the input derivation is not in the list of `selected` 437 # packages. 438 # 439 # isNotSelected :: Derivation -> Bool 440 # 441 # Example: 442 # 443 # isNotSelected common [ frontend backend common ] 444 # => false 445 # 446 # isNotSelected lens [ frontend backend common ] 447 # => true 448 isNotSelected = input: pkgs.lib.all (p: input.outPath or null != p.outPath) selected; 449 450 # A function that takes a list of list of derivations, filters out all 451 # the `selected` packages from each list, and concats the results. 452 # 453 # zipperCombinedPkgs :: [[Derivation]] -> [Derivation] 454 # 455 # Example: 456 # zipperCombinedPkgs [ [ lens conduit ] [ aeson frontend ] ] 457 # => [ lens conduit aeson ] 458 # 459 # Note: The reason this isn't just the function `pkgs.lib.concat` is 460 # that we need to be careful to remove dependencies that are in the 461 # `selected` packages. 462 # 463 # For instance, in the above example, if `common` is a dependency of 464 # `backend`, then zipperCombinedPkgs needs to be careful to filter out 465 # `common`, because cabal will end up ignoring that built version, 466 # assuming new-style commands. 467 zipperCombinedPkgs = vals: 468 pkgs.lib.concatMap 469 (drvList: pkgs.lib.filter isNotSelected drvList) 470 vals; 471 472 # Zip `cabalDepsForSelected` into a single attribute list, combining 473 # the derivations in all the individual attributes. 474 # 475 # Example: 476 # packageInputs 477 # => # Assuming the value of cabalDepsForSelected is the same as 478 # # the example in cabalDepsForSelected: 479 # { buildDepends = [ gcc ... ]; 480 # libraryHaskellDepends = [ lens conduit aeson ... ]; 481 # testHaskellDepends = [ tasty hspec ... ]; 482 # benchmarkHaskellDepends = [ criterion ... ]; 483 # ... 484 # } 485 # 486 # See the Note in `zipperCombinedPkgs` for what gets filtered out from 487 # each of these dependency lists. 488 packageInputs = 489 pkgs.lib.zipAttrsWith (_name: zipperCombinedPkgs) (cabalDepsForSelected ++ [ (extraDependencies self) ]); 490 491 # A attribute set to pass to `haskellPackages.mkDerivation`. 492 # 493 # The important thing to note here is that all the fields from 494 # packageInputs are set correctly. 495 genericBuilderArgs = { 496 pname = 497 if pkgs.lib.length selected == 1 498 then (pkgs.lib.head selected).name 499 else "packages"; 500 version = "0"; 501 license = null; 502 } 503 // packageInputs 504 // pkgs.lib.optionalAttrs doBenchmark { 505 # `doBenchmark` needs to explicitly be set here because haskellPackages.mkDerivation defaults it to `false`. If the user wants benchmark dependencies included in their development shell, it has to be explicitly enabled here. 506 doBenchmark = true; 507 }; 508 509 # This is a pseudo Haskell package derivation that contains all the 510 # dependencies for the packages in `selected`. 511 # 512 # This is a derivation created with `haskellPackages.mkDerivation`. 513 # 514 # pkgWithCombinedDeps :: HaskellDerivation 515 pkgWithCombinedDeps = self.mkDerivation (genericBuilderArgsModifier genericBuilderArgs); 516 517 # The derivation returned from `envFunc` for `pkgWithCombinedDeps`. 518 # 519 # This is a derivation that can be run with `nix-shell`. It provides a 520 # GHC with a package database with all the dependencies of our 521 # `selected` packages. 522 # 523 # This is a derivation created with `stdenv.mkDerivation` (not 524 # `haskellPackages.mkDerivation`). 525 # 526 # pkgWithCombinedDepsDevDrv :: Derivation 527 pkgWithCombinedDepsDevDrv = pkgWithCombinedDeps.envFunc { inherit withHoogle; }; 528 529 mkDerivationArgs = builtins.removeAttrs args [ "genericBuilderArgsModifier" "packages" "withHoogle" "doBenchmark" "extraDependencies" ]; 530 531 in pkgWithCombinedDepsDevDrv.overrideAttrs (old: mkDerivationArgs // { 532 nativeBuildInputs = old.nativeBuildInputs ++ mkDerivationArgs.nativeBuildInputs or []; 533 buildInputs = old.buildInputs ++ mkDerivationArgs.buildInputs or []; 534 }); 535 536 ghc = ghc // { 537 withPackages = self.ghcWithPackages; 538 withHoogle = self.ghcWithHoogle; 539 }; 540 541 /* 542 Run `cabal sdist` on a source. 543 544 Unlike `haskell.lib.sdistTarball`, this does not require any dependencies 545 to be present, as it uses `cabal-install` instead of building `Setup.hs`. 546 This makes `cabalSdist` faster than `sdistTarball`. 547 */ 548 cabalSdist = { 549 src, 550 name ? if src?name then "${src.name}-sdist.tar.gz" else "source.tar.gz" 551 }: 552 pkgs.runCommandLocal name 553 { 554 inherit src; 555 nativeBuildInputs = [ buildHaskellPackages.cabal-install ]; 556 dontUnpack = false; 557 } '' 558 unpackPhase 559 cd "''${sourceRoot:-.}" 560 patchPhase 561 mkdir out 562 HOME=$PWD cabal sdist --output-directory out 563 mv out/*.tar.gz $out 564 ''; 565 566 /* 567 Like `haskell.lib.buildFromSdist`, but using `cabal sdist` instead of 568 building `./Setup`. 569 570 Unlike `haskell.lib.buildFromSdist`, this does not require any dependencies 571 to be present. This makes `buildFromCabalSdist` faster than `haskell.lib.buildFromSdist`. 572 */ 573 buildFromCabalSdist = pkg: 574 haskellLib.overrideSrc 575 { 576 src = self.cabalSdist { inherit (pkg) src; }; 577 version = pkg.version; 578 } 579 pkg; 580 581 }