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