biome: 1.9.2 -> 1.9.3 (#349335)
[NixPkgs.git] / pkgs / development / haskell-modules / lib / compose.nix
blobcbefc44bb01d0a8b716db36d19259f5c6c0d4f0b
1 # TODO(@Ericson2314): Remove `pkgs` param, which is only used for
2 # `buildStackProject`, `justStaticExecutables` and `checkUnusedPackages`
3 { pkgs, lib }:
5 rec {
7   /* This function takes a file like `hackage-packages.nix` and constructs
8      a full package set out of that.
9    */
10   makePackageSet = import ../make-package-set.nix;
12   /* The function overrideCabal lets you alter the arguments to the
13      mkDerivation function.
15      Example:
17      First, note how the aeson package is constructed in hackage-packages.nix:
19          "aeson" = callPackage ({ mkDerivation, attoparsec, <snip>
20                                 }:
21                                   mkDerivation {
22                                     pname = "aeson";
23                                     <snip>
24                                     homepage = "https://github.com/bos/aeson";
25                                   })
27      The mkDerivation function of haskellPackages will take care of putting
28      the homepage in the right place, in meta.
30          > haskellPackages.aeson.meta.homepage
31          "https://github.com/bos/aeson"
33          > x = haskell.lib.compose.overrideCabal (old: { homepage = old.homepage + "#readme"; }) haskellPackages.aeson
34          > x.meta.homepage
35          "https://github.com/bos/aeson#readme"
37    */
38   overrideCabal = f: drv: (drv.override (args: args // {
39     mkDerivation = drv: (args.mkDerivation drv).override f;
40   })) // {
41     overrideScope = scope: overrideCabal f (drv.overrideScope scope);
42   };
44   # : Map Name (Either Path VersionNumber) -> HaskellPackageOverrideSet
45   # Given a set whose values are either paths or version strings, produces
46   # a package override set (i.e. (self: super: { etc. })) that sets
47   # the packages named in the input set to the corresponding versions
48   packageSourceOverrides =
49     overrides: self: super: pkgs.lib.mapAttrs (name: src:
50       let isPath = x: builtins.substring 0 1 (toString x) == "/";
51           generateExprs = if isPath src
52                              then self.callCabal2nix
53                              else self.callHackage;
54       in generateExprs name src {}) overrides;
56   /* doCoverage modifies a haskell package to enable the generation
57      and installation of a coverage report.
59      See https://wiki.haskell.org/Haskell_program_coverage
60    */
61   doCoverage = overrideCabal (drv: { doCoverage = true; });
63   /* dontCoverage modifies a haskell package to disable the generation
64      and installation of a coverage report.
65    */
66   dontCoverage = overrideCabal (drv: { doCoverage = false; });
68   /* doHaddock modifies a haskell package to enable the generation and
69      installation of API documentation from code comments using the
70      haddock tool.
71    */
72   doHaddock = overrideCabal (drv: { doHaddock = true; });
74   /* dontHaddock modifies a haskell package to disable the generation and
75      installation of API documentation from code comments using the
76      haddock tool.
77    */
78   dontHaddock = overrideCabal (drv: { doHaddock = false; });
80   /* doJailbreak enables the removal of version bounds from the cabal
81      file. You may want to avoid this function.
83      This is useful when a package reports that it can not be built
84      due to version mismatches. In some cases, removing the version
85      bounds entirely is an easy way to make a package build, but at
86      the risk of breaking software in non-obvious ways now or in the
87      future.
89      Instead of jailbreaking, you can patch the cabal file.
91      Note that jailbreaking at this time, doesn't lift bounds on
92      conditional branches.
93      https://github.com/peti/jailbreak-cabal/issues/7 has further details.
95    */
96   doJailbreak = overrideCabal (drv: { jailbreak = true; });
98   /* dontJailbreak restores the use of the version bounds the check
99      the use of dependencies in the package description.
100    */
101   dontJailbreak = overrideCabal (drv: { jailbreak = false; });
103   /* doCheck enables dependency checking, compilation and execution
104      of test suites listed in the package description file.
105    */
106   doCheck = overrideCabal (drv: { doCheck = true; });
107   /* dontCheck disables dependency checking, compilation and execution
108      of test suites listed in the package description file.
109    */
110   dontCheck = overrideCabal (drv: { doCheck = false; });
111   /* The dontCheckIf variant sets doCheck = false if the condition
112      applies. In any other case the previously set/default value is used.
113      This prevents accidentally re-enabling tests in a later override.
114      */
115   dontCheckIf = condition: if condition then dontCheck else lib.id;
117   /* doBenchmark enables dependency checking and compilation
118      for benchmarks listed in the package description file.
119      Benchmarks are, however, not executed at the moment.
120    */
121   doBenchmark = overrideCabal (drv: { doBenchmark = true; });
122   /* dontBenchmark disables dependency checking, compilation and execution
123      for benchmarks listed in the package description file.
124    */
125   dontBenchmark = overrideCabal (drv: { doBenchmark = false; });
127   /* doDistribute enables the distribution of binaries for the package
128      via hydra.
129    */
130   doDistribute = overrideCabal (drv: {
131     # lib.platforms.all is the default value for platforms (since GHC can cross-compile)
132     hydraPlatforms = lib.subtractLists (drv.badPlatforms or [])
133       (drv.platforms or lib.platforms.all);
134   });
135   /* dontDistribute disables the distribution of binaries for the package
136      via hydra.
137    */
138   dontDistribute = overrideCabal (drv: { hydraPlatforms = []; });
140   /* appendConfigureFlag adds a single argument that will be passed to the
141      cabal configure command, after the arguments that have been defined
142      in the initial declaration or previous overrides.
144      Example:
146          > haskell.lib.compose.appendConfigureFlag "--profiling-detail=all-functions" haskellPackages.servant
147    */
148   appendConfigureFlag = x: appendConfigureFlags [x];
149   appendConfigureFlags = xs: overrideCabal (drv: { configureFlags = (drv.configureFlags or []) ++ xs; });
151   appendBuildFlag = x: overrideCabal (drv: { buildFlags = (drv.buildFlags or []) ++ [x]; });
152   appendBuildFlags = xs: overrideCabal (drv: { buildFlags = (drv.buildFlags or []) ++ xs; });
154   /* removeConfigureFlag drv x is a Haskell package like drv, but with
155      all cabal configure arguments that are equal to x removed.
157          > haskell.lib.compose.removeConfigureFlag "--verbose" haskellPackages.servant
158    */
159   removeConfigureFlag = x: overrideCabal (drv: { configureFlags = lib.remove x (drv.configureFlags or []); });
161   addBuildTool = x: addBuildTools [x];
162   addBuildTools = xs: overrideCabal (drv: { buildTools = (drv.buildTools or []) ++ xs; });
164   addExtraLibrary = x: addExtraLibraries [x];
165   addExtraLibraries = xs: overrideCabal (drv: { extraLibraries = (drv.extraLibraries or []) ++ xs; });
167   addBuildDepend = x: addBuildDepends [x];
168   addBuildDepends = xs: overrideCabal (drv: { buildDepends = (drv.buildDepends or []) ++ xs; });
170   addTestToolDepend = x: addTestToolDepends [x];
171   addTestToolDepends = xs: overrideCabal (drv: { testToolDepends = (drv.testToolDepends or []) ++ xs; });
173   addPkgconfigDepend = x: addPkgconfigDepends [x];
174   addPkgconfigDepends = xs: overrideCabal (drv: { pkg-configDepends = (drv.pkg-configDepends or []) ++ xs; });
176   addSetupDepend = x: addSetupDepends [x];
177   addSetupDepends = xs: overrideCabal (drv: { setupHaskellDepends = (drv.setupHaskellDepends or []) ++ xs; });
179   enableCabalFlag = x: drv: appendConfigureFlag "-f${x}" (removeConfigureFlag "-f-${x}" drv);
180   disableCabalFlag = x: drv: appendConfigureFlag "-f-${x}" (removeConfigureFlag "-f${x}" drv);
182   markBroken = overrideCabal (drv: { broken = true; hydraPlatforms = []; });
183   unmarkBroken = overrideCabal (drv: { broken = false; });
184   markBrokenVersion = version: drv: assert drv.version == version; markBroken drv;
185   markUnbroken = overrideCabal (drv: { broken = false; });
187   /* disableParallelBuilding drops the -j<n> option from the GHC
188      command line for the given package. This can be useful in rare
189      situations where parallel building of a package causes GHC to
190      fail for some reason.
191    */
192   disableParallelBuilding = overrideCabal (drv: { enableParallelBuilding = false; });
194   enableLibraryProfiling = overrideCabal (drv: { enableLibraryProfiling = true; });
195   disableLibraryProfiling = overrideCabal (drv: { enableLibraryProfiling = false; });
197   enableExecutableProfiling = overrideCabal (drv: { enableExecutableProfiling = true; });
198   disableExecutableProfiling = overrideCabal (drv: { enableExecutableProfiling = false; });
200   enableSharedExecutables = overrideCabal (drv: { enableSharedExecutables = true; });
201   disableSharedExecutables = overrideCabal (drv: { enableSharedExecutables = false; });
203   enableSharedLibraries = overrideCabal (drv: { enableSharedLibraries = true; });
204   disableSharedLibraries = overrideCabal (drv: { enableSharedLibraries = false; });
206   enableDeadCodeElimination = overrideCabal (drv: { enableDeadCodeElimination = true; });
207   disableDeadCodeElimination = overrideCabal (drv: { enableDeadCodeElimination = false; });
209   enableStaticLibraries = overrideCabal (drv: { enableStaticLibraries = true; });
210   disableStaticLibraries = overrideCabal (drv: { enableStaticLibraries = false; });
212   enableSeparateBinOutput = overrideCabal (drv: { enableSeparateBinOutput = true; });
214   appendPatch = x: appendPatches [x];
215   appendPatches = xs: overrideCabal (drv: { patches = (drv.patches or []) ++ xs; });
217   /* Set a specific build target instead of compiling all targets in the package.
218    * For example, imagine we have a .cabal file with a library, and 2 executables "dev" and "server".
219    * We can build only "server" and not wait on the compilation of "dev" by using setBuildTarget as follows:
220    *
221    *   > setBuildTarget "server" (callCabal2nix "thePackageName" thePackageSrc {})
222    *
223    */
224   setBuildTargets = xs: overrideCabal (drv: { buildTarget = lib.concatStringsSep " " xs; });
225   setBuildTarget = x: setBuildTargets [x];
227   doHyperlinkSource = overrideCabal (drv: { hyperlinkSource = true; });
228   dontHyperlinkSource = overrideCabal (drv: { hyperlinkSource = false; });
230   disableHardening = flags: overrideCabal (drv: { hardeningDisable = flags; });
232   /* Let Nix strip the binary files.
233    * This removes debugging symbols.
234    */
235   doStrip = overrideCabal (drv: { dontStrip = false; });
237   /* Stop Nix from stripping the binary files.
238    * This keeps debugging symbols.
239    */
240   dontStrip = overrideCabal (drv: { dontStrip = true; });
242   /* Useful for debugging segfaults with gdb.
243    * This includes dontStrip.
244    */
245   enableDWARFDebugging = drv:
246    # -g: enables debugging symbols
247    # --disable-*-stripping: tell GHC not to strip resulting binaries
248    # dontStrip: see above
249    appendConfigureFlag "--ghc-options=-g --disable-executable-stripping --disable-library-stripping" (dontStrip drv);
251   /* Create a source distribution tarball like those found on hackage,
252      instead of building the package.
253    */
254   sdistTarball = pkg: lib.overrideDerivation pkg (drv: {
255     name = "${drv.pname}-source-${drv.version}";
256     # Since we disable the haddock phase, we also need to override the
257     # outputs since the separate doc output will not be produced.
258     outputs = ["out"];
259     buildPhase = "./Setup sdist";
260     haddockPhase = ":";
261     checkPhase = ":";
262     installPhase = "install -D dist/${drv.pname}-*.tar.gz $out/${drv.pname}-${drv.version}.tar.gz";
263     fixupPhase = ":";
264   });
266   /* Create a documentation tarball suitable for uploading to Hackage instead
267      of building the package.
268    */
269   documentationTarball = pkg:
270     pkgs.lib.overrideDerivation pkg (drv: {
271       name = "${drv.name}-docs";
272       # Like sdistTarball, disable the "doc" output here.
273       outputs = [ "out" ];
274       buildPhase = ''
275         runHook preHaddock
276         ./Setup haddock --for-hackage
277         runHook postHaddock
278       '';
279       haddockPhase = ":";
280       checkPhase = ":";
281       installPhase = ''
282         runHook preInstall
283         mkdir -p "$out"
284         tar --format=ustar \
285           -czf "$out/${drv.name}-docs.tar.gz" \
286           -C dist/doc/html "${drv.name}-docs"
287         runHook postInstall
288       '';
289     });
291   /* Use the gold linker. It is a linker for ELF that is designed
292      "to run as fast as possible on modern systems"
293    */
294   linkWithGold = appendConfigureFlag
295     "--ghc-option=-optl-fuse-ld=gold --ld-option=-fuse-ld=gold --with-ld=ld.gold";
297   /* link executables statically against haskell libs to reduce
298      closure size
299    */
300  justStaticExecutables = overrideCabal (drv: {
301     enableSharedExecutables = false;
302     enableLibraryProfiling = drv.enableExecutableProfiling or false;
303     isLibrary = false;
304     doHaddock = false;
305     postFixup = drv.postFixup or "" + ''
307       # Remove every directory which could have links to other store paths.
308       rm -rf $out/lib $out/nix-support $out/share/doc
309     '';
310     disallowGhcReference = true;
311   });
313   /* Build a source distribution tarball instead of using the source files
314      directly. The effect is that the package is built as if it were published
315      on hackage. This can be used as a test for the source distribution,
316      assuming the build fails when packaging mistakes are in the cabal file.
318      A faster implementation using `cabal-install` is available as
319      `buildFromCabalSdist` in your Haskell package set.
320    */
321   buildFromSdist = pkg: overrideCabal (drv: {
322     src = "${sdistTarball pkg}/${pkg.pname}-${pkg.version}.tar.gz";
324     # Revising and jailbreaking the cabal file has been handled in sdistTarball
325     revision = null;
326     editedCabalFile = null;
327     jailbreak = false;
328   }) pkg;
330   /* Build the package in a strict way to uncover potential problems.
331      This includes buildFromSdist and failOnAllWarnings.
332    */
333   buildStrictly = pkg: buildFromSdist (failOnAllWarnings pkg);
335   /* Disable core optimizations, significantly speeds up build time */
336   disableOptimization = appendConfigureFlag "--disable-optimization";
338   /* Turn on most of the compiler warnings and fail the build if any
339      of them occur. */
340   failOnAllWarnings = appendConfigureFlag "--ghc-option=-Wall --ghc-option=-Werror";
342   /* Add a post-build check to verify that dependencies declared in
343      the cabal file are actually used.
345      The first attrset argument can be used to configure the strictness
346      of this check and a list of ignored package names that would otherwise
347      cause false alarms.
348    */
349   checkUnusedPackages =
350     { ignoreEmptyImports ? false
351     , ignoreMainModule   ? false
352     , ignorePackages     ? []
353     } : drv :
354       overrideCabal (_drv: {
355         postBuild =
356           let args = lib.concatStringsSep " " (
357                        lib.optional ignoreEmptyImports "--ignore-empty-imports" ++
358                        lib.optional ignoreMainModule   "--ignore-main-module" ++
359                        map (pkg: "--ignore-package ${pkg}") ignorePackages
360                      );
361           in "${pkgs.haskellPackages.packunused}/bin/packunused" +
362              lib.optionalString (args != "") " ${args}";
363       }) (appendConfigureFlag "--ghc-option=-ddump-minimal-imports" drv);
365   buildStackProject = pkgs.callPackage ../generic-stack-builder.nix { };
367   /* Add a dummy command to trigger a build despite an equivalent
368      earlier build that is present in the store or cache.
369    */
370   triggerRebuild = i: overrideCabal (drv: {
371     postUnpack = drv.postUnpack or "" + ''
373       # trigger rebuild ${toString i}
374     '';
375   });
377   /* Override the sources for the package and optionally the version.
378      This also takes of removing editedCabalFile.
379    */
380   overrideSrc = { src, version ? null }: drv:
381     overrideCabal (_: { inherit src; version = if version == null then drv.version else version; editedCabalFile = null; }) drv;
383   # Get all of the build inputs of a haskell package, divided by category.
384   getBuildInputs = p: p.getBuildInputs;
386   # Extract the haskell build inputs of a haskell package.
387   # This is useful to build environments for developing on that
388   # package.
389   getHaskellBuildInputs = p: (getBuildInputs p).haskellBuildInputs;
391   # Under normal evaluation, simply return the original package. Under
392   # nix-shell evaluation, return a nix-shell optimized environment.
393   shellAware = p: if lib.inNixShell then p.env else p;
395   ghcInfo = ghc:
396     rec { isCross = (ghc.cross or null) != null;
397           isGhcjs = ghc.isGhcjs or false;
398           nativeGhc = if isCross || isGhcjs
399                         then ghc.bootPkgs.ghc
400                         else ghc;
401         };
403   ### mkDerivation helpers
404   # These allow external users of a haskell package to extract
405   # information about how it is built in the same way that the
406   # generic haskell builder does, by reusing the same functions.
407   # Each function here has the same interface as mkDerivation and thus
408   # can be called for a given package simply by overriding the
409   # mkDerivation argument it used. See getHaskellBuildInputs above for
410   # an example of this.
412   # Some information about which phases should be run.
413   controlPhases = ghc: let inherit (ghcInfo ghc) isCross; in
414                   { doCheck ? !isCross
415                   , doBenchmark ? false
416                   , ...
417                   }: { inherit doCheck doBenchmark; };
419   # Utility to convert a directory full of `cabal2nix`-generated files into a
420   # package override set
421   #
422   # packagesFromDirectory : { directory : Directory, ... } -> HaskellPackageOverrideSet
423   packagesFromDirectory =
424     { directory, ... }:
426     self: super:
427       let
428         haskellPaths =
429           lib.filter (lib.hasSuffix ".nix")
430             (builtins.attrNames (builtins.readDir directory));
432         toKeyVal = file: {
433           name  = builtins.replaceStrings [ ".nix" ] [ "" ] file;
435           value = self.callPackage (directory + "/${file}") { };
436         };
438       in
439         builtins.listToAttrs (map toKeyVal haskellPaths);
441   /*
442     INTERNAL function retained for backwards compatibility, use
443     haskell.packages.*.generateOptparseApplicativeCompletions instead!
444   */
445   __generateOptparseApplicativeCompletion = exeName: overrideCabal (drv: {
446     postInstall = (drv.postInstall or "") + ''
447       bashCompDir="''${!outputBin}/share/bash-completion/completions"
448       zshCompDir="''${!outputBin}/share/zsh/vendor-completions"
449       fishCompDir="''${!outputBin}/share/fish/vendor_completions.d"
450       mkdir -p "$bashCompDir" "$zshCompDir" "$fishCompDir"
451       "''${!outputBin}/bin/${exeName}" --bash-completion-script "''${!outputBin}/bin/${exeName}" >"$bashCompDir/${exeName}"
452       "''${!outputBin}/bin/${exeName}" --zsh-completion-script "''${!outputBin}/bin/${exeName}" >"$zshCompDir/_${exeName}"
453       "''${!outputBin}/bin/${exeName}" --fish-completion-script "''${!outputBin}/bin/${exeName}" >"$fishCompDir/${exeName}.fish"
455       # Sanity check
456       grep -F ${exeName} <$bashCompDir/${exeName} >/dev/null || {
457         echo 'Could not find ${exeName} in completion script.'
458         exit 1
459       }
460     '';
461   });
463   /*
464     Retained for backwards compatibility.
465     Use haskell.packages.*.generateOptparseApplicativeCompletions
466     which is cross aware instead.
467   */
468   generateOptparseApplicativeCompletions = commands: pkg:
469     lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2211) "haskellLib.generateOptparseApplicativeCompletions is deprecated in favor of haskellPackages.generateOptparseApplicativeCompletions. Please change ${pkg.name} to use the latter and make sure it uses its matching haskell.packages set!"
470       (pkgs.lib.foldr __generateOptparseApplicativeCompletion pkg commands);
472   /*
473     Retained for backwards compatibility.
474     Use haskell.packages.*.generateOptparseApplicativeCompletions
475     which is cross aware instead.
476   */
477   generateOptparseApplicativeCompletion = command: pkg:
478     lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2211) "haskellLib.generateOptparseApplicativeCompletion is deprecated in favor of haskellPackages.generateOptparseApplicativeCompletions (plural!). Please change ${pkg.name} to use the latter and make sure it uses its matching haskell.packages set!"
479       (__generateOptparseApplicativeCompletion command pkg);
481   # Don't fail at configure time if there are multiple versions of the
482   # same package in the (recursive) dependencies of the package being
483   # built. Will delay failures, if any, to compile time.
484   allowInconsistentDependencies = overrideCabal (drv: {
485     allowInconsistentDependencies = true;
486   });
488   # Work around a Cabal bug requiring pkg-config --static --libs to work even
489   # when linking dynamically, affecting Cabal 3.8 and 3.9.
490   # https://github.com/haskell/cabal/issues/8455
491   #
492   # For this, we treat the runtime system/pkg-config dependencies of a Haskell
493   # derivation as if they were propagated from their dependencies which allows
494   # pkg-config --static to work in most cases.
495   #
496   # Warning: This function may change or be removed at any time, e.g. if we find
497   # a different workaround, upstream fixes the bug or we patch Cabal.
498   __CabalEagerPkgConfigWorkaround =
499     let
500       # Take list of derivations and return list of the transitive dependency
501       # closure, only taking into account buildInputs. Loosely based on
502       # closePropagationFast.
503       propagatedPlainBuildInputs = drvs:
504         builtins.map (i: i.val) (
505           builtins.genericClosure {
506             startSet = builtins.map (drv:
507               { key = drv.outPath; val = drv; }
508             ) drvs;
509             operator = { val, ... }:
510               if !lib.isDerivation val
511               then [ ]
512               else
513                 builtins.concatMap (drv:
514                   if !lib.isDerivation drv
515                   then [ ]
516                   else [ { key = drv.outPath; val = drv; } ]
517                 ) (val.buildInputs or [ ] ++ val.propagatedBuildInputs or [ ]);
518           }
519         );
520     in
521     overrideCabal (old: {
522       benchmarkPkgconfigDepends = propagatedPlainBuildInputs old.benchmarkPkgconfigDepends or [ ];
523       executablePkgconfigDepends = propagatedPlainBuildInputs old.executablePkgconfigDepends or [ ];
524       libraryPkgconfigDepends = propagatedPlainBuildInputs old.libraryPkgconfigDepends or [ ];
525       testPkgconfigDepends = propagatedPlainBuildInputs old.testPkgconfigDepends or [ ];
526     });