nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{ lib }:
2
3let
4 inherit (builtins)
5 intersectAttrs
6 unsafeGetAttrPos
7 ;
8 inherit (lib)
9 functionArgs
10 isFunction
11 mirrorFunctionArgs
12 isAttrs
13 setFunctionArgs
14 optionalAttrs
15 attrNames
16 filter
17 elemAt
18 concatStringsSep
19 sortOn
20 take
21 length
22 filterAttrs
23 optionalString
24 flip
25 head
26 pipe
27 isDerivation
28 listToAttrs
29 mapAttrs
30 seq
31 flatten
32 deepSeq
33 extends
34 toFunction
35 id
36 ;
37 inherit (lib.strings) levenshtein levenshteinAtMost;
38
39in
40rec {
41
42 /**
43 `overrideDerivation drv f` takes a derivation (i.e., the result
44 of a call to the builtin function `derivation`) and returns a new
45 derivation in which the attributes of the original are overridden
46 according to the function `f`. The function `f` is called with
47 the original derivation attributes.
48
49 `overrideDerivation` allows certain "ad-hoc" customisation
50 scenarios (e.g. in ~/.config/nixpkgs/config.nix). For instance,
51 if you want to "patch" the derivation returned by a package
52 function in Nixpkgs to build another version than what the
53 function itself provides.
54
55 For another application, see build-support/vm, where this
56 function is used to build arbitrary derivations inside a QEMU
57 virtual machine.
58
59 Note that in order to preserve evaluation errors, the new derivation's
60 outPath depends on the old one's, which means that this function cannot
61 be used in circular situations when the old derivation also depends on the
62 new one.
63
64 You should in general prefer `drv.overrideAttrs` over this function;
65 see the nixpkgs manual for more information on overriding.
66
67 # Inputs
68
69 `drv`
70
71 : 1\. Function argument
72
73 `f`
74
75 : 2\. Function argument
76
77 # Type
78
79 ```
80 overrideDerivation :: Derivation -> ( Derivation -> AttrSet ) -> Derivation
81 ```
82
83 # Examples
84 :::{.example}
85 ## `lib.customisation.overrideDerivation` usage example
86
87 ```nix
88 mySed = overrideDerivation pkgs.gnused (oldAttrs: {
89 name = "sed-4.2.2-pre";
90 src = fetchurl {
91 url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2;
92 hash = "sha256-MxBJRcM2rYzQYwJ5XKxhXTQByvSg5jZc5cSHEZoB2IY=";
93 };
94 patches = [];
95 });
96 ```
97
98 :::
99 */
100 overrideDerivation =
101 drv: f:
102 let
103 newDrv = derivation (drv.drvAttrs // (f drv));
104 in
105 flip (extendDerivation (seq drv.drvPath true)) newDrv (
106 {
107 meta = drv.meta or { };
108 passthru = if drv ? passthru then drv.passthru else { };
109 }
110 // (drv.passthru or { })
111 // optionalAttrs (drv ? __spliced) {
112 __spliced = { } // (mapAttrs (_: sDrv: overrideDerivation sDrv f) drv.__spliced);
113 }
114 );
115
116 /**
117 `makeOverridable` takes a function from attribute set to attribute set and
118 injects `override` attribute which can be used to override arguments of
119 the function.
120
121 Please refer to documentation on [`<pkg>.overrideDerivation`](#sec-pkg-overrideDerivation) to learn about `overrideDerivation` and caveats
122 related to its use.
123
124 # Inputs
125
126 `f`
127
128 : 1\. Function argument
129
130 # Type
131
132 ```
133 makeOverridable :: (AttrSet -> a) -> AttrSet -> a
134 ```
135
136 # Examples
137 :::{.example}
138 ## `lib.customisation.makeOverridable` usage example
139
140 ```nix
141 nix-repl> x = {a, b}: { result = a + b; }
142
143 nix-repl> y = lib.makeOverridable x { a = 1; b = 2; }
144
145 nix-repl> y
146 { override = «lambda»; overrideDerivation = «lambda»; result = 3; }
147
148 nix-repl> y.override { a = 10; }
149 { override = «lambda»; overrideDerivation = «lambda»; result = 12; }
150 ```
151
152 :::
153 */
154 makeOverridable =
155 f:
156 let
157 # Creates a functor with the same arguments as f
158 mirrorArgs = mirrorFunctionArgs f;
159 in
160 mirrorArgs (
161 origArgs:
162 let
163 result = f origArgs;
164
165 # Changes the original arguments with (potentially a function that returns) a set of new attributes
166 overrideWith = newArgs: origArgs // (if isFunction newArgs then newArgs origArgs else newArgs);
167
168 # Re-call the function but with different arguments
169 overrideArgs = mirrorArgs (
170 /**
171 Change the arguments with which a certain function is called.
172
173 In some cases, you may find a list of possible attributes to pass in this function's `__functionArgs` attribute, but it will not be complete for an original function like `args@{foo, ...}: ...`, which accepts arbitrary attributes.
174
175 This function was provided by `lib.makeOverridable`.
176 */
177 newArgs: makeOverridable f (overrideWith newArgs)
178 );
179 # Change the result of the function call by applying g to it
180 overrideResult = g: makeOverridable (mirrorArgs (args: g (f args))) origArgs;
181 in
182 if isAttrs result then
183 result
184 // {
185 override = overrideArgs;
186 overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv);
187 ${if result ? overrideAttrs then "overrideAttrs" else null} =
188 /**
189 Override the attributes that were passed to `mkDerivation` in order to generate this derivation.
190
191 This function is provided by `lib.makeOverridable`, and indirectly by `callPackage` among others, in order to make the combination of `override` and `overrideAttrs` work.
192 Specifically, it re-adds the `override` attribute to the result of `overrideAttrs`.
193
194 The real implementation of `overrideAttrs` is provided by `stdenv.mkDerivation`.
195 */
196 # NOTE: part of the above documentation had to be duplicated in `mkDerivation`'s `overrideAttrs`.
197 # design/tech debt issue: https://github.com/NixOS/nixpkgs/issues/273815
198 fdrv: overrideResult (x: x.overrideAttrs fdrv);
199 }
200 else if isFunction result then
201 # Transform the result into a functor while propagating its arguments
202 setFunctionArgs result (functionArgs result)
203 // {
204 override = overrideArgs;
205 }
206 else
207 result
208 );
209
210 /**
211 Call the package function in the file `fn` with the required
212 arguments automatically. The function is called with the
213 arguments `args`, but any missing arguments are obtained from
214 `autoArgs`. This function is intended to be partially
215 parameterised, e.g.,
216
217 ```nix
218 callPackage = callPackageWith pkgs;
219 pkgs = {
220 libfoo = callPackage ./foo.nix { };
221 libbar = callPackage ./bar.nix { };
222 };
223 ```
224
225 If the `libbar` function expects an argument named `libfoo`, it is
226 automatically passed as an argument. Overrides or missing
227 arguments can be supplied in `args`, e.g.
228
229 ```nix
230 libbar = callPackage ./bar.nix {
231 libfoo = null;
232 enableX11 = true;
233 };
234 ```
235
236 <!-- TODO: Apply "Example:" tag to the examples above -->
237
238 # Inputs
239
240 `autoArgs`
241
242 : 1\. Function argument
243
244 `fn`
245
246 : 2\. Function argument
247
248 `args`
249
250 : 3\. Function argument
251
252 # Type
253
254 ```
255 callPackageWith :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
256 ```
257 */
258 callPackageWith =
259 autoArgs: fn: args:
260 let
261 f = if isFunction fn then fn else import fn;
262 fargs = functionArgs f;
263
264 # All arguments that will be passed to the function
265 # This includes automatic ones and ones passed explicitly
266 allArgs = intersectAttrs fargs autoArgs // args;
267
268 # a list of argument names that the function requires, but
269 # wouldn't be passed to it
270 missingArgs =
271 # Filter out arguments that have a default value
272 (
273 filterAttrs (name: value: !value)
274 # Filter out arguments that would be passed
275 (removeAttrs fargs (attrNames allArgs))
276 );
277
278 # Get a list of suggested argument names for a given missing one
279 getSuggestions =
280 arg:
281 pipe (autoArgs // args) [
282 attrNames
283 # Only use ones that are at most 2 edits away. While mork would work,
284 # levenshteinAtMost is only fast for 2 or less.
285 (filter (levenshteinAtMost 2 arg))
286 # Put strings with shorter distance first
287 (sortOn (levenshtein arg))
288 # Only take the first couple results
289 (take 3)
290 # Quote all entries
291 (map (x: "\"" + x + "\""))
292 ];
293
294 prettySuggestions =
295 suggestions:
296 if suggestions == [ ] then
297 ""
298 else if length suggestions == 1 then
299 ", did you mean ${elemAt suggestions 0}?"
300 else
301 ", did you mean ${concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?";
302
303 errorForArg =
304 arg:
305 let
306 loc = unsafeGetAttrPos arg fargs;
307 loc' = if loc != null then loc.file + ":" + toString loc.line else "<unknown location>";
308 in
309 "Function called without required argument \"${arg}\" at "
310 + "${loc'}${prettySuggestions (getSuggestions arg)}";
311
312 # Only show the error for the first missing argument
313 error = errorForArg (head (attrNames missingArgs));
314
315 in
316 if missingArgs == { } then
317 makeOverridable f allArgs
318 # This needs to be an abort so it can't be caught with `builtins.tryEval`,
319 # which is used by nix-env and ofborg to filter out packages that don't evaluate.
320 # This way we're forced to fix such errors in Nixpkgs,
321 # which is especially relevant with allowAliases = false
322 else
323 abort "lib.customisation.callPackageWith: ${error}";
324
325 /**
326 Like callPackage, but for a function that returns an attribute
327 set of derivations. The override function is added to the
328 individual attributes.
329
330 # Inputs
331
332 `autoArgs`
333
334 : 1\. Function argument
335
336 `fn`
337
338 : 2\. Function argument
339
340 `args`
341
342 : 3\. Function argument
343
344 # Type
345
346 ```
347 callPackagesWith :: AttrSet -> ((AttrSet -> AttrSet) | Path) -> AttrSet -> AttrSet
348 ```
349 */
350 callPackagesWith =
351 autoArgs: fn: args:
352 let
353 f = if isFunction fn then fn else import fn;
354 auto = intersectAttrs (functionArgs f) autoArgs;
355 mirrorArgs = mirrorFunctionArgs f;
356 origArgs = auto // args;
357 pkgs = f origArgs;
358 mkAttrOverridable = name: _: makeOverridable (mirrorArgs (newArgs: (f newArgs).${name})) origArgs;
359 in
360 if isDerivation pkgs then
361 throw (
362 "function `callPackages` was called on a *single* derivation "
363 + ''"${pkgs.name or "<unknown-name>"}";''
364 + " did you mean to use `callPackage` instead?"
365 )
366 else
367 mapAttrs mkAttrOverridable pkgs;
368
369 /**
370 Add attributes to each output of a derivation without changing
371 the derivation itself and check a given condition when evaluating.
372
373 # Inputs
374
375 `condition`
376
377 : 1\. Function argument
378
379 `passthru`
380
381 : 2\. Function argument
382
383 `drv`
384
385 : 3\. Function argument
386
387 # Type
388
389 ```
390 extendDerivation :: Bool -> Any -> Derivation -> Derivation
391 ```
392 */
393 extendDerivation =
394 condition: passthru: drv:
395 let
396 outputs = drv.outputs or [ "out" ];
397
398 commonAttrs =
399 drv // (listToAttrs outputsList) // { all = map (x: x.value) outputsList; } // passthru;
400
401 outputToAttrListElement = outputName: {
402 name = outputName;
403 value =
404 commonAttrs
405 // {
406 inherit (drv.${outputName}) type outputName;
407 outputSpecified = true;
408 drvPath =
409 assert condition;
410 drv.${outputName}.drvPath;
411 outPath =
412 assert condition;
413 drv.${outputName}.outPath;
414 }
415 //
416 # TODO: give the derivation control over the outputs.
417 # `overrideAttrs` may not be the only attribute that needs
418 # updating when switching outputs.
419 optionalAttrs (passthru ? overrideAttrs) {
420 # TODO: also add overrideAttrs when overrideAttrs is not custom, e.g. when not splicing.
421 overrideAttrs = f: (passthru.overrideAttrs f).${outputName};
422 };
423 };
424
425 outputsList = map outputToAttrListElement outputs;
426 in
427 commonAttrs
428 // {
429 drvPath =
430 assert condition;
431 drv.drvPath;
432 outPath =
433 assert condition;
434 drv.outPath;
435 };
436
437 /**
438 Strip a derivation of all non-essential attributes, returning
439 only those needed by hydra-eval-jobs. Also strictly evaluate the
440 result to ensure that there are no thunks kept alive to prevent
441 garbage collection.
442
443 # Inputs
444
445 `drv`
446
447 : 1\. Function argument
448
449 # Type
450
451 ```
452 hydraJob :: (Derivation | Null) -> (Derivation | Null)
453 ```
454 */
455 hydraJob =
456 drv:
457 let
458 outputs = drv.outputs or [ "out" ];
459
460 commonAttrs = {
461 inherit (drv) name system meta;
462 inherit outputs;
463 }
464 // optionalAttrs (drv._hydraAggregate or false) {
465 _hydraAggregate = true;
466 constituents = map hydraJob (flatten drv.constituents);
467 }
468 // (listToAttrs outputsList);
469
470 makeOutput =
471 outputName:
472 let
473 output = drv.${outputName};
474 in
475 {
476 name = outputName;
477 value = commonAttrs // {
478 outPath = output.outPath;
479 drvPath = output.drvPath;
480 type = "derivation";
481 inherit outputName;
482 };
483 };
484
485 outputsList = map makeOutput outputs;
486
487 drv' = (head outputsList).value;
488 in
489 if drv == null then null else deepSeq drv' drv';
490
491 /**
492 Make an attribute set (a "scope") from functions that take arguments from that same attribute set.
493 See [](#ex-makeScope) for how to use it.
494
495 # Inputs
496
497 1. `newScope` (`AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a`)
498
499 A function that takes an attribute set `attrs` and returns what ends up as `callPackage` in the output.
500
501 Typical values are `callPackageWith` or the output attribute `newScope`.
502
503 2. `f` (`AttrSet -> AttrSet`)
504
505 A function that takes an attribute set as returned by `makeScope newScope f` (a "scope") and returns any attribute set.
506
507 This function is used to compute the fixpoint of the resulting scope using `callPackage`.
508 Its argument is the lazily evaluated reference to the value of that fixpoint, and is typically called `self` or `final`.
509
510 See [](#ex-makeScope) for how to use it.
511 See [](#sec-functions-library-fixedPoints) for details on fixpoint computation.
512
513 # Output
514
515 `makeScope` returns an attribute set of a form called `scope`, which also contains the final attributes produced by `f`:
516
517 ```
518 scope :: {
519 callPackage :: ((AttrSet -> a) | Path) -> AttrSet -> a
520 newScope = AttrSet -> scope
521 overrideScope = (scope -> scope -> AttrSet) -> scope
522 packages :: AttrSet -> AttrSet
523 }
524 ```
525
526 - `callPackage` (`((AttrSet -> a) | Path) -> AttrSet -> a`)
527
528 A function that
529
530 1. Takes a function `p`, or a path to a Nix file that contains a function `p`, which takes an attribute set and returns value of arbitrary type `a`,
531 2. Takes an attribute set `args` with explicit attributes to pass to `p`,
532 3. Calls `f` with attributes from the original attribute set `attrs` passed to `newScope` updated with `args`, i.e. `attrs // args`, if they match the attributes in the argument of `p`.
533
534 All such functions `p` will be called with the same value for `attrs`.
535
536 See [](#ex-makeScope-callPackage) for how to use it.
537
538 - `newScope` (`AttrSet -> scope`)
539
540 Takes an attribute set `attrs` and returns a scope that extends the original scope.
541
542 - `overrideScope` (`(scope -> scope -> AttrSet) -> scope`)
543
544 Takes a function `g` of the form `final: prev: { # attributes }` to act as an overlay on `f`, and returns a new scope with values determined by `extends g f`.
545 See [](https://nixos.org/manual/nixpkgs/unstable/#function-library-lib.fixedPoints.extends) for details.
546
547 This allows subsequent modification of the final attribute set in a consistent way, i.e. all functions `p` invoked with `callPackage` will be called with the modified values.
548
549 - `packages` (`AttrSet -> AttrSet`)
550
551 The value of the argument `f` to `makeScope`.
552
553 - final attributes
554
555 The final values returned by `f`.
556
557 # Examples
558
559 :::{#ex-makeScope .example}
560 # Create an interdependent package set on top of `pkgs`
561
562 The functions in `foo.nix` and `bar.nix` can depend on each other, in the sense that `foo.nix` can contain a function that expects `bar` as an attribute in its argument.
563
564 ```nix
565 let
566 pkgs = import <nixpkgs> { };
567 in
568 pkgs.lib.makeScope pkgs.newScope (self: {
569 foo = self.callPackage ./foo.nix { };
570 bar = self.callPackage ./bar.nix { };
571 })
572 ```
573
574 evaluates to
575
576 ```nix
577 {
578 callPackage = «lambda»;
579 newScope = «lambda»;
580 overrideScope = «lambda»;
581 packages = «lambda»;
582 foo = «derivation»;
583 bar = «derivation»;
584 }
585 ```
586 :::
587
588 :::{#ex-makeScope-callPackage .example}
589 # Using `callPackage` from a scope
590
591 ```nix
592 let
593 pkgs = import <nixpkgs> { };
594 inherit (pkgs) lib;
595 scope = lib.makeScope lib.callPackageWith (self: { a = 1; b = 2; });
596 three = scope.callPackage ({ a, b }: a + b) { };
597 four = scope.callPackage ({ a, b }: a + b) { a = 2; };
598 in
599 [ three four ]
600 ```
601
602 evaluates to
603
604 ```nix
605 [ 3 4 ]
606 ```
607 :::
608
609 # Type
610
611 ```
612 makeScope :: (AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a) -> (AttrSet -> AttrSet) -> scope
613 ```
614 */
615 makeScope =
616 newScope: f:
617 let
618 self = f self // {
619 newScope = scope: newScope (self // scope);
620 callPackage = self.newScope { };
621 overrideScope = g: makeScope newScope (extends g f);
622 packages = f;
623 };
624 in
625 self;
626
627 /**
628 backward compatibility with old uncurried form; deprecated
629
630 # Inputs
631
632 `splicePackages`
633
634 : 1\. Function argument
635
636 `newScope`
637
638 : 2\. Function argument
639
640 `otherSplices`
641
642 : 3\. Function argument
643
644 `keep`
645
646 : 4\. Function argument
647
648 `extra`
649
650 : 5\. Function argument
651
652 `f`
653
654 : 6\. Function argument
655 */
656 makeScopeWithSplicing =
657 splicePackages: newScope: otherSplices: keep: extra: f:
658 makeScopeWithSplicing' { inherit splicePackages newScope; } {
659 inherit
660 otherSplices
661 keep
662 extra
663 f
664 ;
665 };
666
667 /**
668 Like makeScope, but aims to support cross compilation. It's still ugly, but
669 hopefully it helps a little bit.
670
671 # Type
672
673 ```
674 makeScopeWithSplicing' ::
675 { splicePackages :: Splice -> AttrSet
676 , newScope :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
677 }
678 -> { otherSplices :: Splice, keep :: AttrSet -> AttrSet, extra :: AttrSet -> AttrSet }
679 -> AttrSet
680
681 Splice ::
682 { pkgsBuildBuild :: AttrSet
683 , pkgsBuildHost :: AttrSet
684 , pkgsBuildTarget :: AttrSet
685 , pkgsHostHost :: AttrSet
686 , pkgsHostTarget :: AttrSet
687 , pkgsTargetTarget :: AttrSet
688 }
689 ```
690 */
691 makeScopeWithSplicing' =
692 {
693 splicePackages,
694 newScope,
695 }:
696 {
697 otherSplices,
698 # Attrs from `self` which won't be spliced.
699 # Avoid using keep, it's only used for a python hook workaround, added in PR #104201.
700 # ex: `keep = (self: { inherit (self) aAttr; })`
701 keep ? (_self: { }),
702 # Additional attrs to add to the sets `callPackage`.
703 # When the package is from a subset (but not a subset within a package IS #211340)
704 # within `spliced0` it will be spliced.
705 # When using an package outside the set but it's available from `pkgs`, use the package from `pkgs.__splicedPackages`.
706 # If the package is not available within the set or in `pkgs`, such as a package in a let binding, it will not be spliced
707 # ex:
708 # ```
709 # nix-repl> darwin.apple_sdk.frameworks.CoreFoundation
710 # «derivation ...CoreFoundation-11.0.0.drv»
711 # nix-repl> darwin.CoreFoundation
712 # error: attribute 'CoreFoundation' missing
713 # nix-repl> darwin.callPackage ({ CoreFoundation }: CoreFoundation) { }
714 # «derivation ...CoreFoundation-11.0.0.drv»
715 # ```
716 extra ? (_spliced0: { }),
717 f,
718 }:
719 let
720 spliced0 = splicePackages {
721 pkgsBuildBuild = otherSplices.selfBuildBuild;
722 pkgsBuildHost = otherSplices.selfBuildHost;
723 pkgsBuildTarget = otherSplices.selfBuildTarget;
724 pkgsHostHost = otherSplices.selfHostHost;
725 pkgsHostTarget = self; # Not `otherSplices.selfHostTarget`;
726 pkgsTargetTarget = otherSplices.selfTargetTarget;
727 };
728 spliced = extra spliced0 // spliced0 // keep self;
729 self = f self // {
730 newScope = scope: newScope (spliced // scope);
731 callPackage = newScope spliced; # == self.newScope {};
732 # N.B. the other stages of the package set spliced in are *not*
733 # overridden.
734 overrideScope =
735 g:
736 (makeScopeWithSplicing' { inherit splicePackages newScope; } {
737 inherit otherSplices keep extra;
738 f = extends g f;
739 });
740 packages = f;
741 };
742 in
743 self;
744
745 /**
746 Define a `mkDerivation`-like function based on another `mkDerivation`-like function.
747
748 [`stdenv.mkDerivation`](#part-stdenv) gives access to
749 its final set of derivation attributes when it is passed a function,
750 or when it is passed an overlay-style function in `overrideAttrs`.
751
752 Instead of composing new `stdenv.mkDerivation`-like build helpers
753 using normal function composition,
754 `extendMkDerivation` makes sure that the returned build helper
755 supports such first class recursion like `mkDerivation` does.
756
757 `extendMkDerivation` takes an extra attribute set to configure its behaviour.
758 One can optionally specify
759 `transformDrv` to specify a function to apply to the result derivation,
760 or `inheritFunctionArgs` to decide whether to inherit the `__functionArgs`
761 from the base build helper.
762
763 # Inputs
764
765 `extendMkDerivation`-specific configurations
766 : `constructDrv` (required)
767 : Base build helper, the `mkDerivation`-like build helper to extend.
768
769 `excludeDrvArgNames` (default to `[ ]`)
770 : Argument names not to pass from the input fixed-point arguments to `constructDrv`.
771 It doesn't apply to the updating arguments returned by `extendDrvArgs`.
772
773 `excludeFunctionArgNames` (default to `[ ]`)
774 : `__functionArgs` attribute names to remove from the result build helper.
775 `excludeFunctionArgNames` is useful for argument deprecation while avoiding ellipses.
776
777 `extendDrvArgs` (required)
778 : An extension (overlay) of the argument set, like the one taken by [overrideAttrs](#sec-pkg-overrideAttrs) but applied before passing to `constructDrv`.
779
780 `inheritFunctionArgs` (default to `true`)
781 : Whether to inherit `__functionArgs` from the base build helper.
782 Set `inheritFunctionArgs` to `false` when `extendDrvArgs`'s `args` set pattern does not contain an ellipsis.
783
784 `transformDrv` (default to `lib.id`)
785 : Function to apply to the result derivation.
786
787 # Type
788
789 ```
790 extendMkDerivation ::
791 {
792 constructDrv :: ((FixedPointArgs | AttrSet) -> a)
793 excludeDrvArgNames :: [ String ],
794 excludeFunctionArgNames :: [ String ]
795 extendDrvArgs :: (AttrSet -> AttrSet -> AttrSet)
796 inheritFunctionArgs :: Bool,
797 transformDrv :: a -> a,
798 }
799 -> (FixedPointArgs | AttrSet) -> a
800
801 FixedPointArgs = AttrSet -> AttrSet
802 a = Derivation when defining a build helper
803 ```
804
805 # Examples
806
807 :::{.example}
808 ## `lib.customisation.extendMkDerivation` usage example
809 ```nix-repl
810 mkLocalDerivation = lib.extendMkDerivation {
811 constructDrv = pkgs.stdenv.mkDerivation;
812 excludeDrvArgNames = [ "specialArg" ];
813 extendDrvArgs =
814 finalAttrs: args@{ preferLocalBuild ? true, allowSubstitute ? false, specialArg ? (_: false), ... }:
815 { inherit preferLocalBuild allowSubstitute; passthru = { inherit specialArg; } // args.passthru or { }; };
816 }
817
818 mkLocalDerivation.__functionArgs
819 => { allowSubstitute = true; preferLocalBuild = true; specialArg = true; }
820
821 mkLocalDerivation { inherit (pkgs.hello) pname version src; specialArg = _: false; }
822 => «derivation /nix/store/xirl67m60ahg6jmzicx43a81g635g8z8-hello-2.12.1.drv»
823
824 mkLocalDerivation (finalAttrs: { inherit (pkgs.hello) pname version src; specialArg = _: false; })
825 => «derivation /nix/store/xirl67m60ahg6jmzicx43a81g635g8z8-hello-2.12.1.drv»
826
827 (mkLocalDerivation (finalAttrs: { inherit (pkgs.hello) pname version src; passthru = { foo = "a"; bar = "${finalAttrs.passthru.foo}b"; }; })).bar
828 => "ab"
829 ```
830 :::
831
832 :::{.note}
833 If `transformDrv` is specified,
834 it should take care of existing attributes that perform overriding
835 (e.g., [`overrideAttrs`](#sec-pkg-overrideAttrs))
836 to ensure that the overriding functionality of the result derivation
837 work as expected.
838 Modifications that breaks the overriding include
839 direct [attribute set update](https://nixos.org/manual/nix/stable/language/operators#update)
840 and [`lib.extendDerivation`](#function-library-lib.customisation.extendDerivation).
841 :::
842 */
843 extendMkDerivation =
844 let
845 extendsWithExclusion =
846 excludedNames: g: f: final:
847 let
848 previous = f final;
849 in
850 removeAttrs previous excludedNames // g final previous;
851 in
852 {
853 constructDrv,
854 excludeDrvArgNames ? [ ],
855 excludeFunctionArgNames ? [ ],
856 extendDrvArgs,
857 inheritFunctionArgs ? true,
858 transformDrv ? id,
859 }:
860 setFunctionArgs
861 # Adds the fixed-point style support
862 (
863 fpargs:
864 transformDrv (
865 constructDrv (extendsWithExclusion excludeDrvArgNames extendDrvArgs (toFunction fpargs))
866 )
867 )
868 # Add __functionArgs
869 (
870 removeAttrs (
871 # Inherit the __functionArgs from the base build helper
872 optionalAttrs inheritFunctionArgs (removeAttrs (functionArgs constructDrv) excludeDrvArgNames)
873 # Recover the __functionArgs from the derived build helper
874 // functionArgs (extendDrvArgs { })
875 ) excludeFunctionArgNames
876 )
877 // {
878 inherit
879 # Expose to the result build helper.
880 constructDrv
881 excludeDrvArgNames
882 extendDrvArgs
883 transformDrv
884 ;
885 };
886
887 /**
888 Removes a prefix from the attribute names of a cross index.
889
890 A cross index (short for "Cross Platform Pair Index") is a 6-field structure
891 organizing values by cross-compilation platform relationships.
892
893 # Inputs
894
895 `prefix`
896 : The prefix to remove from cross index attribute names
897
898 `crossIndex`
899 : A cross index with prefixed names
900
901 # Type
902
903 ```
904 renameCrossIndexFrom :: String -> AttrSet -> AttrSet
905 ```
906
907 # Examples
908
909 :::{.example}
910 ## `lib.customisation.renameCrossIndexFrom` usage example
911
912 ```nix
913 renameCrossIndexFrom "pkgs" { pkgsBuildBuild = ...; pkgsBuildHost = ...; ... }
914 => { buildBuild = ...; buildHost = ...; ... }
915 ```
916 :::
917 */
918 renameCrossIndexFrom = prefix: x: {
919 buildBuild = x."${prefix}BuildBuild";
920 buildHost = x."${prefix}BuildHost";
921 buildTarget = x."${prefix}BuildTarget";
922 hostHost = x."${prefix}HostHost";
923 hostTarget = x."${prefix}HostTarget";
924 targetTarget = x."${prefix}TargetTarget";
925 };
926
927 /**
928 Adds a prefix to the attribute names of a cross index.
929
930 A cross index (short for "Cross Platform Pair Index") is a 6-field structure
931 organizing values by cross-compilation platform relationships.
932
933 # Inputs
934
935 `prefix`
936 : The prefix to add to cross index attribute names
937
938 `crossIndex`
939 : A cross index to be prefixed
940
941 # Type
942
943 ```
944 renameCrossIndexTo :: String -> AttrSet -> AttrSet
945 ```
946
947 # Examples
948
949 :::{.example}
950 ## `lib.customisation.renameCrossIndexTo` usage example
951
952 ```nix
953 renameCrossIndexTo "self" { buildBuild = ...; buildHost = ...; ... }
954 => { selfBuildBuild = ...; selfBuildHost = ...; ... }
955 ```
956 :::
957 */
958 renameCrossIndexTo = prefix: x: {
959 "${prefix}BuildBuild" = x.buildBuild;
960 "${prefix}BuildHost" = x.buildHost;
961 "${prefix}BuildTarget" = x.buildTarget;
962 "${prefix}HostHost" = x.hostHost;
963 "${prefix}HostTarget" = x.hostTarget;
964 "${prefix}TargetTarget" = x.targetTarget;
965 };
966
967 /**
968 Takes a function and applies it pointwise to each field of a cross index.
969
970 A cross index (short for "Cross Platform Pair Index") is a 6-field structure
971 organizing values by cross-compilation platform relationships.
972
973 # Inputs
974
975 `f`
976 : Function to apply to each cross index value
977
978 `crossIndex`
979 : A cross index to transform
980
981 # Type
982
983 ```
984 mapCrossIndex :: (a -> b) -> AttrSet -> AttrSet
985 ```
986
987 # Examples
988
989 :::{.example}
990 ## `lib.customisation.mapCrossIndex` usage example
991
992 ```nix
993 mapCrossIndex (x: x * 10) { buildBuild = 1; buildHost = 2; ... }
994 => { buildBuild = 10; buildHost = 20; ... }
995 ```
996
997 ```nix
998 # Extract a package from package sets
999 mapCrossIndex (pkgs: pkgs.hello) crossIndexedPackageSets
1000 ```
1001 :::
1002 */
1003 mapCrossIndex =
1004 f:
1005 {
1006 buildBuild,
1007 buildHost,
1008 buildTarget,
1009 hostHost,
1010 hostTarget,
1011 targetTarget,
1012 }:
1013 {
1014 buildBuild = f buildBuild;
1015 buildHost = f buildHost;
1016 buildTarget = f buildTarget;
1017 hostHost = f hostHost;
1018 hostTarget = f hostTarget;
1019 targetTarget = f targetTarget;
1020 };
1021}