Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at release-19.03 323 lines 13 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 (self) buildHaskellPackages ghc shellFor; 47 inherit (self.buildHaskellPackages) jailbreak-cabal; 48 hscolour = overrideCabal self.buildHaskellPackages.hscolour (drv: { 49 isLibrary = false; 50 doHaddock = false; 51 hyperlinkSource = false; # Avoid depending on hscolour for this build. 52 postFixup = "rm -rf $out/lib $out/share $out/nix-support"; 53 }); 54 cpphs = overrideCabal (self.cpphs.overrideScope (self: super: { 55 mkDerivation = drv: super.mkDerivation (drv // { 56 enableSharedExecutables = false; 57 enableSharedLibraries = false; 58 doHaddock = false; 59 useCpphs = false; 60 }); 61 })) (drv: { 62 isLibrary = false; 63 postFixup = "rm -rf $out/lib $out/share $out/nix-support"; 64 }); 65 }; 66 67 mkDerivation = makeOverridable mkDerivationImpl; 68 69 # manualArgs are the arguments that were explictly passed to `callPackage`, like: 70 # 71 # callPackage foo { bar = null; }; 72 # 73 # here `bar` is a manual argument. 74 callPackageWithScope = scope: fn: manualArgs: 75 let 76 # this code is copied from callPackage in lib/customisation.nix 77 # 78 # we cannot use `callPackage` here because we want to call `makeOverridable` 79 # on `drvScope` (we cannot add `overrideScope` after calling `callPackage` because then it is 80 # lost on `.override`) but determine the auto-args based on `drv` (the problem here 81 # is that nix has no way to "passthrough" args while preserving the reflection 82 # info that callPackage uses to determine the arguments). 83 drv = if stdenv.lib.isFunction fn then fn else import fn; 84 auto = builtins.intersectAttrs (stdenv.lib.functionArgs drv) scope; 85 86 # this wraps the `drv` function to add a `overrideScope` function to the result. 87 drvScope = allArgs: drv allArgs // { 88 overrideScope = f: 89 let newScope = mkScope (fix' (extends f scope.__unfix__)); 90 # note that we have to be careful here: `allArgs` includes the auto-arguments that 91 # weren't manually specified. If we would just pass `allArgs` to the recursive call here, 92 # then we wouldn't look up any packages in the scope in the next interation, because it 93 # appears as if all arguments were already manually passed, so the scope change would do 94 # nothing. 95 in callPackageWithScope newScope drv manualArgs; 96 }; 97 in stdenv.lib.makeOverridable drvScope (auto // manualArgs); 98 99 mkScope = scope: let 100 ps = pkgs.__splicedPackages; 101 scopeSpliced = pkgs.splicePackages { 102 pkgsBuildBuild = scope.buildHaskellPackages.buildHaskellPackages; 103 pkgsBuildHost = scope.buildHaskellPackages; 104 pkgsBuildTarget = {}; 105 pkgsHostHost = {}; 106 pkgsHostTarget = scope; 107 pkgsTargetTarget = {}; 108 } // { 109 # Don't splice these 110 inherit (scope) ghc buildHaskellPackages; 111 }; 112 in ps // ps.xorg // ps.gnome2 // { inherit stdenv; } // scopeSpliced; 113 defaultScope = mkScope self; 114 callPackage = drv: args: callPackageWithScope defaultScope drv args; 115 116 withPackages = packages: buildPackages.callPackage ./with-packages-wrapper.nix { 117 inherit (self) ghc llvmPackages; 118 inherit packages; 119 }; 120 121 haskellSrc2nix = { name, src, sha256 ? null, extraCabal2nixOptions ? "" }: 122 let 123 sha256Arg = if isNull sha256 then "--sha256=" else ''--sha256="${sha256}"''; 124 in pkgs.buildPackages.stdenv.mkDerivation { 125 name = "cabal2nix-${name}"; 126 nativeBuildInputs = [ pkgs.buildPackages.cabal2nix ]; 127 preferLocalBuild = true; 128 allowSubstitutes = false; 129 phases = ["installPhase"]; 130 LANG = "en_US.UTF-8"; 131 LOCALE_ARCHIVE = pkgs.lib.optionalString (buildPlatform.libc == "glibc") "${buildPackages.glibcLocales}/lib/locale/locale-archive"; 132 installPhase = '' 133 export HOME="$TMP" 134 mkdir -p "$out" 135 cabal2nix --compiler=${self.ghc.haskellCompilerName} --system=${hostPlatform.config} ${sha256Arg} "${src}" ${extraCabal2nixOptions} > "$out/default.nix" 136 ''; 137 }; 138 139 all-cabal-hashes-component = name: version: pkgs.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 (self.callPackage src args) (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 }); 170 171in package-set { inherit pkgs stdenv callPackage; } self // { 172 173 inherit mkDerivation callPackage haskellSrc2nix hackage2nix buildHaskellPackages; 174 175 inherit (haskellLib) packageSourceOverrides; 176 177 callHackage = name: version: callPackageKeepDeriver (self.hackage2nix name version); 178 179 # This function does not depend on all-cabal-hashes and therefore will work 180 # for any version that has been released on hackage as opposed to only 181 # versions released before whatever version of all-cabal-hashes you happen 182 # to be currently using. 183 callHackageDirect = {pkg, ver, sha256}@args: 184 let pkgver = "${pkg}-${ver}"; 185 in self.callCabal2nix pkg (pkgs.fetchzip { 186 url = "http://hackage.haskell.org/package/${pkgver}/${pkgver}.tar.gz"; 187 inherit sha256; 188 }); 189 190 # Creates a Haskell package from a source package by calling cabal2nix on the source. 191 callCabal2nixWithOptions = name: src: extraCabal2nixOptions: args: 192 let 193 filter = path: type: 194 pkgs.lib.hasSuffix "${name}.cabal" path || 195 baseNameOf path == "package.yaml"; 196 expr = self.haskellSrc2nix { 197 inherit name extraCabal2nixOptions; 198 src = if pkgs.lib.canCleanSource src 199 then pkgs.lib.cleanSourceWith { inherit src filter; } 200 else src; 201 }; 202 in overrideCabal (callPackageKeepDeriver expr args) (orig: { 203 inherit src; 204 }); 205 206 callCabal2nix = name: src: args: self.callCabal2nixWithOptions name src "" args; 207 208 # : { root : Path 209 # , name : Defaulted String 210 # , source-overrides : Defaulted (Either Path VersionNumber) 211 # , overrides : Defaulted (HaskellPackageOverrideSet) 212 # , modifier : Defaulted 213 # , returnShellEnv : Defaulted 214 # } -> NixShellAwareDerivation 215 # Given a path to a haskell package directory, an optional package name 216 # which defaults to the base name of the path, an optional set of source 217 # overrides as appropriate for the 'packageSourceOverrides' function, an 218 # optional set of arbitrary overrides, and an optional haskell package 219 # modifier, return a derivation appropriate for nix-build or nix-shell to 220 # build that package. 221 developPackage = 222 { root 223 , name ? builtins.baseNameOf root 224 , source-overrides ? {} 225 , overrides ? self: super: {} 226 , modifier ? drv: drv 227 , returnShellEnv ? pkgs.lib.inNixShell }: 228 let drv = 229 (extensible-self.extend 230 (pkgs.lib.composeExtensions 231 (self.packageSourceOverrides source-overrides) 232 overrides)) 233 .callCabal2nix name root {}; 234 in if returnShellEnv then (modifier drv).env else modifier drv; 235 236 ghcWithPackages = selectFrom: withPackages (selectFrom self); 237 238 ghcWithHoogle = selectFrom: 239 let 240 packages = selectFrom self; 241 hoogle = callPackage ./hoogle.nix { 242 inherit packages; 243 }; 244 in withPackages (packages ++ [ hoogle ]); 245 246 # Returns a derivation whose environment contains a GHC with only 247 # the dependencies of packages listed in `packages`, not the 248 # packages themselves. Using nix-shell on this derivation will 249 # give you an environment suitable for developing the listed 250 # packages with an incremental tool like cabal-install. 251 # 252 # # default.nix 253 # with import <nixpkgs> {}; 254 # haskellPackages.extend (haskell.lib.packageSourceOverrides { 255 # frontend = ./frontend; 256 # backend = ./backend; 257 # common = ./common; 258 # }) 259 # 260 # # shell.nix 261 # (import ./.).shellFor { 262 # packages = p: [p.frontend p.backend p.common]; 263 # withHoogle = true; 264 # } 265 # 266 # -- cabal.project 267 # packages: 268 # frontend/ 269 # backend/ 270 # common/ 271 # 272 # bash$ nix-shell --run "cabal new-build all" 273 shellFor = { packages, withHoogle ? false, ... } @ args: 274 let 275 selected = packages self; 276 277 packageInputs = map getBuildInputs selected; 278 279 name = if pkgs.lib.length selected == 1 280 then "ghc-shell-for-${(pkgs.lib.head selected).name}" 281 else "ghc-shell-for-packages"; 282 283 # If `packages = [ a b ]` and `a` depends on `b`, don't build `b`, 284 # because cabal will end up ignoring that built version, assuming 285 # new-style commands. 286 haskellInputs = pkgs.lib.filter 287 (input: pkgs.lib.all (p: input.outPath != p.outPath) selected) 288 (pkgs.lib.concatMap (p: p.haskellBuildInputs) packageInputs); 289 systemInputs = pkgs.lib.concatMap (p: p.systemBuildInputs) packageInputs; 290 291 withPackages = if withHoogle then self.ghcWithHoogle else self.ghcWithPackages; 292 ghcEnv = withPackages (p: haskellInputs); 293 nativeBuildInputs = pkgs.lib.concatMap (p: p.nativeBuildInputs) selected; 294 295 ghcCommand' = if ghc.isGhcjs or false then "ghcjs" else "ghc"; 296 ghcCommand = "${ghc.targetPrefix}${ghcCommand'}"; 297 ghcCommandCaps= pkgs.lib.toUpper ghcCommand'; 298 299 mkDrvArgs = builtins.removeAttrs args ["packages" "withHoogle"]; 300 in pkgs.stdenv.mkDerivation (mkDrvArgs // { 301 name = mkDrvArgs.name or name; 302 303 buildInputs = systemInputs ++ mkDrvArgs.buildInputs or []; 304 nativeBuildInputs = [ ghcEnv ] ++ nativeBuildInputs ++ mkDrvArgs.nativeBuildInputs or []; 305 phases = ["installPhase"]; 306 installPhase = "echo $nativeBuildInputs $buildInputs > $out"; 307 LANG = "en_US.UTF-8"; 308 LOCALE_ARCHIVE = pkgs.lib.optionalString (stdenv.hostPlatform.libc == "glibc") "${buildPackages.glibcLocales}/lib/locale/locale-archive"; 309 "NIX_${ghcCommandCaps}" = "${ghcEnv}/bin/${ghcCommand}"; 310 "NIX_${ghcCommandCaps}PKG" = "${ghcEnv}/bin/${ghcCommand}-pkg"; 311 # TODO: is this still valid? 312 "NIX_${ghcCommandCaps}_DOCDIR" = "${ghcEnv}/share/doc/ghc/html"; 313 "NIX_${ghcCommandCaps}_LIBDIR" = if ghc.isHaLVM or false 314 then "${ghcEnv}/lib/HaLVM-${ghc.version}" 315 else "${ghcEnv}/lib/${ghcCommand}-${ghc.version}"; 316 }); 317 318 ghc = ghc // { 319 withPackages = self.ghcWithPackages; 320 withHoogle = self.ghcWithHoogle; 321 }; 322 323 }