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