1{
2 lib,
3 stdenv,
4 buildPackages,
5 buildHaskellPackages,
6 ghc,
7 jailbreak-cabal,
8 hscolour,
9 cpphs,
10 runCommandCC,
11 ghcWithHoogle,
12 ghcWithPackages,
13 nodejs,
14}:
15
16let
17 isCross = stdenv.buildPlatform != stdenv.hostPlatform;
18
19 # Pass the "wrong" C compiler rather than none at all so packages that just
20 # use the C preproccessor still work, see
21 # https://github.com/haskell/cabal/issues/6466 for details.
22 cc =
23 if stdenv.hasCC then
24 "$CC"
25 else if stdenv.hostPlatform.isGhcjs then
26 "${emscripten}/bin/emcc"
27 else
28 "$CC_FOR_BUILD";
29
30 inherit (buildPackages)
31 fetchurl
32 removeReferencesTo
33 pkg-config
34 coreutils
35 glibcLocales
36 emscripten
37 ;
38
39in
40
41{
42 pname,
43 dontStrip ? stdenv.hostPlatform.isGhcjs,
44 version,
45 revision ? null,
46 sha256 ? null,
47 src ? fetchurl {
48 url = "mirror://hackage/${pname}-${version}.tar.gz";
49 inherit sha256;
50 },
51 sourceRoot ? null,
52 setSourceRoot ? null,
53 # Extra environment variables to set during the build.
54 # See: `../../../doc/languages-frameworks/haskell.section.md`
55 env ? { },
56 buildDepends ? [ ],
57 setupHaskellDepends ? [ ],
58 libraryHaskellDepends ? [ ],
59 executableHaskellDepends ? [ ],
60 buildTarget ? "",
61 buildTools ? [ ],
62 libraryToolDepends ? [ ],
63 executableToolDepends ? [ ],
64 testToolDepends ? [ ],
65 benchmarkToolDepends ? [ ],
66 configureFlags ? [ ],
67 buildFlags ? [ ],
68 haddockFlags ? [ ],
69 description ? null,
70 doCheck ? !isCross,
71 doBenchmark ? false,
72 doHoogle ? true,
73 doHaddockQuickjump ? doHoogle,
74 doInstallIntermediates ? false,
75 editedCabalFile ? null,
76 enableLibraryProfiling ? !stdenv.hostPlatform.isGhcjs,
77 enableExecutableProfiling ? false,
78 profilingDetail ? "exported-functions",
79 # TODO enable shared libs for cross-compiling
80 enableSharedExecutables ? false,
81 enableSharedLibraries ?
82 !stdenv.hostPlatform.isStatic
83 && (ghc.enableShared or false)
84 && !stdenv.hostPlatform.useAndroidPrebuilt, # TODO: figure out why /build leaks into RPATH
85 enableDeadCodeElimination ? (!stdenv.hostPlatform.isDarwin), # TODO: use -dead_strip for darwin
86 # Disabling this for JS prevents this crash: https://gitlab.haskell.org/ghc/ghc/-/issues/23235
87 enableStaticLibraries ?
88 !(stdenv.hostPlatform.isWindows || stdenv.hostPlatform.isWasm || stdenv.hostPlatform.isGhcjs),
89 enableHsc2hsViaAsm ? stdenv.hostPlatform.isWindows,
90 extraLibraries ? [ ],
91 librarySystemDepends ? [ ],
92 executableSystemDepends ? [ ],
93 # On macOS, statically linking against system frameworks is not supported;
94 # see https://developer.apple.com/library/content/qa/qa1118/_index.html
95 # They must be propagated to the environment of any executable linking with the library
96 libraryFrameworkDepends ? [ ],
97 executableFrameworkDepends ? [ ],
98 homepage ? "https://hackage.haskell.org/package/${pname}",
99 platforms ? with lib.platforms; all, # GHC can cross-compile
100 badPlatforms ? lib.platforms.none,
101 hydraPlatforms ? null,
102 hyperlinkSource ? true,
103 isExecutable ? false,
104 isLibrary ? !isExecutable,
105 jailbreak ? false,
106 license,
107 enableParallelBuilding ? true,
108 maintainers ? null,
109 teams ? null,
110 changelog ? null,
111 mainProgram ? null,
112 doCoverage ? false,
113 doHaddock ? !(ghc.isHaLVM or false) && (ghc.hasHaddock or true),
114 doHaddockInterfaces ? doHaddock && lib.versionAtLeast ghc.version "9.0.1",
115 passthru ? { },
116 pkg-configDepends ? [ ],
117 libraryPkgconfigDepends ? [ ],
118 executablePkgconfigDepends ? [ ],
119 testPkgconfigDepends ? [ ],
120 benchmarkPkgconfigDepends ? [ ],
121 testDepends ? [ ],
122 testHaskellDepends ? [ ],
123 testSystemDepends ? [ ],
124 testFrameworkDepends ? [ ],
125 benchmarkDepends ? [ ],
126 benchmarkHaskellDepends ? [ ],
127 benchmarkSystemDepends ? [ ],
128 benchmarkFrameworkDepends ? [ ],
129 # testTarget is deprecated. Use testTargets instead.
130 testTarget ? "",
131 testTargets ? lib.strings.splitString " " testTarget,
132 testFlags ? [ ],
133 broken ? false,
134 preCompileBuildDriver ? null,
135 postCompileBuildDriver ? null,
136 preUnpack ? null,
137 postUnpack ? null,
138 patches ? null,
139 patchPhase ? null,
140 prePatch ? "",
141 postPatch ? "",
142 preConfigure ? null,
143 postConfigure ? null,
144 preBuild ? null,
145 postBuild ? null,
146 preHaddock ? null,
147 postHaddock ? null,
148 installPhase ? null,
149 preInstall ? null,
150 postInstall ? null,
151 checkPhase ? null,
152 preCheck ? null,
153 postCheck ? null,
154 preFixup ? null,
155 postFixup ? null,
156 shellHook ? "",
157 coreSetup ? false, # Use only core packages to build Setup.hs.
158 useCpphs ? false,
159 hardeningDisable ? null,
160 enableSeparateBinOutput ? false,
161 enableSeparateDataOutput ? false,
162 enableSeparateDocOutput ? doHaddock,
163 enableSeparateIntermediatesOutput ? false,
164 # Don't fail at configure time if there are multiple versions of the
165 # same package in the (recursive) dependencies of the package being
166 # built. Will delay failures, if any, to compile time.
167 allowInconsistentDependencies ? false,
168 maxBuildCores ? 16, # more cores usually don't improve performance: https://ghc.haskell.org/trac/ghc/ticket/9221
169 # If set to true, this builds a pre-linked .o file for this Haskell library.
170 # This can make it slightly faster to load this library into GHCi, but takes
171 # extra disk space and compile time.
172 enableLibraryForGhci ? false,
173 # Set this to a previous build of this same package to reuse the intermediate
174 # build products from that prior build as a starting point for accelerating
175 # this build
176 previousIntermediates ? null,
177 # References to these store paths are forbidden in the produced output.
178 disallowedRequisites ? [ ],
179 # Whether to allow the produced output to refer to `ghc`.
180 #
181 # This is used by `haskell.lib.justStaticExecutables` to help prevent static
182 # Haskell binaries from having erroneous dependencies on GHC.
183 #
184 # See https://nixos.org/manual/nixpkgs/unstable/#haskell-packaging-helpers
185 # or its source doc/languages-frameworks/haskell.section.md
186 disallowGhcReference ? false,
187 # Cabal 3.8 which is shipped by default for GHC >= 9.3 always calls
188 # `pkg-config --libs --static` as part of the configure step. This requires
189 # Requires.private dependencies of pkg-config dependencies to be present in
190 # PKG_CONFIG_PATH which is normally not the case in nixpkgs (except in pkgsStatic).
191 # Since there is no patch or upstream patch yet, we replicate the automatic
192 # propagation of dependencies in pkgsStatic for allPkgConfigDepends for
193 # GHC >= 9.3 by default. This option allows overriding this behavior manually
194 # if mismatching Cabal and GHC versions are used.
195 # See also <https://github.com/haskell/cabal/issues/8455>.
196 __propagatePkgConfigDepends ? lib.versionAtLeast ghc.version "9.3",
197 # Propagation can easily lead to the argv limit being exceeded in linker or C
198 # compiler invocations. To work around this we can only propagate derivations
199 # that are known to provide pkg-config modules, as indicated by the presence
200 # of `meta.pkgConfigModules`. This option defaults to false for now, since
201 # this metadata is far from complete in nixpkgs.
202 __onlyPropagateKnownPkgConfigModules ? false,
203}@args:
204
205assert editedCabalFile != null -> revision != null;
206
207# --enable-static does not work on windows. This is a bug in GHC.
208# --enable-static will pass -staticlib to ghc, which only works for mach-o and elf.
209assert stdenv.hostPlatform.isWindows -> enableStaticLibraries == false;
210assert stdenv.hostPlatform.isWasm -> enableStaticLibraries == false;
211
212let
213
214 inherit (lib)
215 optional
216 optionals
217 optionalString
218 versionAtLeast
219 concatStringsSep
220 enableFeature
221 optionalAttrs
222 ;
223
224 isHaLVM = ghc.isHaLVM or false;
225
226 # GHC used for building Setup.hs
227 #
228 # Same as our GHC, unless we're cross, in which case it is native GHC with the
229 # same version.
230 nativeGhc = buildHaskellPackages.ghc;
231
232 # the target dir for haddock documentation
233 docdir = docoutput: docoutput + "/share/doc/" + pname + "-" + version;
234
235 binDir = if enableSeparateBinOutput then "$bin/bin" else "$out/bin";
236
237 newCabalFileUrl = "mirror://hackage/${pname}-${version}/revision/${revision}.cabal";
238 newCabalFile = fetchurl {
239 url = newCabalFileUrl;
240 sha256 = editedCabalFile;
241 name = "${pname}-${version}-r${revision}.cabal";
242 };
243
244 defaultSetupHs = builtins.toFile "Setup.hs" ''
245 import Distribution.Simple
246 main = defaultMain
247 '';
248
249 # This awk expression transforms a package conf file like
250 #
251 # author: John Doe <john-doe@example.com>
252 # description:
253 # The purpose of this library is to do
254 # foo and bar among other things
255 #
256 # into a more easily processeable form:
257 #
258 # author: John Doe <john-doe@example.com>
259 # description: The purpose of this library is to do foo and bar among other things
260 unprettyConf = builtins.toFile "unpretty-cabal-conf.awk" ''
261 /^[^ ]+:/ {
262 # When the line starts with a new field, terminate the previous one with a newline
263 if (started == 1) print ""
264 # to strip leading spaces
265 $1=$1
266 printf "%s", $0
267 started=1
268 }
269
270 /^ +/ {
271 # to strip leading spaces
272 $1=$1
273 printf " %s", $0
274 }
275
276 # Terminate the final field with a newline
277 END { print "" }
278 '';
279
280 crossCabalFlags = [
281 "--with-ghc=${ghcCommand}"
282 "--with-ghc-pkg=${ghc.targetPrefix}ghc-pkg"
283 "--with-gcc=${cc}"
284 ]
285 ++ optionals stdenv.hasCC [
286 "--with-ld=${stdenv.cc.bintools.targetPrefix}ld"
287 "--with-ar=${stdenv.cc.bintools.targetPrefix}ar"
288 # use the one that comes with the cross compiler.
289 "--with-hsc2hs=${ghc.targetPrefix}hsc2hs"
290 "--with-strip=${stdenv.cc.bintools.targetPrefix}strip"
291 ]
292 ++ optionals (!isHaLVM) [
293 "--hsc2hs-option=--cross-compile"
294 (optionalString enableHsc2hsViaAsm "--hsc2hs-option=--via-asm")
295 ]
296 ++ optional (allPkgconfigDepends != [ ]) "--with-pkg-config=${pkg-config.targetPrefix}pkg-config";
297
298 makeGhcOptions = opts: lib.concatStringsSep " " (map (opt: "--ghc-option=${opt}") opts);
299
300 buildFlagsString = optionalString (buildFlags != [ ]) (" " + concatStringsSep " " buildFlags);
301
302 defaultConfigureFlags = [
303 "--verbose"
304 "--prefix=$out"
305 # Note: This must be kept in sync manually with mkGhcLibdir
306 ("--libdir=\\$prefix/lib/\\$compiler" + lib.optionalString (ghc ? hadrian) "/lib")
307 "--libsubdir=\\$abi/\\$libname"
308 (optionalString enableSeparateDataOutput "--datadir=$data/share/${ghcNameWithPrefix}")
309 (optionalString enableSeparateDocOutput "--docdir=${docdir "$doc"}")
310 ]
311 ++ optionals stdenv.hasCC [
312 "--with-gcc=$CC" # Clang won't work without that extra information.
313 ]
314 ++ [
315 "--package-db=$packageConfDir"
316 (optionalString (
317 enableSharedExecutables && stdenv.hostPlatform.isLinux
318 ) "--ghc-option=-optl=-Wl,-rpath=$out/${ghcLibdir}/${pname}-${version}")
319 (optionalString (
320 enableSharedExecutables && stdenv.hostPlatform.isDarwin
321 ) "--ghc-option=-optl=-Wl,-headerpad_max_install_names")
322 (optionalString enableParallelBuilding (makeGhcOptions [
323 "-j$NIX_BUILD_CORES"
324 "+RTS"
325 "-A64M"
326 "-RTS"
327 ]))
328 (optionalString useCpphs (
329 "--with-cpphs=${cpphs}/bin/cpphs "
330 + (makeGhcOptions [
331 "-cpp"
332 "-pgmP${cpphs}/bin/cpphs"
333 "-optP--cpp"
334 ])
335 ))
336 (enableFeature enableLibraryProfiling "library-profiling")
337 (optionalString (
338 enableExecutableProfiling || enableLibraryProfiling
339 ) "--profiling-detail=${profilingDetail}")
340 (enableFeature enableExecutableProfiling "profiling")
341 (enableFeature enableSharedLibraries "shared")
342 (enableFeature doCoverage "coverage")
343 (enableFeature enableStaticLibraries "static")
344 (enableFeature enableSharedExecutables "executable-dynamic")
345 (enableFeature doCheck "tests")
346 (enableFeature doBenchmark "benchmarks")
347 "--enable-library-vanilla" # TODO: Should this be configurable?
348 (enableFeature enableLibraryForGhci "library-for-ghci")
349 (enableFeature enableDeadCodeElimination "split-sections")
350 (enableFeature (!dontStrip) "library-stripping")
351 (enableFeature (!dontStrip) "executable-stripping")
352 ]
353 ++ optionals isCross (
354 [
355 "--configure-option=--host=${stdenv.hostPlatform.config}"
356 ]
357 ++ crossCabalFlags
358 )
359 ++ optionals enableSeparateBinOutput [
360 "--bindir=${binDir}"
361 ]
362 ++ optionals (doHaddockInterfaces && isLibrary) [
363 "--ghc-option=-haddock"
364 ];
365
366 postPhases = optional doInstallIntermediates "installIntermediatesPhase";
367
368 setupCompileFlags = [
369 (optionalString (!coreSetup) "-package-db=$setupPackageConfDir")
370 "-threaded" # https://github.com/haskell/cabal/issues/2398
371 ];
372
373 isHaskellPkg = x: x ? isHaskellLibrary;
374
375 # Work around a Cabal bug requiring pkg-config --static --libs to work even
376 # when linking dynamically, affecting Cabal 3.8 and 3.9.
377 # https://github.com/haskell/cabal/issues/8455
378 #
379 # For this, we treat the runtime system/pkg-config dependencies of a Haskell
380 # derivation as if they were propagated from their dependencies which allows
381 # pkg-config --static to work in most cases.
382 allPkgconfigDepends =
383 let
384 # If __onlyPropagateKnownPkgConfigModules is set, packages without
385 # meta.pkgConfigModules will be filtered out, otherwise all packages in
386 # buildInputs and propagatePlainBuildInputs are propagated.
387 propagateValue =
388 drv: lib.isDerivation drv && (__onlyPropagateKnownPkgConfigModules -> drv ? meta.pkgConfigModules);
389
390 # Take list of derivations and return list of the transitive dependency
391 # closure, only taking into account buildInputs. Loosely based on
392 # closePropagationFast.
393 propagatePlainBuildInputs =
394 drvs:
395 builtins.map (i: i.val) (
396 builtins.genericClosure {
397 startSet = builtins.map (drv: {
398 key = drv.outPath;
399 val = drv;
400 }) (builtins.filter propagateValue drvs);
401 operator =
402 { val, ... }:
403 builtins.concatMap (
404 drv:
405 if propagateValue drv then
406 [
407 {
408 key = drv.outPath;
409 val = drv;
410 }
411 ]
412 else
413 [ ]
414 ) (val.buildInputs or [ ] ++ val.propagatedBuildInputs or [ ]);
415 }
416 );
417 in
418
419 if __propagatePkgConfigDepends then
420 propagatePlainBuildInputs allPkgconfigDepends'
421 else
422 allPkgconfigDepends';
423 allPkgconfigDepends' =
424 pkg-configDepends
425 ++ libraryPkgconfigDepends
426 ++ executablePkgconfigDepends
427 ++ optionals doCheck testPkgconfigDepends
428 ++ optionals doBenchmark benchmarkPkgconfigDepends;
429
430 depsBuildBuild = [
431 nativeGhc
432 ]
433 # CC_FOR_BUILD may be necessary if we have no C preprocessor for the host
434 # platform. See crossCabalFlags above for more details.
435 ++ lib.optionals (!stdenv.hasCC) [ buildPackages.stdenv.cc ];
436 collectedToolDepends =
437 buildTools
438 ++ libraryToolDepends
439 ++ executableToolDepends
440 ++ optionals doCheck testToolDepends
441 ++ optionals doBenchmark benchmarkToolDepends;
442 nativeBuildInputs = [
443 ghc
444 removeReferencesTo
445 ]
446 ++ optional (allPkgconfigDepends != [ ]) (
447 assert pkg-config != null;
448 pkg-config
449 )
450 ++ setupHaskellDepends
451 ++ collectedToolDepends
452 ++ optional stdenv.hostPlatform.isGhcjs nodejs;
453 propagatedBuildInputs =
454 buildDepends ++ libraryHaskellDepends ++ executableHaskellDepends ++ libraryFrameworkDepends;
455 otherBuildInputsHaskell =
456 optionals doCheck (testDepends ++ testHaskellDepends)
457 ++ optionals doBenchmark (benchmarkDepends ++ benchmarkHaskellDepends);
458 otherBuildInputsSystem =
459 extraLibraries
460 ++ librarySystemDepends
461 ++ executableSystemDepends
462 ++ executableFrameworkDepends
463 ++ allPkgconfigDepends
464 ++ optionals doCheck (testSystemDepends ++ testFrameworkDepends)
465 ++ optionals doBenchmark (benchmarkSystemDepends ++ benchmarkFrameworkDepends);
466 # TODO next rebuild just define as `otherBuildInputsHaskell ++ otherBuildInputsSystem`
467 otherBuildInputs =
468 extraLibraries
469 ++ librarySystemDepends
470 ++ executableSystemDepends
471 ++ executableFrameworkDepends
472 ++ allPkgconfigDepends
473 ++ optionals doCheck (
474 testDepends ++ testHaskellDepends ++ testSystemDepends ++ testFrameworkDepends
475 )
476 ++ optionals doBenchmark (
477 benchmarkDepends ++ benchmarkHaskellDepends ++ benchmarkSystemDepends ++ benchmarkFrameworkDepends
478 );
479
480 setupCommand = "./Setup";
481
482 ghcCommand' = "ghc";
483 ghcCommand = "${ghc.targetPrefix}${ghcCommand'}";
484
485 ghcNameWithPrefix = "${ghc.targetPrefix}${ghc.haskellCompilerName}";
486 mkGhcLibdir =
487 ghc:
488 "lib/${ghc.targetPrefix}${ghc.haskellCompilerName}" + lib.optionalString (ghc ? hadrian) "/lib";
489 ghcLibdir = mkGhcLibdir ghc;
490
491 nativeGhcCommand = "${nativeGhc.targetPrefix}ghc";
492
493 buildPkgDb = thisGhc: packageConfDir: ''
494 # If this dependency has a package database, then copy the contents of it,
495 # unless it is one of our GHCs. These can appear in our dependencies when
496 # we are doing native builds, and they have package databases in them, but
497 # we do not want to copy them over.
498 #
499 # We don't need to, since those packages will be provided by the GHC when
500 # we compile with it, and doing so can result in having multiple copies of
501 # e.g. Cabal in the database with the same name and version, which is
502 # ambiguous.
503 if [ -d "$p/${mkGhcLibdir thisGhc}/package.conf.d" ] && [ "$p" != "${ghc}" ] && [ "$p" != "${nativeGhc}" ]; then
504 cp -f "$p/${mkGhcLibdir thisGhc}/package.conf.d/"*.conf ${packageConfDir}/
505 continue
506 fi
507 '';
508
509 intermediatesDir = "share/haskell/${ghc.version}/${pname}-${version}/dist";
510
511 jsexe = rec {
512 shouldAdd = stdenv.hostPlatform.isGhcjs && isExecutable;
513 shouldCopy = shouldAdd && !doInstallIntermediates;
514 shouldSymlink = shouldAdd && doInstallIntermediates;
515 };
516
517 # This is a script suitable for --test-wrapper of Setup.hs' test command
518 # (https://cabal.readthedocs.io/en/3.12/setup-commands.html#cmdoption-runhaskell-Setup.hs-test-test-wrapper).
519 # We use it to set some environment variables that the test suite may need,
520 # e.g. GHC_PACKAGE_PATH to invoke GHC(i) at runtime with build dependencies
521 # available. See the comment accompanying checkPhase below on how to customize
522 # this behavior. We need to use a wrapper script since Cabal forbids setting
523 # certain environment variables since they can alter GHC's behavior (e.g.
524 # GHC_PACKAGE_PATH) and cause failures. While building, Cabal will set
525 # GHC_ENVIRONMENT to make the packages picked at configure time available to
526 # GHC, but unfortunately not at test time. The test wrapper script will be
527 # executed after such environment checks, so we can take some liberties which
528 # is unproblematic since we know our synthetic package db matches what Cabal
529 # will see at configure time exactly. See also
530 # <https://github.com/haskell/cabal/issues/7792>.
531 testWrapperScript = buildPackages.writeShellScript "haskell-generic-builder-test-wrapper.sh" ''
532 set -eu
533
534 # We expect this to be either empty or set by checkPhase
535 if [[ -n "''${NIX_GHC_PACKAGE_PATH_FOR_TEST}" ]]; then
536 export GHC_PACKAGE_PATH="''${NIX_GHC_PACKAGE_PATH_FOR_TEST}"
537 fi
538
539 exec "$@"
540 '';
541
542 testTargetsString =
543 lib.warnIf (testTarget != "")
544 "haskellPackages.mkDerivation: testTarget is deprecated. Use testTargets instead"
545 (lib.concatStringsSep " " testTargets);
546
547 env' = {
548 LANG = "en_US.UTF-8"; # GHC needs the locale configured during the Haddock phase.
549 }
550 // env
551 # Implicit pointer to integer conversions are errors by default since clang 15.
552 # Works around https://gitlab.haskell.org/ghc/ghc/-/issues/23456.
553 // optionalAttrs (stdenv.hasCC && stdenv.cc.isClang) {
554 NIX_CFLAGS_COMPILE =
555 "-Wno-error=int-conversion"
556 + lib.optionalString (env ? NIX_CFLAGS_COMPILE) (" " + env.NIX_CFLAGS_COMPILE);
557 };
558
559in
560lib.fix (
561 drv:
562
563 stdenv.mkDerivation (
564 {
565 inherit pname version;
566
567 outputs = [
568 "out"
569 ]
570 ++ (optional enableSeparateDataOutput "data")
571 ++ (optional enableSeparateDocOutput "doc")
572 ++ (optional enableSeparateBinOutput "bin")
573 ++ (optional enableSeparateIntermediatesOutput "intermediates");
574
575 setOutputFlags = false;
576
577 pos = builtins.unsafeGetAttrPos "pname" args;
578
579 prePhases = [ "setupCompilerEnvironmentPhase" ];
580 preConfigurePhases = [ "compileBuildDriverPhase" ];
581 preInstallPhases = [ "haddockPhase" ];
582
583 inherit src;
584
585 inherit depsBuildBuild nativeBuildInputs;
586 buildInputs =
587 otherBuildInputs
588 ++ optionals (!isLibrary) propagatedBuildInputs
589 # For patchShebangsAuto in fixupPhase
590 ++ optionals stdenv.hostPlatform.isGhcjs [ nodejs ];
591 propagatedBuildInputs = optionals isLibrary propagatedBuildInputs;
592
593 env =
594 optionalAttrs (stdenv.buildPlatform.libc == "glibc") {
595 LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive";
596 }
597 // env';
598
599 prePatch =
600 optionalString (editedCabalFile != null) ''
601 echo "Replace Cabal file with edited version from ${newCabalFileUrl}."
602 cp ${newCabalFile} ${pname}.cabal
603 ''
604 + prePatch;
605
606 postPatch =
607 optionalString jailbreak ''
608 echo "Run jailbreak-cabal to lift version restrictions on build inputs."
609 ${jailbreak-cabal}/bin/jailbreak-cabal ${pname}.cabal
610 ''
611 + postPatch;
612
613 setupCompilerEnvironmentPhase = ''
614 NIX_BUILD_CORES=$(( NIX_BUILD_CORES < ${toString maxBuildCores} ? NIX_BUILD_CORES : ${toString maxBuildCores} ))
615 runHook preSetupCompilerEnvironment
616
617 echo "Build with ${ghc}."
618 ${optionalString (isLibrary && hyperlinkSource) "export PATH=${hscolour}/bin:$PATH"}
619
620 builddir="$(mktemp -d)"
621 setupPackageConfDir="$builddir/setup-package.conf.d"
622 mkdir -p $setupPackageConfDir
623 packageConfDir="$builddir/package.conf.d"
624 mkdir -p $packageConfDir
625
626 setupCompileFlags="${concatStringsSep " " setupCompileFlags}"
627 configureFlags="${concatStringsSep " " defaultConfigureFlags} $configureFlags"
628 ''
629 # We build the Setup.hs on the *build* machine, and as such should only add
630 # dependencies for the build machine.
631 #
632 # pkgs* arrays defined in stdenv/setup.hs
633 + ''
634 for p in "''${pkgsBuildBuild[@]}" "''${pkgsBuildHost[@]}" "''${pkgsBuildTarget[@]}"; do
635 ${buildPkgDb nativeGhc "$setupPackageConfDir"}
636 done
637 ${nativeGhcCommand}-pkg --package-db="$setupPackageConfDir" recache
638 ''
639 # For normal components
640 + ''
641 for p in "''${pkgsHostHost[@]}" "''${pkgsHostTarget[@]}"; do
642 ${buildPkgDb ghc "$packageConfDir"}
643 if [ -d "$p/include" ]; then
644 appendToVar configureFlags "--extra-include-dirs=$p/include"
645 fi
646 if [ -d "$p/lib" ]; then
647 appendToVar configureFlags "--extra-lib-dirs=$p/lib"
648 fi
649 if [[ -d "$p/Library/Frameworks" ]]; then
650 appendToVar configureFlags "--extra-framework-dirs=$p/Library/Frameworks"
651 fi
652 ''
653 + ''
654 done
655 ''
656 + (optionalString stdenv.hostPlatform.isGhcjs ''
657 export EM_CACHE="$(realpath "$(mktemp -d emcache.XXXXXXXXXX)")"
658 cp -Lr ${emscripten}/share/emscripten/cache/* "$EM_CACHE/"
659 chmod u+rwX -R "$EM_CACHE"
660 '')
661 # only use the links hack if we're actually building dylibs. otherwise, the
662 # "dynamic-library-dirs" point to nonexistent paths, and the ln command becomes
663 # "ln -s $out/lib/links", which tries to recreate the links dir and fails
664 #
665 # Note: We need to disable this work-around when using intermediate build
666 # products from a prior build because otherwise Nix will change permissions on
667 # the `$out/lib/links` directory to read-only when the build is done after the
668 # dist directory has already been exported, which triggers an unnecessary
669 # rebuild of modules included in the exported dist directory.
670 + (optionalString
671 (
672 stdenv.hostPlatform.isDarwin
673 && (enableSharedLibraries || enableSharedExecutables)
674 && !enableSeparateIntermediatesOutput
675 )
676 ''
677 # Work around a limit in the macOS Sierra linker on the number of paths
678 # referenced by any one dynamic library:
679 #
680 # Create a local directory with symlinks of the *.dylib (macOS shared
681 # libraries) from all the dependencies.
682 local dynamicLinksDir="$out/lib/links"
683 mkdir -p $dynamicLinksDir
684
685 # Unprettify all package conf files before reading/writing them
686 for d in "$packageConfDir/"*; do
687 # gawk -i inplace seems to strip the last newline
688 gawk -f ${unprettyConf} "$d" > tmp
689 mv tmp "$d"
690 done
691
692 for d in $(grep '^dynamic-library-dirs:' "$packageConfDir"/* | cut -d' ' -f2- | tr ' ' '\n' | sort -u); do
693 for lib in "$d/"*.{dylib,so}; do
694 # Allow overwriting because C libs can be pulled in multiple times.
695 ln -sf "$lib" "$dynamicLinksDir"
696 done
697 done
698 # Edit the local package DB to reference the links directory.
699 for f in "$packageConfDir/"*.conf; do
700 sed -i "s,dynamic-library-dirs: .*,dynamic-library-dirs: $dynamicLinksDir," "$f"
701 done
702 ''
703 )
704 + ''
705 ${ghcCommand}-pkg --package-db="$packageConfDir" recache
706
707 runHook postSetupCompilerEnvironment
708 '';
709
710 compileBuildDriverPhase = ''
711 runHook preCompileBuildDriver
712
713 for i in Setup.hs Setup.lhs ${defaultSetupHs}; do
714 test -f $i && break
715 done
716
717 echo setupCompileFlags: $setupCompileFlags
718 ${nativeGhcCommand} $setupCompileFlags --make -o Setup -odir $builddir -hidir $builddir $i
719
720 runHook postCompileBuildDriver
721 '';
722
723 # Cabal takes flags like `--configure-option=--host=...` instead
724 configurePlatforms = [ ];
725 inherit configureFlags;
726
727 # Note: the options here must be always added, regardless of whether the
728 # package specifies `hardeningDisable`.
729 hardeningDisable =
730 lib.optionals (args ? hardeningDisable) hardeningDisable
731 ++ lib.optional (ghc.isHaLVM or false) "all"
732 # Static libraries (ie. all of pkgsStatic.haskellPackages) fail to build
733 # because by default Nix adds `-pie` to the linker flags: this
734 # conflicts with the `-r` and `-no-pie` flags added by GHC (see
735 # https://gitlab.haskell.org/ghc/ghc/-/issues/19580). hardeningDisable
736 # changes the default Nix behavior regarding adding "hardening" flags.
737 ++ lib.optional enableStaticLibraries "pie";
738
739 configurePhase = ''
740 runHook preConfigure
741
742 echo configureFlags: $configureFlags
743 ${setupCommand} configure $configureFlags 2>&1 | ${coreutils}/bin/tee "$NIX_BUILD_TOP/cabal-configure.log"
744 ${lib.optionalString (!allowInconsistentDependencies) ''
745 if grep -E -q -z 'Warning:.*depends on multiple versions' "$NIX_BUILD_TOP/cabal-configure.log"; then
746 echo >&2 "*** abort because of serious configure-time warning from Cabal"
747 exit 1
748 fi
749 ''}
750
751 runHook postConfigure
752 '';
753
754 buildPhase = ''
755 runHook preBuild
756 ''
757 + lib.optionalString (previousIntermediates != null) ''
758 mkdir -p dist;
759 rm -r dist/build
760 cp -r ${previousIntermediates}/${intermediatesDir}/build dist/build
761 find dist/build -exec chmod u+w {} +
762 find dist/build -exec touch -d '1970-01-01T00:00:00Z' {} +
763 ''
764 + ''
765 ${setupCommand} build ${buildTarget}${buildFlagsString}
766 runHook postBuild
767 '';
768
769 inherit doCheck;
770
771 # Run test suite(s) and pass `checkFlags` as well as `checkFlagsArray`.
772 # `testFlags` are added to `checkFlagsArray` each prefixed with
773 # `--test-option`, so Cabal passes it to the underlying test suite binary.
774 #
775 # We also take care of setting GHC_PACKAGE_PATH during test suite execution,
776 # so it can run GHC(i) with build dependencies available:
777 # - If NIX_GHC_PACKAGE_PATH_FOR_TEST is set, it become the value of GHC_PACKAGE_PATH
778 # while the test suite is executed.
779 # - If it is empty, it'll be unset during test suite execution.
780 # - Otherwise GHC_PACKAGE_PATH will have the package db used for configuring
781 # plus GHC's core packages.
782 checkPhase = ''
783 runHook preCheck
784 checkFlagsArray+=(
785 "--show-details=streaming"
786 "--test-wrapper=${testWrapperScript}"
787 ${lib.escapeShellArgs (builtins.map (opt: "--test-option=${opt}") testFlags)}
788 )
789 export NIX_GHC_PACKAGE_PATH_FOR_TEST="''${NIX_GHC_PACKAGE_PATH_FOR_TEST:-$packageConfDir:}"
790 ${setupCommand} test ${testTargetsString} $checkFlags ''${checkFlagsArray:+"''${checkFlagsArray[@]}"}
791 runHook postCheck
792 '';
793
794 haddockPhase = ''
795 runHook preHaddock
796 ${optionalString (doHaddock && isLibrary) ''
797 ${setupCommand} haddock --html \
798 ${optionalString doHoogle "--hoogle"} \
799 ${optionalString doHaddockQuickjump "--quickjump"} \
800 ${optionalString (isLibrary && hyperlinkSource) "--hyperlink-source"} \
801 ${lib.concatStringsSep " " haddockFlags}
802 ''}
803 runHook postHaddock
804 '';
805
806 installPhase = ''
807 runHook preInstall
808
809 ${
810 if !isLibrary && buildTarget == "" then
811 "${setupCommand} install"
812 # ^^ if the project is not a library, and no build target is specified, we can just use "install".
813 else if !isLibrary then
814 "${setupCommand} copy ${buildTarget}"
815 # ^^ if the project is not a library, and we have a build target, then use "copy" to install
816 # just the target specified; "install" will error here, since not all targets have been built.
817 else
818 ''
819 ${setupCommand} copy ${buildTarget}
820 local packageConfDir="$out/${ghcLibdir}/package.conf.d"
821 local packageConfFile="$packageConfDir/${pname}-${version}.conf"
822 mkdir -p "$packageConfDir"
823 ${setupCommand} register --gen-pkg-config=$packageConfFile
824 if [ -d "$packageConfFile" ]; then
825 mv "$packageConfFile/"* "$packageConfDir"
826 rmdir "$packageConfFile"
827 fi
828 for packageConfFile in "$packageConfDir/"*; do
829 local pkgId=$(gawk -f ${unprettyConf} "$packageConfFile" \
830 | grep '^id:' | cut -d' ' -f2)
831 mv "$packageConfFile" "$packageConfDir/$pkgId.conf"
832 done
833
834 # delete confdir if there are no libraries
835 find $packageConfDir -maxdepth 0 -empty -delete;
836 ''
837 }
838
839
840 ${optionalString doCoverage "mkdir -p $out/share && cp -r dist/hpc $out/share"}
841
842 ${optionalString jsexe.shouldCopy ''
843 for jsexeDir in dist/build/*/*.jsexe; do
844 bn=$(basename $jsexeDir)
845 exe="''${bn%.jsexe}"
846 cp -r dist/build/$exe/$exe.jsexe ${binDir}
847 done
848 ''}
849
850 ${optionalString enableSeparateDocOutput ''
851 for x in ${docdir "$doc"}"/html/src/"*.html; do
852 remove-references-to -t $out $x
853 done
854 mkdir -p $doc
855 ''}
856 ${optionalString enableSeparateDataOutput "mkdir -p $data"}
857
858 runHook postInstall
859 '';
860
861 ${if doInstallIntermediates then "installIntermediatesPhase" else null} = ''
862 runHook preInstallIntermediates
863 intermediatesOutput=${if enableSeparateIntermediatesOutput then "$intermediates" else "$out"}
864 installIntermediatesDir="$intermediatesOutput/${intermediatesDir}"
865 mkdir -p "$installIntermediatesDir"
866 cp -r dist/build "$installIntermediatesDir"
867 runHook postInstallIntermediates
868
869 ${optionalString jsexe.shouldSymlink ''
870 for jsexeDir in $installIntermediatesDir/build/*/*.jsexe; do
871 bn=$(basename $jsexeDir)
872 exe="''${bn%.jsexe}"
873 (cd ${binDir} && ln -s $installIntermediatesDir/build/$exe/$exe.jsexe)
874 done
875 ''}
876 '';
877
878 passthru = passthru // rec {
879
880 inherit pname version disallowGhcReference;
881
882 compiler = ghc;
883
884 # All this information is intended just for `shellFor`. It should be
885 # considered unstable and indeed we knew how to keep it private we would.
886 getCabalDeps = {
887 inherit
888 buildDepends
889 buildTools
890 executableFrameworkDepends
891 executableHaskellDepends
892 executablePkgconfigDepends
893 executableSystemDepends
894 executableToolDepends
895 extraLibraries
896 libraryFrameworkDepends
897 libraryHaskellDepends
898 libraryPkgconfigDepends
899 librarySystemDepends
900 libraryToolDepends
901 pkg-configDepends
902 setupHaskellDepends
903 ;
904 }
905 // lib.optionalAttrs doCheck {
906 inherit
907 testDepends
908 testFrameworkDepends
909 testHaskellDepends
910 testPkgconfigDepends
911 testSystemDepends
912 testToolDepends
913 ;
914 }
915 // lib.optionalAttrs doBenchmark {
916 inherit
917 benchmarkDepends
918 benchmarkFrameworkDepends
919 benchmarkHaskellDepends
920 benchmarkPkgconfigDepends
921 benchmarkSystemDepends
922 benchmarkToolDepends
923 ;
924 };
925
926 # Attributes for the old definition of `shellFor`. Should be removed but
927 # this predates the warning at the top of `getCabalDeps`.
928 getBuildInputs = rec {
929 inherit propagatedBuildInputs otherBuildInputs allPkgconfigDepends;
930 haskellBuildInputs = isHaskellPartition.right;
931 systemBuildInputs = isHaskellPartition.wrong;
932 isHaskellPartition = lib.partition isHaskellPkg (
933 propagatedBuildInputs ++ otherBuildInputs ++ depsBuildBuild ++ nativeBuildInputs
934 );
935 };
936
937 isHaskellLibrary = isLibrary;
938
939 # TODO: ask why the split outputs are configurable at all?
940 # TODO: include tests for split if possible
941 # Given the haskell package, returns
942 # the directory containing the haddock documentation.
943 # `null' if no haddock documentation was built.
944 # TODO: fetch the self from the fixpoint instead
945 haddockDir = self: if doHaddock then "${docdir self.doc}/html" else null;
946
947 # Creates a derivation containing all of the necessary dependencies for building the
948 # parent derivation. The attribute set that it takes as input can be viewed as:
949 #
950 # { withHoogle }
951 #
952 # The derivation that it builds contains no outpaths because it is meant for use
953 # as an environment
954 #
955 # # Example use
956 # # Creates a shell with all of the dependencies required to build the "hello" package,
957 # # and with python:
958 #
959 # > nix-shell -E 'with (import <nixpkgs> {}); \
960 # > haskellPackages.hello.envFunc { buildInputs = [ python ]; }'
961 envFunc =
962 {
963 withHoogle ? false,
964 }:
965 let
966 name = "ghc-shell-for-${drv.name}";
967
968 withPackages = if withHoogle then ghcWithHoogle else ghcWithPackages;
969
970 # We use the `ghcWithPackages` function from `buildHaskellPackages` if we
971 # want a shell for the sake of cross compiling a package. In the native case
972 # we don't use this at all, and instead put the setupDepends in the main
973 # `ghcWithPackages`. This way we don't have two wrapper scripts called `ghc`
974 # shadowing each other on the PATH.
975 ghcEnvForBuild =
976 assert isCross;
977 buildHaskellPackages.ghcWithPackages (_: setupHaskellDepends);
978
979 ghcEnv = withPackages (
980 _: otherBuildInputsHaskell ++ propagatedBuildInputs ++ lib.optionals (!isCross) setupHaskellDepends
981 );
982
983 ghcCommandCaps = lib.toUpper ghcCommand';
984 in
985 runCommandCC name {
986 inherit shellHook;
987
988 depsBuildBuild = lib.optional isCross ghcEnvForBuild;
989 nativeBuildInputs = [
990 ghcEnv
991 ]
992 ++ optional (allPkgconfigDepends != [ ]) pkg-config
993 ++ collectedToolDepends;
994 buildInputs = otherBuildInputsSystem;
995
996 env = {
997 "NIX_${ghcCommandCaps}" = "${ghcEnv}/bin/${ghcCommand}";
998 "NIX_${ghcCommandCaps}PKG" = "${ghcEnv}/bin/${ghcCommand}-pkg";
999 # TODO: is this still valid?
1000 "NIX_${ghcCommandCaps}_DOCDIR" = "${ghcEnv}/share/doc/ghc/html";
1001 "NIX_${ghcCommandCaps}_LIBDIR" =
1002 if ghc.isHaLVM or false then "${ghcEnv}/lib/HaLVM-${ghc.version}" else "${ghcEnv}/${ghcLibdir}";
1003 }
1004 // optionalAttrs (stdenv.buildPlatform.libc == "glibc") {
1005 # TODO: Why is this written in terms of `buildPackages`, unlike
1006 # the outer `env`?
1007 #
1008 # According to @sternenseemann [1]:
1009 #
1010 # > The condition is based on `buildPlatform`, so it needs to
1011 # > match. `LOCALE_ARCHIVE` is set to accompany `LANG` which
1012 # > concerns things we execute on the build platform like
1013 # > `haddock`.
1014 # >
1015 # > Arguably the outer non `buildPackages` one is incorrect and
1016 # > probably works by accident in most cases since the locale
1017 # > archive is not platform specific (the trouble is that it
1018 # > may sometimes be impossible to cross-compile). At least
1019 # > that would be my assumption.
1020 #
1021 # [1]: https://github.com/NixOS/nixpkgs/pull/424368#discussion_r2202683378
1022 LOCALE_ARCHIVE = "${buildPackages.glibcLocales}/lib/locale/locale-archive";
1023 }
1024 // env';
1025 } "echo $nativeBuildInputs $buildInputs > $out";
1026
1027 env = envFunc { };
1028
1029 };
1030
1031 meta = {
1032 inherit homepage license platforms;
1033 }
1034 // optionalAttrs (args ? broken) { inherit broken; }
1035 // optionalAttrs (args ? description) { inherit description; }
1036 // optionalAttrs (args ? maintainers) { inherit maintainers; }
1037 // optionalAttrs (args ? teams) { inherit teams; }
1038 // optionalAttrs (args ? hydraPlatforms) { inherit hydraPlatforms; }
1039 // optionalAttrs (args ? badPlatforms) { inherit badPlatforms; }
1040 // optionalAttrs (args ? changelog) { inherit changelog; }
1041 // optionalAttrs (args ? mainProgram) { inherit mainProgram; };
1042
1043 }
1044 // optionalAttrs (args ? sourceRoot) { inherit sourceRoot; }
1045 // optionalAttrs (args ? setSourceRoot) { inherit setSourceRoot; }
1046 // optionalAttrs (args ? preCompileBuildDriver) { inherit preCompileBuildDriver; }
1047 // optionalAttrs (args ? postCompileBuildDriver) { inherit postCompileBuildDriver; }
1048 // optionalAttrs (args ? preUnpack) { inherit preUnpack; }
1049 // optionalAttrs (args ? postUnpack) { inherit postUnpack; }
1050 // optionalAttrs (args ? patches) { inherit patches; }
1051 // optionalAttrs (args ? patchPhase) { inherit patchPhase; }
1052 // optionalAttrs (args ? preConfigure) { inherit preConfigure; }
1053 // optionalAttrs (args ? postConfigure) { inherit postConfigure; }
1054 // optionalAttrs (args ? preBuild) { inherit preBuild; }
1055 // optionalAttrs (args ? postBuild) { inherit postBuild; }
1056 // optionalAttrs (args ? doBenchmark) { inherit doBenchmark; }
1057 // optionalAttrs (args ? checkPhase) { inherit checkPhase; }
1058 // optionalAttrs (args ? preCheck) { inherit preCheck; }
1059 // optionalAttrs (args ? postCheck) { inherit postCheck; }
1060 // optionalAttrs (args ? preHaddock) { inherit preHaddock; }
1061 // optionalAttrs (args ? postHaddock) { inherit postHaddock; }
1062 // optionalAttrs (args ? preInstall) { inherit preInstall; }
1063 // optionalAttrs (args ? installPhase) { inherit installPhase; }
1064 // optionalAttrs (args ? postInstall) { inherit postInstall; }
1065 // optionalAttrs (args ? preFixup) { inherit preFixup; }
1066 // optionalAttrs (args ? postFixup) { inherit postFixup; }
1067 // optionalAttrs (args ? dontStrip) { inherit dontStrip; }
1068 // optionalAttrs (postPhases != [ ]) { inherit postPhases; }
1069 // optionalAttrs (disallowedRequisites != [ ] || disallowGhcReference) {
1070 disallowedRequisites = disallowedRequisites ++ (if disallowGhcReference then [ ghc ] else [ ]);
1071 }
1072 )
1073)