1{ lib, stdenv, mkShell, glibcLocales, pkgconfig, ghcForComponent, makeConfigFiles, hsPkgs, hoogleLocal, haskellLib, buildPackages, compiler }:
3{ # `packages` function selects packages that will be worked on in the shell itself.
4 # These packages will not be built by `shellFor`, but their
5 # dependencies will be included in the shell's `ghc-pkg list`.
6 packages ? ps: builtins.attrValues (haskellLib.selectLocalPackages ps)
7 # `components` function selects components that will be worked on in the shell itself.
8 # By default `shellFor` will include the dependencies of all of the components
9 # in the selected packages. If only as subset of the components will be
10 # worked on in the shell then we can pass a different `components` function
12, components ? ps: lib.concatMap haskellLib.getAllComponents (packages ps)
13 # Additional packages to be added unconditionally
18, packageSetupDeps ? true
23 # TODO find out why hoogle index creation can be made to work for cross compilers
24 withHoogle' = withHoogle && !haskellLib.isCrossHost;
26 selectedPackages = packages hsPkgs;
27 additionalPackages = additional hsPkgs;
28 directlySelectedComponents = components hsPkgs;
30 # Given `directlySelectedComponents = [ a b ]`, we construct a shell that includes all of their dependencies
32 # But we want to exclude `a` if it is a transitive dependecy of `b`
34 # - cabal will end up ignoring that built version;
35 # - The user has indicated that's what they're working on, so they probably don't want to have to build
36 # it first (and it will change often).
37 # Generally we never want to include any of `directlySelectedComponents` as dependencies.
39 # We do this by defining a set of `selectedComponents`, where `x` is in `selectedComponents` if and only if:
40 # - `x` is in `directlySelectedComponents`
41 # - `x` is a transitive dependency of something in `directlySelectedComponents`
42 # and `x` transitively depends on something in `directlySelectedComponents`
43 # We use the dependencies of `selectedComponents` filtering out members of `selectedComponents`
45 # Furthermore, if `a` depends on `b`, `a` will include the library component of `b` in its `buildInputs`
46 # (to make `propagatedBuildInputs` of `pkgconfig-depends` work). So we also need to filter those
47 # (the pkgconfig depends of `b` will still be included in the
48 # system shell's `buildInputs` via `b`'s own `buildInputs`).
51 # all packages that are indirectly depended on by `directlySelectedComponents`
52 # including `directlySelectedComponents`
53 transitiveDependenciesComponents =
55 (builtins.map (x: lib.nameValuePair (x.name) x)
56 (haskellLib.flatLibDepends {depends = directlySelectedComponents;}));
59 comp: selectedComponentsBitmap."${((haskellLib.dependToLib comp).name or null)}" or false;
60 selectedComponentsBitmap =
62 (_: x: (builtins.any isSelectedComponent x.config.depends))
63 transitiveDependenciesComponents
64 // builtins.listToAttrs (map (x: lib.nameValuePair x.name true) directlySelectedComponents); # base case
67 lib.filter isSelectedComponent (lib.attrValues transitiveDependenciesComponents);
69 # Given a list of `depends`, removes those which are selected components
70 removeSelectedInputs =
71 lib.filter (input: !(isSelectedComponent input));
73 # The configs of all the selected components
74 selectedConfigs = map (c: c.config) selectedComponents
75 ++ lib.optionals packageSetupDeps (map (p: p.setup.config) selectedPackages);
77 name = if lib.length selectedPackages == 1
78 then "ghc-shell-for-${(lib.head selectedPackages).identifier.name}"
79 else "ghc-shell-for-packages";
81 # We need to remove any dependencies which would bring in selected components (see above).
82 packageInputs = removeSelectedInputs (lib.concatMap (cfg: cfg.depends) selectedConfigs)
83 ++ additionalPackages;
85 # Add the system libraries and build tools of the selected haskell packages to the shell.
86 # We need to remove any inputs which are selected components (see above).
87 # `buildInputs`, `propagatedBuildInputs`, and `executableToolDepends` contain component
88 # derivations, not packages, so we use `removeSelectedInputs`).
89 systemInputs = removeSelectedInputs (lib.concatMap
90 (c: c.buildInputs ++ c.propagatedBuildInputs) selectedComponents);
91 nativeBuildInputs = removeSelectedInputs
92 (lib.concatMap (c: c.executableToolDepends) selectedComponents);
94 # Set up a "dummy" component to use with ghcForComponent.
96 depends = packageInputs;
99 doExactConfig = false;
101 configFiles = makeConfigFiles {
102 fullName = args.name or name;
103 identifier.name = name;
106 ghcEnv = ghcForComponent {
108 componentName = name;
109 postInstall = lib.optionalString withHoogle' ''
110 ln -s ${hoogleIndex}/bin/hoogle $out/bin
116 # Get the doc package for a component, and add attributes that
117 # hoogle.nix expects.
118 docPackage = p: lib.getOutput "doc" p // {
119 pname = p.identifier.name;
120 haddockDir = lib.const p.haddockDir;
123 packages = map docPackage (haskellLib.flatLibDepends component);
125 # Need to add hoogle to hsPkgs.
126 # inherit (hsPkgs) hoogle;
128 lib.optionalAttrs (args ? tools && args.tools ? hoogle) {
129 hoogle = buildPackages.haskell-nix.tool compiler.nix-name "hoogle" args.tools.hoogle;
133 mkDrvArgs = builtins.removeAttrs args ["packages" "components" "additional" "withHoogle" "tools"];
135 mkShell (mkDrvArgs // {
136 name = mkDrvArgs.name or name;
138 buildInputs = systemInputs
139 ++ mkDrvArgs.buildInputs or [];
140 nativeBuildInputs = [ ghcEnv ]
142 ++ mkDrvArgs.nativeBuildInputs or []
143 ++ lib.attrValues (buildPackages.haskell-nix.tools compiler.nix-name tools)
144 # If this shell is a cross compilation shell include
145 # wrapper script for running cabal build with appropriate args.
146 # Includes `--with-compiler` in case the `cabal.project` file has `with-compiler:` in it.
147 ++ lib.optional (ghcEnv.targetPrefix != "") (
148 buildPackages.writeShellScriptBin "${ghcEnv.targetPrefix}cabal" ''
150 --with-ghc=${ghcEnv.targetPrefix}ghc \
151 --with-compiler=${ghcEnv.targetPrefix}ghc \
152 --with-ghc-pkg=${ghcEnv.targetPrefix}ghc-pkg \
153 --with-hsc2hs=${ghcEnv.targetPrefix}hsc2hs \
154 ${lib.optionalString (ghcEnv.targetPrefix == "js-unknown-ghcjs-") ''
155 --with-ghcjs=${ghcEnv.targetPrefix}ghc \
156 --with-ghcjs-pkg=${ghcEnv.targetPrefix}ghc-pkg \
158 ''} $(builtin type -P "${ghcEnv.targetPrefix}pkg-config" &> /dev/null && echo "--with-pkg-config=${ghcEnv.targetPrefix}pkg-config") \
161 phases = ["installPhase"];
163 echo "${"Shell for " + toString (builtins.map (p : p.identifier.name) selectedPackages)}"
164 echo $nativeBuildInputs $buildInputs > $out
166 LANG = "en_US.UTF-8";
167 LOCALE_ARCHIVE = lib.optionalString (stdenv.hostPlatform.libc == "glibc") "${glibcLocales}/lib/locale/locale-archive";
169 # This helps tools like `ghcide` (that use the ghc api) to find
170 # the correct global package DB.
171 NIX_GHC_LIBDIR = ghcEnv + "/" + configFiles.libDir;
173 passthru = (mkDrvArgs.passthru or {}) // {
177 } // lib.optionalAttrs exactDeps {
178 CABAL_CONFIG = "${configFiles}/cabal.config";
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list