1{ stdenv, fetchurl, ghc, pkgconfig, glibcLocales, coreutils, gnugrep, gnused
2, jailbreak-cabal, hscolour, cpphs, nodePackages
3}:
4
5{ pname
6, dontStrip ? (ghc.isGhcjs or false)
7, version, revision ? null
8, sha256 ? null
9, src ? fetchurl { url = "mirror://hackage/${pname}-${version}.tar.gz"; inherit sha256; }
10, buildDepends ? [], libraryHaskellDepends ? [], executableHaskellDepends ? []
11, buildTarget ? ""
12, buildTools ? [], libraryToolDepends ? [], executableToolDepends ? [], testToolDepends ? []
13, configureFlags ? []
14, description ? ""
15, doCheck ? stdenv.lib.versionOlder "7.4" ghc.version
16, doHoogle ? true
17, editedCabalFile ? null
18, enableLibraryProfiling ? false
19, enableExecutableProfiling ? false
20, enableSharedExecutables ? ((ghc.isGhcjs or false) || stdenv.lib.versionOlder "7.7" ghc.version)
21, enableSharedLibraries ? ((ghc.isGhcjs or false) || stdenv.lib.versionOlder "7.7" ghc.version)
22, enableSplitObjs ? !stdenv.isDarwin # http://hackage.haskell.org/trac/ghc/ticket/4013
23, enableStaticLibraries ? true
24, extraLibraries ? [], librarySystemDepends ? [], executableSystemDepends ? []
25, homepage ? "http://hackage.haskell.org/package/${pname}"
26, platforms ? ghc.meta.platforms
27, hydraPlatforms ? platforms
28, hyperlinkSource ? true
29, isExecutable ? false, isLibrary ? !isExecutable
30, jailbreak ? false
31, license
32, maintainers ? []
33, doHaddock ? !stdenv.isDarwin || stdenv.lib.versionAtLeast ghc.version "7.8"
34, passthru ? {}
35, pkgconfigDepends ? [], libraryPkgconfigDepends ? [], executablePkgconfigDepends ? [], testPkgconfigDepends ? []
36, testDepends ? [], testHaskellDepends ? [], testSystemDepends ? []
37, testTarget ? ""
38, broken ? false
39, preCompileBuildDriver ? "", postCompileBuildDriver ? ""
40, preUnpack ? "", postUnpack ? ""
41, patches ? [], patchPhase ? "", prePatch ? "", postPatch ? ""
42, preConfigure ? "", postConfigure ? ""
43, preBuild ? "", postBuild ? ""
44, installPhase ? "", preInstall ? "", postInstall ? ""
45, checkPhase ? "", preCheck ? "", postCheck ? ""
46, preFixup ? "", postFixup ? ""
47, shellHook ? ""
48, coreSetup ? false # Use only core packages to build Setup.hs.
49, useCpphs ? false
50} @ args:
51
52assert editedCabalFile != null -> revision != null;
53
54let
55
56 inherit (stdenv.lib) optional optionals optionalString versionOlder
57 concatStringsSep enableFeature optionalAttrs toUpper;
58
59 isCross = ghc.isCross or false;
60 isGhcjs = ghc.isGhcjs or false;
61 packageDbFlag = if isGhcjs || versionOlder "7.6" ghc.version
62 then "package-db"
63 else "package-conf";
64
65 nativeGhc = if isCross then ghc.bootPkgs.ghc else ghc;
66 nativeIsCross = nativeGhc.isCross or false;
67 nativePackageDbFlag = if versionOlder "7.6" nativeGhc.version
68 then "package-db"
69 else "package-conf";
70
71 newCabalFileUrl = "http://hackage.haskell.org/package/${pname}-${version}/revision/${revision}.cabal";
72 newCabalFile = fetchurl {
73 url = newCabalFileUrl;
74 sha256 = editedCabalFile;
75 name = "${pname}-${version}-r${revision}.cabal";
76 };
77
78 defaultSetupHs = builtins.toFile "Setup.hs" ''
79 import Distribution.Simple
80 main = defaultMain
81 '';
82
83 hasActiveLibrary = isLibrary && (enableStaticLibraries || enableSharedLibraries || enableLibraryProfiling);
84
85 # We cannot enable -j<n> parallelism for libraries because GHC is far more
86 # likely to generate a non-determistic library ID in that case. Further
87 # details are at <https://github.com/peti/ghc-library-id-bug>.
88 enableParallelBuilding = versionOlder "7.8" ghc.version && !hasActiveLibrary;
89
90 defaultConfigureFlags = [
91 "--verbose" "--prefix=$out" "--libdir=\\$prefix/lib/\\$compiler" "--libsubdir=\\$pkgid"
92 "--with-gcc=$CC" # Clang won't work without that extra information.
93 "--package-db=$packageConfDir"
94 (optionalString (enableSharedExecutables && stdenv.isLinux) "--ghc-option=-optl=-Wl,-rpath=$out/lib/${ghc.name}/${pname}-${version}")
95 (optionalString (enableSharedExecutables && stdenv.isDarwin) "--ghc-option=-optl=-Wl,-headerpad_max_install_names")
96 (optionalString enableParallelBuilding "--ghc-option=-j$NIX_BUILD_CORES")
97 (optionalString useCpphs "--with-cpphs=${cpphs}/bin/cpphs --ghc-options=-cpp --ghc-options=-pgmP${cpphs}/bin/cpphs --ghc-options=-optP--cpp")
98 (enableFeature enableSplitObjs "split-objs")
99 (enableFeature enableLibraryProfiling "library-profiling")
100 (enableFeature enableExecutableProfiling (if versionOlder ghc.version "8" then "executable-profiling" else "profiling"))
101 (enableFeature enableSharedLibraries "shared")
102 (optionalString (isGhcjs || versionOlder "7" ghc.version) (enableFeature enableStaticLibraries "library-vanilla"))
103 (optionalString (isGhcjs || versionOlder "7.4" ghc.version) (enableFeature enableSharedExecutables "executable-dynamic"))
104 (optionalString (isGhcjs || versionOlder "7" ghc.version) (enableFeature doCheck "tests"))
105 ] ++ optionals isGhcjs [
106 "--with-hsc2hs=${nativeGhc}/bin/hsc2hs"
107 "--ghcjs"
108 ];
109
110 setupCompileFlags = [
111 (optionalString (!coreSetup) "-${packageDbFlag}=$packageConfDir")
112 (optionalString (isGhcjs || versionOlder "7.8" ghc.version) "-j$NIX_BUILD_CORES")
113 (optionalString (versionOlder "7.10" ghc.version) "-threaded") # https://github.com/haskell/cabal/issues/2398
114 ];
115
116 isHaskellPkg = x: (x ? pname) && (x ? version) && (x ? env);
117 isSystemPkg = x: !isHaskellPkg x;
118
119 allPkgconfigDepends = pkgconfigDepends ++ libraryPkgconfigDepends ++ executablePkgconfigDepends ++
120 optionals doCheck testPkgconfigDepends;
121
122 propagatedBuildInputs = buildDepends ++ libraryHaskellDepends ++ executableHaskellDepends;
123 otherBuildInputs = extraLibraries ++ librarySystemDepends ++ executableSystemDepends ++
124 buildTools ++ libraryToolDepends ++ executableToolDepends ++
125 optionals (allPkgconfigDepends != []) ([pkgconfig] ++ allPkgconfigDepends) ++
126 optionals doCheck (testDepends ++ testHaskellDepends ++ testSystemDepends ++ testToolDepends);
127 allBuildInputs = propagatedBuildInputs ++ otherBuildInputs;
128
129 haskellBuildInputs = stdenv.lib.filter isHaskellPkg allBuildInputs;
130 systemBuildInputs = stdenv.lib.filter isSystemPkg allBuildInputs;
131
132 ghcEnv = ghc.withPackages (p: haskellBuildInputs);
133
134 setupBuilder = if isCross then "${nativeGhc}/bin/ghc" else ghcCommand;
135 setupCommand = "./Setup";
136 ghcCommand = if isGhcjs then "ghcjs" else "ghc";
137 ghcCommandCaps = toUpper ghcCommand;
138
139in
140
141assert allPkgconfigDepends != [] -> pkgconfig != null;
142
143stdenv.mkDerivation ({
144 name = "${pname}-${version}";
145
146 pos = builtins.unsafeGetAttrPos "pname" args;
147
148 prePhases = ["setupCompilerEnvironmentPhase"];
149 preConfigurePhases = ["compileBuildDriverPhase"];
150 preInstallPhases = ["haddockPhase"];
151
152 inherit src;
153
154 nativeBuildInputs = otherBuildInputs ++ optionals (!hasActiveLibrary) propagatedBuildInputs;
155 propagatedNativeBuildInputs = optionals hasActiveLibrary propagatedBuildInputs;
156
157 LANG = "en_US.UTF-8"; # GHC needs the locale configured during the Haddock phase.
158
159 prePatch = optionalString (editedCabalFile != null) ''
160 echo "Replace Cabal file with edited version from ${newCabalFileUrl}."
161 cp ${newCabalFile} ${pname}.cabal
162 '' + prePatch;
163
164 postPatch = optionalString jailbreak ''
165 echo "Run jailbreak-cabal to lift version restrictions on build inputs."
166 ${jailbreak-cabal}/bin/jailbreak-cabal ${pname}.cabal
167 '' + postPatch;
168
169 setupCompilerEnvironmentPhase = ''
170 runHook preSetupCompilerEnvironment
171
172 echo "Build with ${ghc}."
173 export PATH="${ghc}/bin:$PATH"
174 ${optionalString (hasActiveLibrary && hyperlinkSource) "export PATH=${hscolour}/bin:$PATH"}
175
176 packageConfDir="$TMPDIR/package.conf.d"
177 mkdir -p $packageConfDir
178
179 setupCompileFlags="${concatStringsSep " " setupCompileFlags}"
180 configureFlags="${concatStringsSep " " defaultConfigureFlags} $configureFlags"
181
182 local inputClosure=""
183 for i in $propagatedNativeBuildInputs $nativeBuildInputs; do
184 findInputs $i inputClosure propagated-native-build-inputs
185 done
186 for p in $inputClosure; do
187 if [ -d "$p/lib/${ghc.name}/package.conf.d" ]; then
188 cp -f "$p/lib/${ghc.name}/package.conf.d/"*.conf $packageConfDir/
189 continue
190 fi
191 if [ -d "$p/include" ]; then
192 configureFlags+=" --extra-include-dirs=$p/include"
193 fi
194 if [ -d "$p/lib" ]; then
195 configureFlags+=" --extra-lib-dirs=$p/lib"
196 fi
197 done
198 ${ghcCommand}-pkg --${packageDbFlag}="$packageConfDir" recache
199
200 runHook postSetupCompilerEnvironment
201 '';
202
203 compileBuildDriverPhase = ''
204 runHook preCompileBuildDriver
205
206 for i in Setup.hs Setup.lhs ${defaultSetupHs}; do
207 test -f $i && break
208 done
209
210 echo setupCompileFlags: $setupCompileFlags
211 ${setupBuilder} $setupCompileFlags --make -o Setup -odir $TMPDIR -hidir $TMPDIR $i
212
213 runHook postCompileBuildDriver
214 '';
215
216 configurePhase = ''
217 runHook preConfigure
218
219 unset GHC_PACKAGE_PATH # Cabal complains if this variable is set during configure.
220
221 echo configureFlags: $configureFlags
222 ${setupCommand} configure $configureFlags 2>&1 | ${coreutils}/bin/tee "$NIX_BUILD_TOP/cabal-configure.log"
223 if ${gnugrep}/bin/egrep -q '^Warning:.*depends on multiple versions' "$NIX_BUILD_TOP/cabal-configure.log"; then
224 echo >&2 "*** abort because of serious configure-time warning from Cabal"
225 exit 1
226 fi
227
228 export GHC_PACKAGE_PATH="$packageConfDir:"
229
230 runHook postConfigure
231 '';
232
233 buildPhase = ''
234 runHook preBuild
235 ${setupCommand} build ${buildTarget}
236 runHook postBuild
237 '';
238
239 checkPhase = ''
240 runHook preCheck
241 ${setupCommand} test ${testTarget}
242 runHook postCheck
243 '';
244
245 haddockPhase = ''
246 runHook preHaddock
247 ${optionalString (doHaddock && hasActiveLibrary) ''
248 ${setupCommand} haddock --html \
249 ${optionalString doHoogle "--hoogle"} \
250 ${optionalString (hasActiveLibrary && hyperlinkSource) "--hyperlink-source"}
251 ''}
252 runHook postHaddock
253 '';
254
255 installPhase = ''
256 runHook preInstall
257
258 ${if !hasActiveLibrary then "${setupCommand} install" else ''
259 ${setupCommand} copy
260 local packageConfDir="$out/lib/${ghc.name}/package.conf.d"
261 local packageConfFile="$packageConfDir/${pname}-${version}.conf"
262 mkdir -p "$packageConfDir"
263 ${setupCommand} register --gen-pkg-config=$packageConfFile
264 local pkgId=$( ${gnused}/bin/sed -n -e 's|^id: ||p' $packageConfFile )
265 mv $packageConfFile $packageConfDir/$pkgId.conf
266 ''}
267
268 ${optionalString (enableSharedExecutables && isExecutable && !isGhcjs && stdenv.isDarwin && stdenv.lib.versionOlder ghc.version "7.10") ''
269 for exe in "$out/bin/"* ; do
270 install_name_tool -add_rpath "$out/lib/ghc-${ghc.version}/${pname}-${version}" "$exe"
271 done
272 ''}
273
274 runHook postInstall
275 '';
276
277 passthru = passthru // {
278
279 inherit pname version;
280
281 isHaskellLibrary = hasActiveLibrary;
282
283 env = stdenv.mkDerivation {
284 name = "interactive-${pname}-${version}-environment";
285 nativeBuildInputs = [ ghcEnv systemBuildInputs ]
286 ++ optional isGhcjs ghc."socket.io"; # for ghcjsi
287 LANG = "en_US.UTF-8";
288 LOCALE_ARCHIVE = optionalString stdenv.isLinux "${glibcLocales}/lib/locale/locale-archive";
289 shellHook = ''
290 export NIX_${ghcCommandCaps}="${ghcEnv}/bin/${ghcCommand}"
291 export NIX_${ghcCommandCaps}PKG="${ghcEnv}/bin/${ghcCommand}-pkg"
292 export NIX_${ghcCommandCaps}_DOCDIR="${ghcEnv}/share/doc/ghc/html"
293 export NIX_${ghcCommandCaps}_LIBDIR="${ghcEnv}/lib/${ghcEnv.name}"
294 ${shellHook}
295 '';
296 };
297
298 };
299
300 meta = { inherit homepage license platforms; }
301 // optionalAttrs broken { inherit broken; }
302 // optionalAttrs (description != "") { inherit description; }
303 // optionalAttrs (maintainers != []) { inherit maintainers; }
304 // optionalAttrs (hydraPlatforms != platforms) { inherit hydraPlatforms; }
305 ;
306
307}
308// optionalAttrs (preCompileBuildDriver != "") { inherit preCompileBuildDriver; }
309// optionalAttrs (postCompileBuildDriver != "") { inherit postCompileBuildDriver; }
310// optionalAttrs (preUnpack != "") { inherit preUnpack; }
311// optionalAttrs (postUnpack != "") { inherit postUnpack; }
312// optionalAttrs (configureFlags != []) { inherit configureFlags; }
313// optionalAttrs (patches != []) { inherit patches; }
314// optionalAttrs (patchPhase != "") { inherit patchPhase; }
315// optionalAttrs (preConfigure != "") { inherit preConfigure; }
316// optionalAttrs (postConfigure != "") { inherit postConfigure; }
317// optionalAttrs (preBuild != "") { inherit preBuild; }
318// optionalAttrs (postBuild != "") { inherit postBuild; }
319// optionalAttrs (doCheck) { inherit doCheck; }
320// optionalAttrs (checkPhase != "") { inherit checkPhase; }
321// optionalAttrs (preCheck != "") { inherit preCheck; }
322// optionalAttrs (postCheck != "") { inherit postCheck; }
323// optionalAttrs (preInstall != "") { inherit preInstall; }
324// optionalAttrs (installPhase != "") { inherit installPhase; }
325// optionalAttrs (postInstall != "") { inherit postInstall; }
326// optionalAttrs (preFixup != "") { inherit preFixup; }
327// optionalAttrs (postFixup != "") { inherit postFixup; }
328// optionalAttrs (dontStrip) { inherit dontStrip; }
329// optionalAttrs (stdenv.isLinux) { LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive"; }
330)