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