1{ lib, stdenv, buildPackages, buildHaskellPackages, ghc
2, jailbreak-cabal, hscolour, cpphs, nodejs
3, ghcWithHoogle, ghcWithPackages
4}:
5
6let
7 isCross = stdenv.buildPlatform != stdenv.hostPlatform;
8 inherit (buildPackages)
9 fetchurl removeReferencesTo
10 pkg-config coreutils gnugrep gnused glibcLocales;
11in
12
13{ pname
14# Note that ghc.isGhcjs != stdenv.hostPlatform.isGhcjs.
15# ghc.isGhcjs implies that we are using ghcjs, a project separate from GHC.
16# (mere) stdenv.hostPlatform.isGhcjs means that we are using GHC's JavaScript
17# backend. The latter is a normal cross compilation backend and needs little
18# special accommodation.
19, dontStrip ? (ghc.isGhcjs or false || stdenv.hostPlatform.isGhcjs)
20, version, revision ? null
21, sha256 ? null
22, src ? fetchurl { url = "mirror://hackage/${pname}-${version}.tar.gz"; inherit sha256; }
23, buildDepends ? [], setupHaskellDepends ? [], libraryHaskellDepends ? [], executableHaskellDepends ? []
24, buildTarget ? ""
25, buildTools ? [], libraryToolDepends ? [], executableToolDepends ? [], testToolDepends ? [], benchmarkToolDepends ? []
26, configureFlags ? []
27, buildFlags ? []
28, haddockFlags ? []
29, description ? null
30, doCheck ? !isCross && lib.versionOlder "7.4" ghc.version
31, doBenchmark ? false
32, doHoogle ? true
33, doHaddockQuickjump ? doHoogle && lib.versionAtLeast ghc.version "8.6"
34, doInstallIntermediates ? false
35, editedCabalFile ? null
36# aarch64 outputs otherwise exceed 2GB limit
37, enableLibraryProfiling ? !(ghc.isGhcjs or stdenv.targetPlatform.isAarch64 or false)
38, enableExecutableProfiling ? false
39, profilingDetail ? "exported-functions"
40# TODO enable shared libs for cross-compiling
41, enableSharedExecutables ? false
42, enableSharedLibraries ? !stdenv.hostPlatform.isStatic && (ghc.enableShared or false)
43, enableDeadCodeElimination ? (!stdenv.isDarwin) # TODO: use -dead_strip for darwin
44, enableStaticLibraries ? !(stdenv.hostPlatform.isWindows or stdenv.hostPlatform.isWasm)
45, enableHsc2hsViaAsm ? stdenv.hostPlatform.isWindows && lib.versionAtLeast ghc.version "8.4"
46, extraLibraries ? [], librarySystemDepends ? [], executableSystemDepends ? []
47# On macOS, statically linking against system frameworks is not supported;
48# see https://developer.apple.com/library/content/qa/qa1118/_index.html
49# They must be propagated to the environment of any executable linking with the library
50, libraryFrameworkDepends ? [], executableFrameworkDepends ? []
51, homepage ? "https://hackage.haskell.org/package/${pname}"
52, platforms ? with lib.platforms; all # GHC can cross-compile
53, badPlatforms ? lib.platforms.none
54, hydraPlatforms ? null
55, hyperlinkSource ? true
56, isExecutable ? false, isLibrary ? !isExecutable
57, jailbreak ? false
58, license
59, enableParallelBuilding ? true
60, maintainers ? null
61, changelog ? null
62, mainProgram ? null
63, doCoverage ? false
64, doHaddock ? !(ghc.isHaLVM or false) && (ghc.hasHaddock or true)
65, doHaddockInterfaces ? doHaddock && lib.versionAtLeast ghc.version "9.0.1"
66, passthru ? {}
67, pkg-configDepends ? [], libraryPkgconfigDepends ? [], executablePkgconfigDepends ? [], testPkgconfigDepends ? [], benchmarkPkgconfigDepends ? []
68, testDepends ? [], testHaskellDepends ? [], testSystemDepends ? [], testFrameworkDepends ? []
69, benchmarkDepends ? [], benchmarkHaskellDepends ? [], benchmarkSystemDepends ? [], benchmarkFrameworkDepends ? []
70, testTarget ? "", testFlags ? []
71, broken ? false
72, preCompileBuildDriver ? null, postCompileBuildDriver ? null
73, preUnpack ? null, postUnpack ? null
74, patches ? null, patchPhase ? null, prePatch ? "", postPatch ? ""
75, preConfigure ? null, postConfigure ? null
76, preBuild ? null, postBuild ? null
77, preHaddock ? null, postHaddock ? null
78, installPhase ? null, preInstall ? null, postInstall ? null
79, checkPhase ? null, preCheck ? null, postCheck ? null
80, preFixup ? null, postFixup ? null
81, shellHook ? ""
82, coreSetup ? false # Use only core packages to build Setup.hs.
83, useCpphs ? false
84, hardeningDisable ? null
85, enableSeparateBinOutput ? false
86, enableSeparateDataOutput ? false
87, enableSeparateDocOutput ? doHaddock
88, enableSeparateIntermediatesOutput ? false
89, # Don't fail at configure time if there are multiple versions of the
90 # same package in the (recursive) dependencies of the package being
91 # built. Will delay failures, if any, to compile time.
92 allowInconsistentDependencies ? false
93, maxBuildCores ? 16 # more cores usually don't improve performance: https://ghc.haskell.org/trac/ghc/ticket/9221
94, # If set to true, this builds a pre-linked .o file for this Haskell library.
95 # This can make it slightly faster to load this library into GHCi, but takes
96 # extra disk space and compile time.
97 enableLibraryForGhci ? false
98 # Set this to a previous build of this same package to reuse the intermediate
99 # build products from that prior build as a starting point for accelerating
100 # this build
101, previousIntermediates ? null
102} @ args:
103
104assert editedCabalFile != null -> revision != null;
105
106# --enable-static does not work on windows. This is a bug in GHC.
107# --enable-static will pass -staticlib to ghc, which only works for mach-o and elf.
108assert stdenv.hostPlatform.isWindows -> enableStaticLibraries == false;
109assert stdenv.hostPlatform.isWasm -> enableStaticLibraries == false;
110
111let
112
113 inherit (lib) optional optionals optionalString versionOlder versionAtLeast
114 concatStringsSep enableFeature optionalAttrs;
115
116 isGhcjs = ghc.isGhcjs or false;
117 isHaLVM = ghc.isHaLVM or false;
118 packageDbFlag = if isGhcjs || isHaLVM || versionOlder "7.6" ghc.version
119 then "package-db"
120 else "package-conf";
121
122 # GHC used for building Setup.hs
123 #
124 # Same as our GHC, unless we're cross, in which case it is native GHC with the
125 # same version, or ghcjs, in which case its the ghc used to build ghcjs.
126 nativeGhc = buildHaskellPackages.ghc;
127 nativePackageDbFlag = if versionOlder "7.6" nativeGhc.version
128 then "package-db"
129 else "package-conf";
130
131 # the target dir for haddock documentation
132 docdir = docoutput: docoutput + "/share/doc/" + pname + "-" + version;
133
134 binDir = if enableSeparateBinOutput then "$bin/bin" else "$out/bin";
135
136 newCabalFileUrl = "mirror://hackage/${pname}-${version}/revision/${revision}.cabal";
137 newCabalFile = fetchurl {
138 url = newCabalFileUrl;
139 sha256 = editedCabalFile;
140 name = "${pname}-${version}-r${revision}.cabal";
141 };
142
143 defaultSetupHs = builtins.toFile "Setup.hs" ''
144 import Distribution.Simple
145 main = defaultMain
146 '';
147
148 # This awk expression transforms a package conf file like
149 #
150 # author: John Doe <john-doe@example.com>
151 # description:
152 # The purpose of this library is to do
153 # foo and bar among other things
154 #
155 # into a more easily processeable form:
156 #
157 # author: John Doe <john-doe@example.com>
158 # description: The purpose of this library is to do foo and bar among other things
159 unprettyConf = builtins.toFile "unpretty-cabal-conf.awk" ''
160 /^[^ ]+:/ {
161 # When the line starts with a new field, terminate the previous one with a newline
162 if (started == 1) print ""
163 # to strip leading spaces
164 $1=$1
165 printf "%s", $0
166 started=1
167 }
168
169 /^ +/ {
170 # to strip leading spaces
171 $1=$1
172 printf " %s", $0
173 }
174
175 # Terminate the final field with a newline
176 END { print "" }
177 '';
178
179 crossCabalFlags = [
180 "--with-ghc=${ghcCommand}"
181 "--with-ghc-pkg=${ghc.targetPrefix}ghc-pkg"
182 # Pass the "wrong" C compiler rather than none at all so packages that just
183 # use the C preproccessor still work, see
184 # https://github.com/haskell/cabal/issues/6466 for details.
185 "--with-gcc=${if stdenv.hasCC then "$CC" else "$CC_FOR_BUILD"}"
186 ] ++ optionals stdenv.hasCC [
187 "--with-ld=${stdenv.cc.bintools.targetPrefix}ld"
188 "--with-ar=${stdenv.cc.bintools.targetPrefix}ar"
189 # use the one that comes with the cross compiler.
190 "--with-hsc2hs=${ghc.targetPrefix}hsc2hs"
191 "--with-strip=${stdenv.cc.bintools.targetPrefix}strip"
192 ] ++ optionals (!isHaLVM) [
193 "--hsc2hs-option=--cross-compile"
194 (optionalString enableHsc2hsViaAsm "--hsc2hs-option=--via-asm")
195 ] ++ optional (allPkgconfigDepends != [])
196 "--with-pkg-config=${pkg-config.targetPrefix}pkg-config";
197
198 parallelBuildingFlags = "-j$NIX_BUILD_CORES" + optionalString stdenv.isLinux " +RTS -A64M -RTS";
199
200 crossCabalFlagsString =
201 lib.optionalString isCross (" " + lib.concatStringsSep " " crossCabalFlags);
202
203 buildFlagsString = optionalString (buildFlags != []) (" " + concatStringsSep " " buildFlags);
204
205 defaultConfigureFlags = [
206 "--verbose"
207 "--prefix=$out"
208 # Note: This must be kept in sync manually with mkGhcLibdir
209 ("--libdir=\\$prefix/lib/\\$compiler" + lib.optionalString (ghc ? hadrian) "/lib")
210 "--libsubdir=\\$abi/\\$libname"
211 (optionalString enableSeparateDataOutput "--datadir=$data/share/${ghcNameWithPrefix}")
212 (optionalString enableSeparateDocOutput "--docdir=${docdir "$doc"}")
213 ] ++ optionals stdenv.hasCC [
214 "--with-gcc=$CC" # Clang won't work without that extra information.
215 ] ++ [
216 "--package-db=$packageConfDir"
217 (optionalString (enableSharedExecutables && stdenv.isLinux) "--ghc-option=-optl=-Wl,-rpath=$out/${ghcLibdir}/${pname}-${version}")
218 (optionalString (enableSharedExecutables && stdenv.isDarwin) "--ghc-option=-optl=-Wl,-headerpad_max_install_names")
219 (optionalString enableParallelBuilding "--ghc-options=${parallelBuildingFlags}")
220 (optionalString useCpphs "--with-cpphs=${cpphs}/bin/cpphs --ghc-options=-cpp --ghc-options=-pgmP${cpphs}/bin/cpphs --ghc-options=-optP--cpp")
221 (enableFeature (enableDeadCodeElimination && !stdenv.hostPlatform.isAarch32 && !stdenv.hostPlatform.isAarch64 && (versionAtLeast "8.0.1" ghc.version)) "split-objs")
222 (enableFeature enableLibraryProfiling "library-profiling")
223 (optionalString ((enableExecutableProfiling || enableLibraryProfiling) && versionOlder "8" ghc.version) "--profiling-detail=${profilingDetail}")
224 (enableFeature enableExecutableProfiling (if versionOlder ghc.version "8" then "executable-profiling" else "profiling"))
225 (enableFeature enableSharedLibraries "shared")
226 (optionalString (versionAtLeast ghc.version "7.10") (enableFeature doCoverage "coverage"))
227 (optionalString (versionOlder "8.4" ghc.version) (enableFeature enableStaticLibraries "static"))
228 (optionalString (isGhcjs || versionOlder "7.4" ghc.version) (enableFeature enableSharedExecutables "executable-dynamic"))
229 (optionalString (isGhcjs || versionOlder "7" ghc.version) (enableFeature doCheck "tests"))
230 (enableFeature doBenchmark "benchmarks")
231 "--enable-library-vanilla" # TODO: Should this be configurable?
232 (enableFeature enableLibraryForGhci "library-for-ghci")
233 ] ++ optionals (enableDeadCodeElimination && (lib.versionOlder "8.0.1" ghc.version)) [
234 "--ghc-option=-split-sections"
235 ] ++ optionals dontStrip [
236 "--disable-library-stripping"
237 "--disable-executable-stripping"
238 ] ++ optionals isGhcjs [
239 "--ghcjs"
240 ] ++ optionals isCross ([
241 "--configure-option=--host=${stdenv.hostPlatform.config}"
242 ] ++ crossCabalFlags
243 ) ++ optionals enableSeparateBinOutput [
244 "--bindir=${binDir}"
245 ] ++ optionals (doHaddockInterfaces && isLibrary) [
246 "--ghc-options=-haddock"
247 ];
248
249 postPhases = optional doInstallIntermediates [ "installIntermediatesPhase" ];
250
251 setupCompileFlags = [
252 (optionalString (!coreSetup) "-${nativePackageDbFlag}=$setupPackageConfDir")
253 (optionalString enableParallelBuilding (parallelBuildingFlags))
254 "-threaded" # https://github.com/haskell/cabal/issues/2398
255 "-rtsopts" # allow us to pass RTS flags to the generated Setup executable
256 ];
257
258 isHaskellPkg = x: x ? isHaskellLibrary;
259
260 allPkgconfigDepends = pkg-configDepends ++ libraryPkgconfigDepends ++ executablePkgconfigDepends ++
261 optionals doCheck testPkgconfigDepends ++ optionals doBenchmark benchmarkPkgconfigDepends;
262
263 depsBuildBuild = [ nativeGhc ]
264 # CC_FOR_BUILD may be necessary if we have no C preprocessor for the host
265 # platform. See crossCabalFlags above for more details.
266 ++ lib.optionals (!stdenv.hasCC) [ buildPackages.stdenv.cc ];
267 collectedToolDepends =
268 buildTools ++ libraryToolDepends ++ executableToolDepends ++
269 optionals doCheck testToolDepends ++
270 optionals doBenchmark benchmarkToolDepends;
271 nativeBuildInputs =
272 [ ghc removeReferencesTo ] ++ optional (allPkgconfigDepends != []) pkg-config ++
273 setupHaskellDepends ++ collectedToolDepends;
274 propagatedBuildInputs = buildDepends ++ libraryHaskellDepends ++ executableHaskellDepends ++ libraryFrameworkDepends;
275 otherBuildInputsHaskell =
276 optionals doCheck (testDepends ++ testHaskellDepends) ++
277 optionals doBenchmark (benchmarkDepends ++ benchmarkHaskellDepends);
278 otherBuildInputsSystem =
279 extraLibraries ++ librarySystemDepends ++ executableSystemDepends ++ executableFrameworkDepends ++
280 allPkgconfigDepends ++
281 optionals doCheck (testSystemDepends ++ testFrameworkDepends) ++
282 optionals doBenchmark (benchmarkSystemDepends ++ benchmarkFrameworkDepends);
283 # TODO next rebuild just define as `otherBuildInputsHaskell ++ otherBuildInputsSystem`
284 otherBuildInputs =
285 extraLibraries ++ librarySystemDepends ++ executableSystemDepends ++ executableFrameworkDepends ++
286 allPkgconfigDepends ++
287 optionals doCheck (testDepends ++ testHaskellDepends ++ testSystemDepends ++ testFrameworkDepends) ++
288 optionals doBenchmark (benchmarkDepends ++ benchmarkHaskellDepends ++ benchmarkSystemDepends ++ benchmarkFrameworkDepends);
289
290 setupCommand = "./Setup";
291
292 ghcCommand' = if isGhcjs then "ghcjs" else "ghc";
293 ghcCommand = "${ghc.targetPrefix}${ghcCommand'}";
294
295 ghcNameWithPrefix = "${ghc.targetPrefix}${ghc.haskellCompilerName}";
296 mkGhcLibdir = ghc: "lib/${ghc.targetPrefix}${ghc.haskellCompilerName}"
297 + lib.optionalString (ghc ? hadrian) "/lib";
298 ghcLibdir = mkGhcLibdir ghc;
299
300 nativeGhcCommand = "${nativeGhc.targetPrefix}ghc";
301
302 buildPkgDb = thisGhc: packageConfDir: ''
303 # If this dependency has a package database, then copy the contents of it,
304 # unless it is one of our GHCs. These can appear in our dependencies when
305 # we are doing native builds, and they have package databases in them, but
306 # we do not want to copy them over.
307 #
308 # We don't need to, since those packages will be provided by the GHC when
309 # we compile with it, and doing so can result in having multiple copies of
310 # e.g. Cabal in the database with the same name and version, which is
311 # ambiguous.
312 if [ -d "$p/${mkGhcLibdir thisGhc}/package.conf.d" ] && [ "$p" != "${ghc}" ] && [ "$p" != "${nativeGhc}" ]; then
313 cp -f "$p/${mkGhcLibdir thisGhc}/package.conf.d/"*.conf ${packageConfDir}/
314 continue
315 fi
316 '';
317
318 intermediatesDir = "share/haskell/${ghc.version}/${pname}-${version}/dist";
319in lib.fix (drv:
320
321assert allPkgconfigDepends != [] -> pkg-config != null;
322
323stdenv.mkDerivation ({
324 inherit pname version;
325
326 outputs = [ "out" ]
327 ++ (optional enableSeparateDataOutput "data")
328 ++ (optional enableSeparateDocOutput "doc")
329 ++ (optional enableSeparateBinOutput "bin")
330 ++ (optional enableSeparateIntermediatesOutput "intermediates");
331
332 setOutputFlags = false;
333
334 pos = builtins.unsafeGetAttrPos "pname" args;
335
336 prePhases = ["setupCompilerEnvironmentPhase"];
337 preConfigurePhases = ["compileBuildDriverPhase"];
338 preInstallPhases = ["haddockPhase"];
339
340 inherit src;
341
342 inherit depsBuildBuild nativeBuildInputs;
343 buildInputs = otherBuildInputs ++ optionals (!isLibrary) propagatedBuildInputs
344 # For patchShebangsAuto in fixupPhase
345 ++ optionals stdenv.hostPlatform.isGhcjs [ nodejs ];
346 propagatedBuildInputs = optionals isLibrary propagatedBuildInputs;
347
348 LANG = "en_US.UTF-8"; # GHC needs the locale configured during the Haddock phase.
349
350 prePatch = optionalString (editedCabalFile != null) ''
351 echo "Replace Cabal file with edited version from ${newCabalFileUrl}."
352 cp ${newCabalFile} ${pname}.cabal
353 '' + prePatch;
354
355 postPatch = optionalString jailbreak ''
356 echo "Run jailbreak-cabal to lift version restrictions on build inputs."
357 ${jailbreak-cabal}/bin/jailbreak-cabal ${pname}.cabal
358 '' + postPatch;
359
360 setupCompilerEnvironmentPhase = ''
361 NIX_BUILD_CORES=$(( NIX_BUILD_CORES < ${toString maxBuildCores} ? NIX_BUILD_CORES : ${toString maxBuildCores} ))
362 runHook preSetupCompilerEnvironment
363
364 echo "Build with ${ghc}."
365 ${optionalString (isLibrary && hyperlinkSource) "export PATH=${hscolour}/bin:$PATH"}
366
367 builddir="$(mktemp -d)"
368 setupPackageConfDir="$builddir/setup-package.conf.d"
369 mkdir -p $setupPackageConfDir
370 packageConfDir="$builddir/package.conf.d"
371 mkdir -p $packageConfDir
372
373 setupCompileFlags="${concatStringsSep " " setupCompileFlags}"
374 configureFlags="${concatStringsSep " " defaultConfigureFlags} $configureFlags"
375 ''
376 # We build the Setup.hs on the *build* machine, and as such should only add
377 # dependencies for the build machine.
378 #
379 # pkgs* arrays defined in stdenv/setup.hs
380 + ''
381 for p in "''${pkgsBuildBuild[@]}" "''${pkgsBuildHost[@]}" "''${pkgsBuildTarget[@]}"; do
382 ${buildPkgDb nativeGhc "$setupPackageConfDir"}
383 done
384 ${nativeGhcCommand}-pkg --${nativePackageDbFlag}="$setupPackageConfDir" recache
385 ''
386 # For normal components
387 + ''
388 for p in "''${pkgsHostHost[@]}" "''${pkgsHostTarget[@]}"; do
389 ${buildPkgDb ghc "$packageConfDir"}
390 if [ -d "$p/include" ]; then
391 configureFlags+=" --extra-include-dirs=$p/include"
392 fi
393 if [ -d "$p/lib" ]; then
394 configureFlags+=" --extra-lib-dirs=$p/lib"
395 fi
396 ''
397 # It is not clear why --extra-framework-dirs does work fine on Linux
398 + optionalString (!stdenv.buildPlatform.isDarwin || versionAtLeast nativeGhc.version "8.0") ''
399 if [[ -d "$p/Library/Frameworks" ]]; then
400 configureFlags+=" --extra-framework-dirs=$p/Library/Frameworks"
401 fi
402 '' + ''
403 done
404 ''
405 # only use the links hack if we're actually building dylibs. otherwise, the
406 # "dynamic-library-dirs" point to nonexistent paths, and the ln command becomes
407 # "ln -s $out/lib/links", which tries to recreate the links dir and fails
408 #
409 # Note: We need to disable this work-around when using intermediate build
410 # products from a prior build because otherwise Nix will change permissions on
411 # the `$out/lib/links` directory to read-only when the build is done after the
412 # dist directory has already been exported, which triggers an unnecessary
413 # rebuild of modules included in the exported dist directory.
414 + (optionalString (stdenv.isDarwin && (enableSharedLibraries || enableSharedExecutables) && !enableSeparateIntermediatesOutput) ''
415 # Work around a limit in the macOS Sierra linker on the number of paths
416 # referenced by any one dynamic library:
417 #
418 # Create a local directory with symlinks of the *.dylib (macOS shared
419 # libraries) from all the dependencies.
420 local dynamicLinksDir="$out/lib/links"
421 mkdir -p $dynamicLinksDir
422
423 # Unprettify all package conf files before reading/writing them
424 for d in "$packageConfDir/"*; do
425 # gawk -i inplace seems to strip the last newline
426 gawk -f ${unprettyConf} "$d" > tmp
427 mv tmp "$d"
428 done
429
430 for d in $(grep '^dynamic-library-dirs:' "$packageConfDir"/* | cut -d' ' -f2- | tr ' ' '\n' | sort -u); do
431 for lib in "$d/"*.{dylib,so}; do
432 # Allow overwriting because C libs can be pulled in multiple times.
433 ln -sf "$lib" "$dynamicLinksDir"
434 done
435 done
436 # Edit the local package DB to reference the links directory.
437 for f in "$packageConfDir/"*.conf; do
438 sed -i "s,dynamic-library-dirs: .*,dynamic-library-dirs: $dynamicLinksDir," "$f"
439 done
440 '') + ''
441 ${ghcCommand}-pkg --${packageDbFlag}="$packageConfDir" recache
442
443 runHook postSetupCompilerEnvironment
444 '';
445
446 compileBuildDriverPhase = ''
447 runHook preCompileBuildDriver
448
449 for i in Setup.hs Setup.lhs ${defaultSetupHs}; do
450 test -f $i && break
451 done
452
453 echo setupCompileFlags: $setupCompileFlags
454 ${nativeGhcCommand} $setupCompileFlags --make -o Setup -odir $builddir -hidir $builddir $i
455
456 runHook postCompileBuildDriver
457 '';
458
459 # Cabal takes flags like `--configure-option=--host=...` instead
460 configurePlatforms = [];
461 inherit configureFlags;
462
463 # Note: the options here must be always added, regardless of whether the
464 # package specifies `hardeningDisable`.
465 hardeningDisable = lib.optionals (args ? hardeningDisable) hardeningDisable
466 ++ lib.optional (ghc.isHaLVM or false) "all"
467 # Static libraries (ie. all of pkgsStatic.haskellPackages) fail to build
468 # because by default Nix adds `-pie` to the linker flags: this
469 # conflicts with the `-r` and `-no-pie` flags added by GHC (see
470 # https://gitlab.haskell.org/ghc/ghc/-/issues/19580). hardeningDisable
471 # changes the default Nix behavior regarding adding "hardening" flags.
472 ++ lib.optional enableStaticLibraries "pie";
473
474 configurePhase = ''
475 runHook preConfigure
476
477 unset GHC_PACKAGE_PATH # Cabal complains if this variable is set during configure.
478
479 echo configureFlags: $configureFlags
480 ${setupCommand} configure $configureFlags 2>&1 | ${coreutils}/bin/tee "$NIX_BUILD_TOP/cabal-configure.log"
481 ${lib.optionalString (!allowInconsistentDependencies) ''
482 if ${gnugrep}/bin/egrep -q -z 'Warning:.*depends on multiple versions' "$NIX_BUILD_TOP/cabal-configure.log"; then
483 echo >&2 "*** abort because of serious configure-time warning from Cabal"
484 exit 1
485 fi
486 ''}
487 export GHC_PACKAGE_PATH="$packageConfDir:"
488
489 runHook postConfigure
490 '';
491
492 buildPhase =
493 ''
494 runHook preBuild
495 ''
496 + lib.optionalString (previousIntermediates != null)
497 ''
498 mkdir -p dist;
499 rm -r dist/build
500 cp -r ${previousIntermediates}/${intermediatesDir}/build dist/build
501 find dist/build -exec chmod u+w {} +
502 find dist/build -exec touch -d '1970-01-01T00:00:00Z' {} +
503 ''
504 + ''
505 ${setupCommand} build ${buildTarget}${crossCabalFlagsString}${buildFlagsString}
506 runHook postBuild
507 '';
508
509 inherit doCheck;
510
511 # Run test suite(s) and pass `checkFlags` as well as `checkFlagsArray`.
512 # `testFlags` are added to `checkFlagsArray` each prefixed with
513 # `--test-option`, so Cabal passes it to the underlying test suite binary.
514 checkPhase = ''
515 runHook preCheck
516 checkFlagsArray+=(
517 "--show-details=streaming"
518 ${lib.escapeShellArgs (builtins.map (opt: "--test-option=${opt}") testFlags)}
519 )
520 ${setupCommand} test ${testTarget} $checkFlags ''${checkFlagsArray:+"''${checkFlagsArray[@]}"}
521 runHook postCheck
522 '';
523
524 haddockPhase = ''
525 runHook preHaddock
526 ${optionalString (doHaddock && isLibrary) ''
527 ${setupCommand} haddock --html \
528 ${optionalString doHoogle "--hoogle"} \
529 ${optionalString doHaddockQuickjump "--quickjump"} \
530 ${optionalString (isLibrary && hyperlinkSource) "--hyperlink-source"} \
531 ${lib.concatStringsSep " " haddockFlags}
532 ''}
533 runHook postHaddock
534 '';
535
536 installPhase = ''
537 runHook preInstall
538
539 ${if !isLibrary && buildTarget == "" then "${setupCommand} install"
540 # ^^ if the project is not a library, and no build target is specified, we can just use "install".
541 else if !isLibrary then "${setupCommand} copy ${buildTarget}"
542 # ^^ if the project is not a library, and we have a build target, then use "copy" to install
543 # just the target specified; "install" will error here, since not all targets have been built.
544 else ''
545 ${setupCommand} copy ${buildTarget}
546 local packageConfDir="$out/${ghcLibdir}/package.conf.d"
547 local packageConfFile="$packageConfDir/${pname}-${version}.conf"
548 mkdir -p "$packageConfDir"
549 ${setupCommand} register --gen-pkg-config=$packageConfFile
550 if [ -d "$packageConfFile" ]; then
551 mv "$packageConfFile/"* "$packageConfDir"
552 rmdir "$packageConfFile"
553 fi
554 for packageConfFile in "$packageConfDir/"*; do
555 local pkgId=$(gawk -f ${unprettyConf} "$packageConfFile" \
556 | grep '^id:' | cut -d' ' -f2)
557 mv "$packageConfFile" "$packageConfDir/$pkgId.conf"
558 done
559
560 # delete confdir if there are no libraries
561 find $packageConfDir -maxdepth 0 -empty -delete;
562 ''}
563 ${optionalString isGhcjs ''
564 for exeDir in "${binDir}/"*.jsexe; do
565 exe="''${exeDir%.jsexe}"
566 printWords '#!${nodejs}/bin/node' > "$exe"
567 echo >> "$exe"
568 cat "$exeDir/all.js" >> "$exe"
569 chmod +x "$exe"
570 done
571 ''}
572 ${optionalString doCoverage "mkdir -p $out/share && cp -r dist/hpc $out/share"}
573 ${optionalString (enableSharedExecutables && isExecutable && !isGhcjs && stdenv.isDarwin && lib.versionOlder ghc.version "7.10") ''
574 for exe in "${binDir}/"* ; do
575 install_name_tool -add_rpath "$out/${ghcLibdir}/${pname}-${version}" "$exe"
576 done
577 ''}
578
579 ${optionalString enableSeparateDocOutput ''
580 for x in ${docdir "$doc"}"/html/src/"*.html; do
581 remove-references-to -t $out $x
582 done
583 mkdir -p $doc
584 ''}
585 ${optionalString enableSeparateDataOutput "mkdir -p $data"}
586
587 runHook postInstall
588 '';
589
590 ${if doInstallIntermediates then "installIntermediatesPhase" else null} = ''
591 runHook preInstallIntermediates
592 intermediatesOutput=${if enableSeparateIntermediatesOutput then "$intermediates" else "$out"}
593 installIntermediatesDir="$intermediatesOutput/${intermediatesDir}"
594 mkdir -p "$installIntermediatesDir"
595 cp -r dist/build "$installIntermediatesDir"
596 runHook postInstallIntermediates
597 '';
598
599 passthru = passthru // rec {
600
601 inherit pname version;
602
603 compiler = ghc;
604
605 # All this information is intended just for `shellFor`. It should be
606 # considered unstable and indeed we knew how to keep it private we would.
607 getCabalDeps = {
608 inherit
609 buildDepends
610 buildTools
611 executableFrameworkDepends
612 executableHaskellDepends
613 executablePkgconfigDepends
614 executableSystemDepends
615 executableToolDepends
616 extraLibraries
617 libraryFrameworkDepends
618 libraryHaskellDepends
619 libraryPkgconfigDepends
620 librarySystemDepends
621 libraryToolDepends
622 pkg-configDepends
623 setupHaskellDepends
624 ;
625 } // lib.optionalAttrs doCheck {
626 inherit
627 testDepends
628 testFrameworkDepends
629 testHaskellDepends
630 testPkgconfigDepends
631 testSystemDepends
632 testToolDepends
633 ;
634 } // lib.optionalAttrs doBenchmark {
635 inherit
636 benchmarkDepends
637 benchmarkFrameworkDepends
638 benchmarkHaskellDepends
639 benchmarkPkgconfigDepends
640 benchmarkSystemDepends
641 benchmarkToolDepends
642 ;
643 };
644
645 # Attributes for the old definition of `shellFor`. Should be removed but
646 # this predates the warning at the top of `getCabalDeps`.
647 getBuildInputs = rec {
648 inherit propagatedBuildInputs otherBuildInputs allPkgconfigDepends;
649 haskellBuildInputs = isHaskellPartition.right;
650 systemBuildInputs = isHaskellPartition.wrong;
651 isHaskellPartition = lib.partition
652 isHaskellPkg
653 (propagatedBuildInputs ++ otherBuildInputs ++ depsBuildBuild ++ nativeBuildInputs);
654 };
655
656 isHaskellLibrary = isLibrary;
657
658 # TODO: ask why the split outputs are configurable at all?
659 # TODO: include tests for split if possible
660 # Given the haskell package, returns
661 # the directory containing the haddock documentation.
662 # `null' if no haddock documentation was built.
663 # TODO: fetch the self from the fixpoint instead
664 haddockDir = self: if doHaddock then "${docdir self.doc}/html" else null;
665
666 # Creates a derivation containing all of the necessary dependencies for building the
667 # parent derivation. The attribute set that it takes as input can be viewed as:
668 #
669 # { withHoogle }
670 #
671 # The derivation that it builds contains no outpaths because it is meant for use
672 # as an environment
673 #
674 # # Example use
675 # # Creates a shell with all of the dependencies required to build the "hello" package,
676 # # and with python:
677 #
678 # > nix-shell -E 'with (import <nixpkgs> {}); \
679 # > haskell.packages.ghc865.hello.envFunc { buildInputs = [ python ]; }'
680 envFunc = { withHoogle ? false }:
681 let
682 name = "ghc-shell-for-${drv.name}";
683
684 withPackages = if withHoogle then ghcWithHoogle else ghcWithPackages;
685
686 # We use the `ghcWithPackages` function from `buildHaskellPackages` if we
687 # want a shell for the sake of cross compiling a package. In the native case
688 # we don't use this at all, and instead put the setupDepends in the main
689 # `ghcWithPackages`. This way we don't have two wrapper scripts called `ghc`
690 # shadowing each other on the PATH.
691 ghcEnvForBuild =
692 assert isCross;
693 buildHaskellPackages.ghcWithPackages (_: setupHaskellDepends);
694
695 ghcEnv = withPackages (_:
696 otherBuildInputsHaskell ++
697 propagatedBuildInputs ++
698 lib.optionals (!isCross) setupHaskellDepends);
699
700 ghcCommandCaps = lib.toUpper ghcCommand';
701 in stdenv.mkDerivation ({
702 inherit name shellHook;
703
704 depsBuildBuild = lib.optional isCross ghcEnvForBuild;
705 nativeBuildInputs =
706 [ ghcEnv ] ++ optional (allPkgconfigDepends != []) pkg-config ++
707 collectedToolDepends;
708 buildInputs =
709 otherBuildInputsSystem;
710 phases = ["installPhase"];
711 installPhase = "echo $nativeBuildInputs $buildInputs > $out";
712 LANG = "en_US.UTF-8";
713 LOCALE_ARCHIVE = lib.optionalString (stdenv.hostPlatform.libc == "glibc") "${buildPackages.glibcLocales}/lib/locale/locale-archive";
714 "NIX_${ghcCommandCaps}" = "${ghcEnv}/bin/${ghcCommand}";
715 "NIX_${ghcCommandCaps}PKG" = "${ghcEnv}/bin/${ghcCommand}-pkg";
716 # TODO: is this still valid?
717 "NIX_${ghcCommandCaps}_DOCDIR" = "${ghcEnv}/share/doc/ghc/html";
718 "NIX_${ghcCommandCaps}_LIBDIR" = if ghc.isHaLVM or false
719 then "${ghcEnv}/lib/HaLVM-${ghc.version}"
720 else "${ghcEnv}/${ghcLibdir}";
721 });
722
723 env = envFunc { };
724
725 };
726
727 meta = { inherit homepage license platforms; }
728 // optionalAttrs (args ? broken) { inherit broken; }
729 // optionalAttrs (args ? description) { inherit description; }
730 // optionalAttrs (args ? maintainers) { inherit maintainers; }
731 // optionalAttrs (args ? hydraPlatforms) { inherit hydraPlatforms; }
732 // optionalAttrs (args ? badPlatforms) { inherit badPlatforms; }
733 // optionalAttrs (args ? changelog) { inherit changelog; }
734 // optionalAttrs (args ? mainProgram) { inherit mainProgram; }
735 ;
736
737}
738// optionalAttrs (args ? preCompileBuildDriver) { inherit preCompileBuildDriver; }
739// optionalAttrs (args ? postCompileBuildDriver) { inherit postCompileBuildDriver; }
740// optionalAttrs (args ? preUnpack) { inherit preUnpack; }
741// optionalAttrs (args ? postUnpack) { inherit postUnpack; }
742// optionalAttrs (args ? patches) { inherit patches; }
743// optionalAttrs (args ? patchPhase) { inherit patchPhase; }
744// optionalAttrs (args ? preConfigure) { inherit preConfigure; }
745// optionalAttrs (args ? postConfigure) { inherit postConfigure; }
746// optionalAttrs (args ? preBuild) { inherit preBuild; }
747// optionalAttrs (args ? postBuild) { inherit postBuild; }
748// optionalAttrs (args ? doBenchmark) { inherit doBenchmark; }
749// optionalAttrs (args ? checkPhase) { inherit checkPhase; }
750// optionalAttrs (args ? preCheck) { inherit preCheck; }
751// optionalAttrs (args ? postCheck) { inherit postCheck; }
752// optionalAttrs (args ? preHaddock) { inherit preHaddock; }
753// optionalAttrs (args ? postHaddock) { inherit postHaddock; }
754// optionalAttrs (args ? preInstall) { inherit preInstall; }
755// optionalAttrs (args ? installPhase) { inherit installPhase; }
756// optionalAttrs (args ? postInstall) { inherit postInstall; }
757// optionalAttrs (args ? preFixup) { inherit preFixup; }
758// optionalAttrs (args ? postFixup) { inherit postFixup; }
759// optionalAttrs (args ? dontStrip) { inherit dontStrip; }
760// optionalAttrs (postPhases != []) { inherit postPhases; }
761// optionalAttrs (stdenv.buildPlatform.libc == "glibc"){ LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive"; }
762)
763)