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