Skip to content

Commit b4a36e9

Browse files
committed
Store default setup on ghc derivation
This gives us a way to look up the same derivation rather than recomputing the same derivation multiple times. This gives a 5% to 10% improvement in eval time. Measured with: ``` time nix-instantiate -E '(import ./. {}).pkgs-unstable.haskell-nix.tool "ghc8107" "haskell-language-server" {}' ```
1 parent 05c0555 commit b4a36e9

File tree

3 files changed

+114
-70
lines changed

3 files changed

+114
-70
lines changed

builder/hspkg-builder.nix

Lines changed: 1 addition & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -39,77 +39,8 @@ let
3939

4040
defaultSetupSrc = if stdenv.hostPlatform.isGhcjs then ./Setup.ghcjs.hs else ./Setup.hs;
4141

42-
# This is the `Cabal` library that was built for `cabal-install` to use.
43-
# It makes sense to use this version (when possible) because it will match the behavior of
44-
# building with `cabal-install` (including fixes that may not be in the
45-
# version of Cabal bundled with GHC).
46-
cabalFromCabalInstall = buildPackages.haskell-nix.cabal-install-unchecked.${compiler-nix-name}.project.hsPkgs.Cabal.components.library;
47-
48-
# Check there is no chance we are building `cabalFromCabalInstall`. Using `cabalFromCabalInstall`
49-
# to build itseld would cause infinite recursion.
50-
useCabalFromCabalInstall =
51-
# `cabalFromCabalInstall` is not cross compiled
52-
stdenv.buildPlatform != stdenv.hostPlatform
53-
||
54-
# These are the dependencies of `Cabal`
55-
!builtins.elem package.identifier.name
56-
["nix-tools" "alex" "happy" "hscolour" "Cabal" "bytestring" "aeson" "time"
57-
"filepath" "base-compat-batteries" "base-compat" "unix" "directory" "transformers"
58-
"containers" "binary" "mtl" "text" "process" "parsec"];
59-
60-
defaultSetup = setup-builder ({
61-
name = "${ghc.targetPrefix}default-Setup";
62-
component = {
63-
depends = config.setup-depends ++ lib.optional useCabalFromCabalInstall cabalFromCabalInstall;
64-
libs = [];
65-
frameworks = [];
66-
doExactConfig = false;
67-
includeDirs = [];
68-
asmSources = [];
69-
cSources = [];
70-
cmmSources = [];
71-
cxxSources = [];
72-
jsSources = [];
73-
extraSrcFiles = [ "Setup.hs" "Setup.lhs" ];
74-
pkgconfig = [];
75-
build-tools = [];
76-
77-
platforms = null;
78-
preBuild = null; postBuild = null;
79-
preInstall = null; postInstall = null;
80-
preUnpack = null; postUnpack = null;
81-
};
82-
package = {
83-
identifier = {
84-
name = "default-Setup";
85-
version = "1.0";
86-
};
87-
homepage = null;
88-
synopsis = null;
89-
license = "MIT";
90-
};
91-
src = null;
92-
cleanSrc = buildPackages.runCommand "default-Setup-src" {} ''
93-
mkdir $out
94-
cat ${defaultSetupSrc} > $out/Setup.hs
95-
'';
96-
inherit defaultSetupSrc;
97-
} // lib.optionalAttrs useCabalFromCabalInstall {
98-
# This is needed so that we don't get duplicate packages when we
99-
# add a custom Cabal package to the dependencies. That way custom
100-
# setups won't complain about e.g. binary from the Cabal dependencies
101-
# and binary from the global package-db.
102-
nonReinstallablePkgs = [];
103-
});
104-
105-
# buildPackages.runCommand "default-Setup" { nativeBuildInputs = [(ghc.passthru.buildGHC or ghc)]; } ''
106-
# cat ${defaultSetupSrc} > Setup.hs
107-
# mkdir -p $out/bin
108-
# ${(ghc.passthru.buildGHC or ghc).targetPrefix}ghc Setup.hs --make -o $out/bin/Setup
109-
# '';
110-
11142
setup = if package.buildType == "Simple"
112-
then defaultSetup
43+
then ghc.defaultSetupFor package.identifier.name
11344
else setup-builder {
11445
component = components.setup // {
11546
depends = config.setup-depends ++ components.setup.depends ++ package.setup-depends;

overlays/default-setup.nix

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# This overlay adds the two versions of the default setup
2+
# exe to the ghc derivations (one using the latest Cabal and
3+
# one using the GHC provided Cabal). These are then used
4+
# when a package has the `Simple` build type. Storing them
5+
# on the GHC derivation means that nix eval does not have
6+
# to compute the same derivation multiple times.
7+
final: prev:
8+
let
9+
nonReinstallablePkgs = [];
10+
haskellLib = final.haskell-nix.haskellLib;
11+
defaultSetupSrc =
12+
if final.stdenv.hostPlatform.isGhcjs
13+
then ../builder/Setup.ghcjs.hs
14+
else ../builder/Setup.hs;
15+
addDefaultSetup = compiler-nix-name: ghc:
16+
let
17+
# When building setup depends we need to use the build systems GHC and Packages
18+
makeSetupConfigFiles = haskellLib.weakCallPackage final.buildPackages ../builder/make-config-files.nix {
19+
inherit haskellLib nonReinstallablePkgs;
20+
ghc = (ghc.passthru.buildGHC or ghc);
21+
};
22+
setup-builder = haskellLib.weakCallPackage final ../builder/setup-builder.nix {
23+
ghc = (ghc.passthru.buildGHC or ghc);
24+
hsPkgs = {};
25+
# We need to use the buildPackages stdenv to build the setup-builder.
26+
# in the native case, it would be the same in the cross case however
27+
# we *really* want to build the Setup.hs on the build machine and not
28+
# have the stdenv confuse it with the target/host env.
29+
inherit (final.buildPackages) stdenv pkgconfig;
30+
inherit (final) buildPackages;
31+
inherit haskellLib nonReinstallablePkgs makeSetupConfigFiles;
32+
};
33+
34+
# This is the `Cabal` library that was built for `cabal-install` to use.
35+
# It makes sense to use this version (when possible) because it will match the behavior of
36+
# building with `cabal-install` (including fixes that may not be in the
37+
# version of Cabal bundled with GHC).
38+
cabalFromCabalInstall = final.buildPackages.haskell-nix.cabal-install-unchecked.${compiler-nix-name}.project.hsPkgs.Cabal.components.library;
39+
40+
in ghc // rec {
41+
defaultSetup = final.lib.mapAttrs (_: useCabalFromCabalInstall: setup-builder ({
42+
name = "${ghc.targetPrefix}default-Setup";
43+
component = {
44+
depends = final.lib.optional useCabalFromCabalInstall cabalFromCabalInstall;
45+
libs = [];
46+
frameworks = [];
47+
doExactConfig = false;
48+
includeDirs = [];
49+
asmSources = [];
50+
cSources = [];
51+
cmmSources = [];
52+
cxxSources = [];
53+
jsSources = [];
54+
extraSrcFiles = [ "Setup.hs" "Setup.lhs" ];
55+
pkgconfig = [];
56+
build-tools = [];
57+
58+
platforms = null;
59+
preBuild = null; postBuild = null;
60+
preInstall = null; postInstall = null;
61+
preUnpack = null; postUnpack = null;
62+
};
63+
package = {
64+
identifier = {
65+
name = "default-Setup";
66+
version = "1.0";
67+
};
68+
homepage = null;
69+
synopsis = null;
70+
license = "MIT";
71+
};
72+
src = null;
73+
cleanSrc = final.buildPackages.runCommand "default-Setup-src" {} ''
74+
mkdir $out
75+
cat ${defaultSetupSrc} > $out/Setup.hs
76+
'';
77+
inherit defaultSetupSrc;
78+
} // final.lib.optionalAttrs useCabalFromCabalInstall {
79+
# This is needed so that we don't get duplicate packages when we
80+
# add a custom Cabal package to the dependencies. That way custom
81+
# setups won't complain about e.g. binary from the Cabal dependencies
82+
# and binary from the global package-db.
83+
nonReinstallablePkgs = [];
84+
})) {
85+
useCabalFromCabalInstall = true;
86+
useCabalFromGHC = false;
87+
};
88+
89+
# Check there is no chance we are building `cabalFromCabalInstall`. Using `cabalFromCabalInstall`
90+
# to build itself would cause infinite recursion.
91+
defaultSetupFor = packageName:
92+
if
93+
# `cabalFromCabalInstall` is not cross compiled
94+
final.stdenv.buildPlatform != final.stdenv.hostPlatform
95+
||
96+
# These are the dependencies of `Cabal`
97+
!builtins.elem packageName
98+
["nix-tools" "alex" "happy" "hscolour" "Cabal" "bytestring" "aeson" "time"
99+
"filepath" "base-compat-batteries" "base-compat" "unix" "directory" "transformers"
100+
"containers" "binary" "mtl" "text" "process" "parsec"]
101+
then defaultSetup.useCabalFromCabalInstall
102+
else defaultSetup.useCabalFromGHC;
103+
};
104+
in {
105+
haskell-nix = prev.haskell-nix // {
106+
compiler = final.lib.mapAttrs addDefaultSetup prev.haskell-nix.compiler;
107+
bootstrap = prev.haskell-nix.bootstrap // {
108+
compiler = final.lib.mapAttrs addDefaultSetup prev.haskell-nix.bootstrap.compiler;
109+
};
110+
};
111+
}

overlays/default.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ let
2121
gobject-introspection = import ./gobject-introspection.nix;
2222
hix = import ./hix.nix;
2323
ghcjs = import ./ghcjs.nix;
24+
default-setup = import ./default-setup.nix;
2425
};
2526

2627
composeExtensions = f: g: final: prev:
@@ -54,6 +55,7 @@ let
5455
gobject-introspection
5556
hix
5657
hydra
58+
default-setup
5759
# Restore nixpkgs haskell and haskellPackages
5860
(_: prev: { inherit (prev.haskell-nix-prev) haskell haskellPackages; })
5961
];

0 commit comments

Comments
 (0)