Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at release-18.03 252 lines 9.9 kB view raw
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 to use for building haskell packages 15 stdenv 16 17, haskellLib 18 19, # hashes for downloading Hackage packages 20 all-cabal-hashes 21 22, # compiler to use 23 ghc 24 25, # A function that takes `{ pkgs, stdenv, callPackage }` as the first arg and 26 # `self` as second, and returns a set of haskell packages 27 package-set 28 29, # The final, fully overriden package set usable with the nixpkgs fixpoint 30 # overriding functionality 31 extensible-self 32}: 33 34# return value: a function from self to the package set 35self: 36 37let 38 inherit (stdenv) buildPlatform hostPlatform; 39 40 inherit (stdenv.lib) fix' extends makeOverridable; 41 inherit (haskellLib) overrideCabal getBuildInputs; 42 43 mkDerivationImpl = pkgs.callPackage ./generic-builder.nix { 44 inherit stdenv; 45 nodejs = buildPackages.nodejs-slim; 46 inherit buildHaskellPackages; 47 inherit (self) ghc; 48 inherit (buildHaskellPackages) jailbreak-cabal; 49 hscolour = overrideCabal buildHaskellPackages.hscolour (drv: { 50 isLibrary = false; 51 doHaddock = false; 52 hyperlinkSource = false; # Avoid depending on hscolour for this build. 53 postFixup = "rm -rf $out/lib $out/share $out/nix-support"; 54 }); 55 cpphs = overrideCabal (self.cpphs.overrideScope (self: super: { 56 mkDerivation = drv: super.mkDerivation (drv // { 57 enableSharedExecutables = false; 58 enableSharedLibraries = false; 59 doHaddock = false; 60 useCpphs = false; 61 }); 62 })) (drv: { 63 isLibrary = false; 64 postFixup = "rm -rf $out/lib $out/share $out/nix-support"; 65 }); 66 }; 67 68 mkDerivation = makeOverridable mkDerivationImpl; 69 70 # manualArgs are the arguments that were explictly passed to `callPackage`, like: 71 # 72 # callPackage foo { bar = null; }; 73 # 74 # here `bar` is a manual argument. 75 callPackageWithScope = scope: fn: manualArgs: 76 let 77 # this code is copied from callPackage in lib/customisation.nix 78 # 79 # we cannot use `callPackage` here because we want to call `makeOverridable` 80 # on `drvScope` (we cannot add `overrideScope` after calling `callPackage` because then it is 81 # lost on `.override`) but determine the auto-args based on `drv` (the problem here 82 # is that nix has no way to "passthrough" args while preserving the reflection 83 # info that callPackage uses to determine the arguments). 84 drv = if stdenv.lib.isFunction fn then fn else import fn; 85 auto = builtins.intersectAttrs (stdenv.lib.functionArgs drv) scope; 86 87 # this wraps the `drv` function to add a `overrideScope` function to the result. 88 drvScope = allArgs: drv allArgs // { 89 overrideScope = f: 90 let newScope = mkScope (fix' (extends f scope.__unfix__)); 91 # note that we have to be careful here: `allArgs` includes the auto-arguments that 92 # weren't manually specified. If we would just pass `allArgs` to the recursive call here, 93 # then we wouldn't look up any packages in the scope in the next interation, because it 94 # appears as if all arguments were already manually passed, so the scope change would do 95 # nothing. 96 in callPackageWithScope newScope drv manualArgs; 97 }; 98 in stdenv.lib.makeOverridable drvScope (auto // manualArgs); 99 100 mkScope = scope: pkgs // pkgs.xorg // pkgs.gnome2 // { inherit stdenv; } // scope; 101 defaultScope = mkScope self; 102 callPackage = drv: args: callPackageWithScope defaultScope drv args; 103 104 withPackages = packages: buildPackages.callPackage ./with-packages-wrapper.nix { 105 inherit (self) ghc llvmPackages; 106 inherit packages; 107 }; 108 109 haskellSrc2nix = { name, src, sha256 ? null, extraCabal2nixOptions ? "" }: 110 let 111 sha256Arg = if isNull sha256 then "--sha256=" else ''--sha256="${sha256}"''; 112 in pkgs.buildPackages.stdenv.mkDerivation { 113 name = "cabal2nix-${name}"; 114 nativeBuildInputs = [ pkgs.buildPackages.cabal2nix ]; 115 preferLocalBuild = true; 116 phases = ["installPhase"]; 117 LANG = "en_US.UTF-8"; 118 LOCALE_ARCHIVE = pkgs.lib.optionalString buildPlatform.isLinux "${buildPackages.glibcLocales}/lib/locale/locale-archive"; 119 installPhase = '' 120 export HOME="$TMP" 121 mkdir -p "$out" 122 cabal2nix --compiler=${self.ghc.haskellCompilerName} --system=${hostPlatform.system} ${sha256Arg} "${src}" ${extraCabal2nixOptions} > "$out/default.nix" 123 ''; 124 }; 125 126 all-cabal-hashes-component = name: version: pkgs.runCommand "all-cabal-hashes-component-${name}-${version}" {} '' 127 tar --wildcards -xzvf ${all-cabal-hashes} \*/${name}/${version}/${name}.{json,cabal} 128 mkdir -p $out 129 mv */${name}/${version}/${name}.{json,cabal} $out 130 ''; 131 132 hackage2nix = name: version: let component = all-cabal-hashes-component name version; in self.haskellSrc2nix { 133 name = "${name}-${version}"; 134 sha256 = ''$(sed -e 's/.*"SHA256":"//' -e 's/".*$//' "${component}/${name}.json")''; 135 src = "${component}/${name}.cabal"; 136 }; 137 138 # Adds a nix file as an input to the haskell derivation it 139 # produces. This is useful for callHackage / callCabal2nix to 140 # prevent the generated default.nix from being garbage collected 141 # (requiring it to be frequently rebuilt), which can be an 142 # annoyance. 143 callPackageKeepDeriver = src: args: 144 overrideCabal (self.callPackage src args) (orig: { 145 preConfigure = '' 146 # Generated from ${src} 147 ${orig.preConfigure or ""} 148 ''; 149 }); 150 151in package-set { inherit pkgs stdenv callPackage; } self // { 152 153 inherit mkDerivation callPackage haskellSrc2nix hackage2nix; 154 155 inherit (haskellLib) packageSourceOverrides; 156 157 callHackage = name: version: callPackageKeepDeriver (self.hackage2nix name version); 158 159 # Creates a Haskell package from a source package by calling cabal2nix on the source. 160 callCabal2nix = name: src: args: let 161 filter = path: type: 162 pkgs.lib.hasSuffix "${name}.cabal" path || 163 baseNameOf path == "package.yaml"; 164 expr = self.haskellSrc2nix { 165 inherit name; 166 src = if pkgs.lib.canCleanSource src 167 then pkgs.lib.cleanSourceWith { inherit src filter; } 168 else src; 169 }; 170 in overrideCabal (callPackageKeepDeriver expr args) (orig: { 171 inherit src; 172 }); 173 174 # : { root : Path 175 # , source-overrides : Defaulted (Either Path VersionNumber) 176 # , overrides : Defaulted (HaskellPackageOverrideSet) 177 # , modifier : Defaulted 178 # } -> NixShellAwareDerivation 179 # Given a path to a haskell package directory whose cabal file is 180 # named the same as the directory name, an optional set of 181 # source overrides as appropriate for the 'packageSourceOverrides' 182 # function, an optional set of arbitrary overrides, and an optional 183 # haskell package modifier, return a derivation appropriate 184 # for nix-build or nix-shell to build that package. 185 developPackage = { root, source-overrides ? {}, overrides ? self: super: {}, modifier ? drv: drv }: 186 let name = builtins.baseNameOf root; 187 drv = 188 (extensible-self.extend (pkgs.lib.composeExtensions (self.packageSourceOverrides source-overrides) overrides)).callCabal2nix name root {}; 189 in if pkgs.lib.inNixShell then (modifier drv).env else modifier drv; 190 191 ghcWithPackages = selectFrom: withPackages (selectFrom self); 192 193 ghcWithHoogle = selectFrom: 194 let 195 packages = selectFrom self; 196 hoogle = callPackage ./hoogle.nix { 197 inherit packages; 198 }; 199 in withPackages (packages ++ [ hoogle ]); 200 201 # Returns a derivation whose environment contains a GHC with only 202 # the dependencies of packages listed in `packages`, not the 203 # packages themselves. Using nix-shell on this derivation will 204 # give you an environment suitable for developing the listed 205 # packages with an incremental tool like cabal-install. 206 # 207 # # default.nix 208 # with import <nixpkgs> {}; 209 # haskellPackages.extend (haskell.lib.packageSourceOverrides { 210 # frontend = ./frontend; 211 # backend = ./backend; 212 # common = ./common; 213 # }) 214 # 215 # # shell.nix 216 # (import ./.).shellFor { 217 # packages = p: [p.frontend p.backend p.common]; 218 # withHoogle = true; 219 # } 220 # 221 # -- cabal.project 222 # packages: 223 # frontend/ 224 # backend/ 225 # common/ 226 # 227 # bash$ nix-shell --run "cabal new-build all" 228 shellFor = { packages, withHoogle ? false, ... } @ args: 229 let 230 selected = packages self; 231 packageInputs = builtins.map getBuildInputs selected; 232 haskellInputs = 233 builtins.filter 234 (input: pkgs.lib.all (p: input.outPath != p.outPath) selected) 235 (pkgs.lib.concatMap (p: p.haskellBuildInputs) packageInputs); 236 systemInputs = pkgs.lib.concatMap (p: p.systemBuildInputs) packageInputs; 237 withPackages = if withHoogle then self.ghcWithHoogle else self.ghcWithPackages; 238 mkDrvArgs = builtins.removeAttrs args ["packages" "withHoogle"]; 239 in pkgs.stdenv.mkDerivation (mkDrvArgs // { 240 name = "ghc-shell-for-packages"; 241 nativeBuildInputs = [(withPackages (_: haskellInputs))] ++ mkDrvArgs.nativeBuildInputs or []; 242 buildInputs = systemInputs ++ mkDrvArgs.buildInputs or []; 243 phases = ["installPhase"]; 244 installPhase = "echo $nativeBuildInputs $buildInputs > $out"; 245 }); 246 247 ghc = ghc // { 248 withPackages = self.ghcWithPackages; 249 withHoogle = self.ghcWithHoogle; 250 }; 251 252 }