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