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