-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathpackage-set.nix
219 lines (196 loc) · 9.66 KB
/
package-set.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
{ lts-def
, pkgs ? import <nixpkgs> {}
, hackage ? import <hackage>
, haskell ? import <haskell> }:
{ extraDeps ? hsPkgs: {} }:
let
# packages that we must never try to reinstal.
nonReinstallablePkgs = [ "rts" "ghc" "ghc-prim" "integer-gmp" "integer-simple" "base"
"Win32" "process" "deepseq" "array" "directory" "time" "unix"
"filepath" "bytestring" "ghci" "binary" "containers"];
hackagePkgs = with pkgs.lib;
let shippedPkgs = filterAttrs (n: _: builtins.elem n nonReinstallablePkgs)
(mapAttrs (name: version: { ${version} = null; })
(lts-def {}).compiler.packages);
in recursiveUpdate hackage.exprs shippedPkgs;
# We may depend on packages shipped with ghc, or need to rebuild them.
ghcPackages = pkgs.lib.mapAttrs (name: version: hackagePkgs.${name}.${version}
) (lts-def {}).compiler.packages;
# Thus the final package set in our augmented (extrDeps) lts set is the following:
ltsPkgs = ghcPackages
// (lts-def hackagePkgs).packages
// extraDeps hackagePkgs;
driver = haskell.compat.driver;
host-map = haskell.compat.host-map;
# compiler this lts set is built against.
compiler = pkgs.haskell.packages.${(lts-def {}).compiler.nix-name};
# This is a tiny bit better than doJailbreak.
#
# We essentially *know* the dependencies, and with the
# full cabal file representation, we also know all the
# flags. As such we can sidestep the solver.
#
# Pros:
# - no need for doJailbreak
# - no need for jailbreak-cabal to be built with
# Cabal2 if the cabal file requires it.
# - no reliance on --allow-newer, which only made
# a very short lived appearance in Cabal.
# (Cabal-2.0.0.2 -- Cabal-2.2.0.0)
#
# Cons:
# - automatic flag resolution won't happen and will
# have to be hard coded.
#
# Ideally we'd just inspect the haskell*Depends fields
# we feed the builder. However because we null out the
# lirbaries ghc ships (e.g. base, ghc, ...) this would
# result in an incomplete --dependency=<name>=<name>-<version>
# set and not lead to the desired outcome.
#
# If we could still have base, etc. not nulled, but
# produce some virtual derivation, that might allow us
# to just use the haskell*Depends fields to extract the
# name and version for each dependency.
#
# Ref: https://github.com/haskell/cabal/issues/3163#issuecomment-185833150
# ---
# ghc-pkg should be ${ghcCommand}-pkg; and --package-db
# should better be --${packageDbFlag}; but we don't have
# those variables in scope.
doExactConfig = pkgs: pkg: let targetPrefix = with pkgs.stdenv; lib.optionalString
(hostPlatform != buildPlatform)
"${hostPlatform.config}-";
in pkgs.haskell.lib.overrideCabal pkg (drv: {
# TODO: need to run `ghc-pkg field <pkg> id` over all `--dependency`
# values. Should we encode the `id` in the nix-pkg as well?
preConfigure = (drv.preConfigure or "") + ''
configureFlags+=" --exact-configuration"
globalPackages=$(${targetPrefix}ghc-pkg list --global --simple-output)
localPackages=$(${targetPrefix}ghc-pkg --package-db="$packageConfDir" list --simple-output)
for pkg in $globalPackages; do
pkgName=''${pkg%-*}
if [ "$pkgName" != "rts" ]; then
if [[ " ${pkgs.lib.concatStringsSep " " nonReinstallablePkgs} " =~ " $pkgName " ]]; then
configureFlags+=" --dependency="''${pkg%-*}=$pkg
fi
fi
done
for pkg in $localPackages; do
configureFlags+=" --dependency="''${pkg%-*}=$pkg
done
#echo "<<< <<< <<<"
#echo ''${configureFlags}
configureFlags=$(for flag in ''${configureFlags};do case "X''${flag}" in
X--dependency=*)
pkgId=$(${targetPrefix}ghc-pkg --package-db="$packageConfDir" field ''${flag##*=} id || ${targetPrefix}ghc-pkg --global field ''${flag##*=} id)
echo ''${flag%=*}=$(echo $pkgId | awk -F' ' '{ print $2 }')
;;
*) echo ''${flag};;
esac; done)
#echo "--- --- ---"
#echo ''${configureFlags}
#echo ">>> >>> >>>"
'';
});
doAllowNewer = pkg: pkgs.haskell.lib.appendConfigureFlag pkg "--allow-newer";
# # fetch a package candidate from hackage and return the cabal2nix expression.
# hackageCandidate = name: ver: args: self.callCabal2nix name (fetchTarball "https://hackage.haskell.org/package/${name}-${ver}/candidate/${name}-${ver}.tar.gz") args;
# # iserv logic
# libiserv = with haskell.lib; addExtraLibrary (enableCabalFlag (self.hackageCandidate "libiserv" "8.5" {}) "network") self.network;
# iserv-proxy = self.hackageCandidate "iserv-proxy" "8.5" { libiserv = self.libiserv; };
# # TODO: Why is `network` not properly propagated from `libiserv`?
# remote-iserv = with haskell.lib; let pkg = addExtraLibrary (self.hackageCandidate "remote-iserv" "8.5" { libiserv = self.libiserv; }) self.network; in
# overrideCabal (addBuildDepends pkg [ windows.mingw_w64_pthreads ]) (drv: {
# postInstall = ''
# cp ${windows.mingw_w64_pthreads}/bin/libwinpthread-1.dll $out/bin/
# '';
# });
# fast -- the logic is as follows:
# - test are often broken and we have a curated set
# thus, let us assume we don't need no tests. (also time consuming)
# - haddocks are not used, and sometimes fail. (also time consuming)
# - The curated set has proper version bounds, so we can just
# exactConfig globally
fast = pkgs: drv: with pkgs.haskell.lib;
(doExactConfig pkgs
(disableSharedLibraries
(disableSharedExecutables
(disableLibraryProfiling
(disableExecutableProfiling
(dontHaddock
(dontCheck drv)))))));
toGenericPackage = stackPkgs: args: name: path:
if path == null then null else
let expr = driver { cabalexpr = import path;
pkgs = pkgs // { haskellPackages = stackPkgs; }
# fetchgit should always come from the buildPackages
# if it comes from the targetPackages we won't even
# be able to execute it.
// { fetchgit = pkgs.buildPackages.fetchgit; }
# haskell lib -> nix lib mapping
// { crypto = pkgs.openssl;
"c++" = null; # no libc++
"stdc++"= pkgs.gcc7-ng-libstdcpp-v3;
ssl = pkgs.openssl;
z = pkgs.zlib;
}
# -- windows
// { advapi32 = null; gdi32 = null; imm32 = null; msimg32 = null;
shell32 = null; shfolder = null; shlwapi = null; user32 = null;
winmm = null;
kernel32 = null; ws2_32 = null;
ssl32 = null; eay32 = pkgs.openssl;
iphlpapi = null; # IP Help API
msvcrt = null; # this is the libc
Crypt32 = null;
};
inherit (host-map pkgs.stdenv) os arch;
version = compiler.ghc.version; };
# Use `callPackage` from the `compiler` here, to get the
# right compiler.
in compiler.callPackage expr args;
in let stackPackages = pkgs: self:
(let p = (pkgs.lib.mapAttrs (toGenericPackage self {}) ltsPkgs)
// { cassava = toGenericPackage self
{ flags = { bytestring--lt-0_10_4 = false; }; }
"cassava" ltsPkgs.cassava;
time-locale-compat = toGenericPackage self
{ flags = { old-locale = false; }; }
"time-locale-compat" ltsPkgs.time-locale-compat;
libiserv = toGenericPackage self
{ flags = { network = true; }; }
"libiserv" ltsPkgs.libiserv;
cardano-sl-tools = toGenericPackage self
{ flags = { for-installer = true; }; }
"cardano-sl-tools" ltsPkgs.cardano-sl-tools;
# integer-logarithms = toGenericPackage self
# { flags = { integer-gmp = false; }; }
# "integer-logarithms" ltsPkgs.integer-logarithms;
# bytestring = toGenericPackage self
# { flags = { integer-simple = true; }; }
# "bytestring" ltsPkgs.bytestring;
# text = toGenericPackage self
# { flags = { integer-simple = true; }; }
# "text" ltsPkgs.text;
# hashable = toGenericPackage self
# { flags = { integer-gmp = false; }; }
# "hashable" ltsPkgs.hashable;
# cborg = toGenericPackage self
# { flags = { optimize-gmp = false; }; }
# "cborg" ltsPkgs.cborg;
# scientific = toGenericPackage self
# { flags = { integer-simple = true; }; }
# "scientific" ltsPkgs.scientific;
}
;
in (pkgs.lib.mapAttrs (_: v: if v == null then null else fast pkgs v) p) // (with pkgs.haskell.lib;
{ doctest = null;
hsc2hs = null;
buildPackages = pkgs.buildPackages.haskellPackages;
integer-simple = null; }));
in compiler.override {
initialPackages = { pkgs, stdenv, callPackage }: self: (stackPackages pkgs self);
configurationCommon = { ... }: self: super: {};
compilerConfig = self: super: {};
}