1{ lib }:
2
3let
4 inherit (builtins)
5 intersectAttrs
6 ;
7 inherit (lib)
8 functionArgs
9 isFunction
10 mirrorFunctionArgs
11 isAttrs
12 setFunctionArgs
13 optionalAttrs
14 attrNames
15 filter
16 elemAt
17 concatStringsSep
18 sortOn
19 take
20 length
21 filterAttrs
22 optionalString
23 flip
24 pathIsDirectory
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 (newArgs: makeOverridable f (overrideWith newArgs));
170 # Change the result of the function call by applying g to it
171 overrideResult = g: makeOverridable (mirrorArgs (args: g (f args))) origArgs;
172 in
173 if isAttrs result then
174 result
175 // {
176 override = overrideArgs;
177 overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv);
178 ${if result ? overrideAttrs then "overrideAttrs" else null} =
179 fdrv: overrideResult (x: x.overrideAttrs fdrv);
180 }
181 else if isFunction result then
182 # Transform the result into a functor while propagating its arguments
183 setFunctionArgs result (functionArgs result)
184 // {
185 override = overrideArgs;
186 }
187 else
188 result
189 );
190
191 /**
192 Call the package function in the file `fn` with the required
193 arguments automatically. The function is called with the
194 arguments `args`, but any missing arguments are obtained from
195 `autoArgs`. This function is intended to be partially
196 parameterised, e.g.,
197
198 ```nix
199 callPackage = callPackageWith pkgs;
200 pkgs = {
201 libfoo = callPackage ./foo.nix { };
202 libbar = callPackage ./bar.nix { };
203 };
204 ```
205
206 If the `libbar` function expects an argument named `libfoo`, it is
207 automatically passed as an argument. Overrides or missing
208 arguments can be supplied in `args`, e.g.
209
210 ```nix
211 libbar = callPackage ./bar.nix {
212 libfoo = null;
213 enableX11 = true;
214 };
215 ```
216
217 <!-- TODO: Apply "Example:" tag to the examples above -->
218
219 # Inputs
220
221 `autoArgs`
222
223 : 1\. Function argument
224
225 `fn`
226
227 : 2\. Function argument
228
229 `args`
230
231 : 3\. Function argument
232
233 # Type
234
235 ```
236 callPackageWith :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
237 ```
238 */
239 callPackageWith =
240 autoArgs: fn: args:
241 let
242 f = if isFunction fn then fn else import fn;
243 fargs = functionArgs f;
244
245 # All arguments that will be passed to the function
246 # This includes automatic ones and ones passed explicitly
247 allArgs = intersectAttrs fargs autoArgs // args;
248
249 # a list of argument names that the function requires, but
250 # wouldn't be passed to it
251 missingArgs =
252 # Filter out arguments that have a default value
253 (
254 filterAttrs (name: value: !value)
255 # Filter out arguments that would be passed
256 (removeAttrs fargs (attrNames allArgs))
257 );
258
259 # Get a list of suggested argument names for a given missing one
260 getSuggestions =
261 arg:
262 pipe (autoArgs // args) [
263 attrNames
264 # Only use ones that are at most 2 edits away. While mork would work,
265 # levenshteinAtMost is only fast for 2 or less.
266 (filter (levenshteinAtMost 2 arg))
267 # Put strings with shorter distance first
268 (sortOn (levenshtein arg))
269 # Only take the first couple results
270 (take 3)
271 # Quote all entries
272 (map (x: "\"" + x + "\""))
273 ];
274
275 prettySuggestions =
276 suggestions:
277 if suggestions == [ ] then
278 ""
279 else if length suggestions == 1 then
280 ", did you mean ${elemAt suggestions 0}?"
281 else
282 ", did you mean ${concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?";
283
284 errorForArg =
285 arg:
286 let
287 loc = builtins.unsafeGetAttrPos arg fargs;
288 # loc' can be removed once lib/minver.nix is >2.3.4, since that includes
289 # https://github.com/NixOS/nix/pull/3468 which makes loc be non-null
290 loc' =
291 if loc != null then
292 loc.file + ":" + toString loc.line
293 else if !isFunction fn then
294 toString (lib.filesystem.resolveDefaultNix fn)
295 else
296 "<unknown location>";
297 in
298 "Function called without required argument \"${arg}\" at "
299 + "${loc'}${prettySuggestions (getSuggestions arg)}";
300
301 # Only show the error for the first missing argument
302 error = errorForArg (head (attrNames missingArgs));
303
304 in
305 if missingArgs == { } then
306 makeOverridable f allArgs
307 # This needs to be an abort so it can't be caught with `builtins.tryEval`,
308 # which is used by nix-env and ofborg to filter out packages that don't evaluate.
309 # This way we're forced to fix such errors in Nixpkgs,
310 # which is especially relevant with allowAliases = false
311 else
312 abort "lib.customisation.callPackageWith: ${error}";
313
314 /**
315 Like callPackage, but for a function that returns an attribute
316 set of derivations. The override function is added to the
317 individual attributes.
318
319 # Inputs
320
321 `autoArgs`
322
323 : 1\. Function argument
324
325 `fn`
326
327 : 2\. Function argument
328
329 `args`
330
331 : 3\. Function argument
332
333 # Type
334
335 ```
336 callPackagesWith :: AttrSet -> ((AttrSet -> AttrSet) | Path) -> AttrSet -> AttrSet
337 ```
338 */
339 callPackagesWith =
340 autoArgs: fn: args:
341 let
342 f = if isFunction fn then fn else import fn;
343 auto = intersectAttrs (functionArgs f) autoArgs;
344 mirrorArgs = mirrorFunctionArgs f;
345 origArgs = auto // args;
346 pkgs = f origArgs;
347 mkAttrOverridable = name: _: makeOverridable (mirrorArgs (newArgs: (f newArgs).${name})) origArgs;
348 in
349 if isDerivation pkgs then
350 throw (
351 "function `callPackages` was called on a *single* derivation "
352 + ''"${pkgs.name or "<unknown-name>"}";''
353 + " did you mean to use `callPackage` instead?"
354 )
355 else
356 mapAttrs mkAttrOverridable pkgs;
357
358 /**
359 Add attributes to each output of a derivation without changing
360 the derivation itself and check a given condition when evaluating.
361
362 # Inputs
363
364 `condition`
365
366 : 1\. Function argument
367
368 `passthru`
369
370 : 2\. Function argument
371
372 `drv`
373
374 : 3\. Function argument
375
376 # Type
377
378 ```
379 extendDerivation :: Bool -> Any -> Derivation -> Derivation
380 ```
381 */
382 extendDerivation =
383 condition: passthru: drv:
384 let
385 outputs = drv.outputs or [ "out" ];
386
387 commonAttrs =
388 drv // (listToAttrs outputsList) // ({ all = map (x: x.value) outputsList; }) // passthru;
389
390 outputToAttrListElement = outputName: {
391 name = outputName;
392 value =
393 commonAttrs
394 // {
395 inherit (drv.${outputName}) type outputName;
396 outputSpecified = true;
397 drvPath =
398 assert condition;
399 drv.${outputName}.drvPath;
400 outPath =
401 assert condition;
402 drv.${outputName}.outPath;
403 }
404 //
405 # TODO: give the derivation control over the outputs.
406 # `overrideAttrs` may not be the only attribute that needs
407 # updating when switching outputs.
408 optionalAttrs (passthru ? overrideAttrs) {
409 # TODO: also add overrideAttrs when overrideAttrs is not custom, e.g. when not splicing.
410 overrideAttrs = f: (passthru.overrideAttrs f).${outputName};
411 };
412 };
413
414 outputsList = map outputToAttrListElement outputs;
415 in
416 commonAttrs
417 // {
418 drvPath =
419 assert condition;
420 drv.drvPath;
421 outPath =
422 assert condition;
423 drv.outPath;
424 };
425
426 /**
427 Strip a derivation of all non-essential attributes, returning
428 only those needed by hydra-eval-jobs. Also strictly evaluate the
429 result to ensure that there are no thunks kept alive to prevent
430 garbage collection.
431
432 # Inputs
433
434 `drv`
435
436 : 1\. Function argument
437
438 # Type
439
440 ```
441 hydraJob :: (Derivation | Null) -> (Derivation | Null)
442 ```
443 */
444 hydraJob =
445 drv:
446 let
447 outputs = drv.outputs or [ "out" ];
448
449 commonAttrs = {
450 inherit (drv) name system meta;
451 inherit outputs;
452 }
453 // optionalAttrs (drv._hydraAggregate or false) {
454 _hydraAggregate = true;
455 constituents = map hydraJob (flatten drv.constituents);
456 }
457 // (listToAttrs outputsList);
458
459 makeOutput =
460 outputName:
461 let
462 output = drv.${outputName};
463 in
464 {
465 name = outputName;
466 value = commonAttrs // {
467 outPath = output.outPath;
468 drvPath = output.drvPath;
469 type = "derivation";
470 inherit outputName;
471 };
472 };
473
474 outputsList = map makeOutput outputs;
475
476 drv' = (head outputsList).value;
477 in
478 if drv == null then null else deepSeq drv' drv';
479
480 /**
481 Make an attribute set (a "scope") from functions that take arguments from that same attribute set.
482 See [](#ex-makeScope) for how to use it.
483
484 # Inputs
485
486 1. `newScope` (`AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a`)
487
488 A function that takes an attribute set `attrs` and returns what ends up as `callPackage` in the output.
489
490 Typical values are `callPackageWith` or the output attribute `newScope`.
491
492 2. `f` (`AttrSet -> AttrSet`)
493
494 A function that takes an attribute set as returned by `makeScope newScope f` (a "scope") and returns any attribute set.
495
496 This function is used to compute the fixpoint of the resulting scope using `callPackage`.
497 Its argument is the lazily evaluated reference to the value of that fixpoint, and is typically called `self` or `final`.
498
499 See [](#ex-makeScope) for how to use it.
500 See [](#sec-functions-library-fixedPoints) for details on fixpoint computation.
501
502 # Output
503
504 `makeScope` returns an attribute set of a form called `scope`, which also contains the final attributes produced by `f`:
505
506 ```
507 scope :: {
508 callPackage :: ((AttrSet -> a) | Path) -> AttrSet -> a
509 newScope = AttrSet -> scope
510 overrideScope = (scope -> scope -> AttrSet) -> scope
511 packages :: AttrSet -> AttrSet
512 }
513 ```
514
515 - `callPackage` (`((AttrSet -> a) | Path) -> AttrSet -> a`)
516
517 A function that
518
519 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`,
520 2. Takes an attribute set `args` with explicit attributes to pass to `p`,
521 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`.
522
523 All such functions `p` will be called with the same value for `attrs`.
524
525 See [](#ex-makeScope-callPackage) for how to use it.
526
527 - `newScope` (`AttrSet -> scope`)
528
529 Takes an attribute set `attrs` and returns a scope that extends the original scope.
530
531 - `overrideScope` (`(scope -> scope -> AttrSet) -> scope`)
532
533 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`.
534 See [](https://nixos.org/manual/nixpkgs/unstable/#function-library-lib.fixedPoints.extends) for details.
535
536 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.
537
538 - `packages` (`AttrSet -> AttrSet`)
539
540 The value of the argument `f` to `makeScope`.
541
542 - final attributes
543
544 The final values returned by `f`.
545
546 # Examples
547
548 :::{#ex-makeScope .example}
549 # Create an interdependent package set on top of `pkgs`
550
551 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.
552
553 ```nix
554 let
555 pkgs = import <nixpkgs> { };
556 in
557 pkgs.lib.makeScope pkgs.newScope (self: {
558 foo = self.callPackage ./foo.nix { };
559 bar = self.callPackage ./bar.nix { };
560 })
561 ```
562
563 evaluates to
564
565 ```nix
566 {
567 callPackage = «lambda»;
568 newScope = «lambda»;
569 overrideScope = «lambda»;
570 packages = «lambda»;
571 foo = «derivation»;
572 bar = «derivation»;
573 }
574 ```
575 :::
576
577 :::{#ex-makeScope-callPackage .example}
578 # Using `callPackage` from a scope
579
580 ```nix
581 let
582 pkgs = import <nixpkgs> { };
583 inherit (pkgs) lib;
584 scope = lib.makeScope lib.callPackageWith (self: { a = 1; b = 2; });
585 three = scope.callPackage ({ a, b }: a + b) { };
586 four = scope.callPackage ({ a, b }: a + b) { a = 2; };
587 in
588 [ three four ]
589 ```
590
591 evaluates to
592
593 ```nix
594 [ 3 4 ]
595 ```
596 :::
597
598 # Type
599
600 ```
601 makeScope :: (AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a) -> (AttrSet -> AttrSet) -> scope
602 ```
603 */
604 makeScope =
605 newScope: f:
606 let
607 self = f self // {
608 newScope = scope: newScope (self // scope);
609 callPackage = self.newScope { };
610 overrideScope = g: makeScope newScope (extends g f);
611 packages = f;
612 };
613 in
614 self;
615
616 /**
617 backward compatibility with old uncurried form; deprecated
618
619 # Inputs
620
621 `splicePackages`
622
623 : 1\. Function argument
624
625 `newScope`
626
627 : 2\. Function argument
628
629 `otherSplices`
630
631 : 3\. Function argument
632
633 `keep`
634
635 : 4\. Function argument
636
637 `extra`
638
639 : 5\. Function argument
640
641 `f`
642
643 : 6\. Function argument
644 */
645 makeScopeWithSplicing =
646 splicePackages: newScope: otherSplices: keep: extra: f:
647 makeScopeWithSplicing' { inherit splicePackages newScope; } {
648 inherit
649 otherSplices
650 keep
651 extra
652 f
653 ;
654 };
655
656 /**
657 Like makeScope, but aims to support cross compilation. It's still ugly, but
658 hopefully it helps a little bit.
659
660 # Type
661
662 ```
663 makeScopeWithSplicing' ::
664 { splicePackages :: Splice -> AttrSet
665 , newScope :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
666 }
667 -> { otherSplices :: Splice, keep :: AttrSet -> AttrSet, extra :: AttrSet -> AttrSet }
668 -> AttrSet
669
670 Splice ::
671 { pkgsBuildBuild :: AttrSet
672 , pkgsBuildHost :: AttrSet
673 , pkgsBuildTarget :: AttrSet
674 , pkgsHostHost :: AttrSet
675 , pkgsHostTarget :: AttrSet
676 , pkgsTargetTarget :: AttrSet
677 }
678 ```
679 */
680 makeScopeWithSplicing' =
681 {
682 splicePackages,
683 newScope,
684 }:
685 {
686 otherSplices,
687 # Attrs from `self` which won't be spliced.
688 # Avoid using keep, it's only used for a python hook workaround, added in PR #104201.
689 # ex: `keep = (self: { inherit (self) aAttr; })`
690 keep ? (_self: { }),
691 # Additional attrs to add to the sets `callPackage`.
692 # When the package is from a subset (but not a subset within a package IS #211340)
693 # within `spliced0` it will be spliced.
694 # When using an package outside the set but it's available from `pkgs`, use the package from `pkgs.__splicedPackages`.
695 # 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
696 # ex:
697 # ```
698 # nix-repl> darwin.apple_sdk.frameworks.CoreFoundation
699 # «derivation ...CoreFoundation-11.0.0.drv»
700 # nix-repl> darwin.CoreFoundation
701 # error: attribute 'CoreFoundation' missing
702 # nix-repl> darwin.callPackage ({ CoreFoundation }: CoreFoundation) { }
703 # «derivation ...CoreFoundation-11.0.0.drv»
704 # ```
705 extra ? (_spliced0: { }),
706 f,
707 }:
708 let
709 spliced0 = splicePackages {
710 pkgsBuildBuild = otherSplices.selfBuildBuild;
711 pkgsBuildHost = otherSplices.selfBuildHost;
712 pkgsBuildTarget = otherSplices.selfBuildTarget;
713 pkgsHostHost = otherSplices.selfHostHost;
714 pkgsHostTarget = self; # Not `otherSplices.selfHostTarget`;
715 pkgsTargetTarget = otherSplices.selfTargetTarget;
716 };
717 spliced = extra spliced0 // spliced0 // keep self;
718 self = f self // {
719 newScope = scope: newScope (spliced // scope);
720 callPackage = newScope spliced; # == self.newScope {};
721 # N.B. the other stages of the package set spliced in are *not*
722 # overridden.
723 overrideScope =
724 g:
725 (makeScopeWithSplicing' { inherit splicePackages newScope; } {
726 inherit otherSplices keep extra;
727 f = extends g f;
728 });
729 packages = f;
730 };
731 in
732 self;
733
734 /**
735 Define a `mkDerivation`-like function based on another `mkDerivation`-like function.
736
737 [`stdenv.mkDerivation`](#part-stdenv) gives access to
738 its final set of derivation attributes when it is passed a function,
739 or when it is passed an overlay-style function in `overrideAttrs`.
740
741 Instead of composing new `stdenv.mkDerivation`-like build helpers
742 using normal function composition,
743 `extendMkDerivation` makes sure that the returned build helper
744 supports such first class recursion like `mkDerivation` does.
745
746 `extendMkDerivation` takes an extra attribute set to configure its behaviour.
747 One can optionally specify
748 `transformDrv` to specify a function to apply to the result derivation,
749 or `inheritFunctionArgs` to decide whether to inherit the `__functionArgs`
750 from the base build helper.
751
752 # Inputs
753
754 `extendMkDerivation`-specific configurations
755 : `constructDrv`: Base build helper, the `mkDerivation`-like build helper to extend.
756 : `excludeDrvArgNames`: Argument names not to pass from the input fixed-point arguments to `constructDrv`. Note: It doesn't apply to the updating arguments returned by `extendDrvArgs`.
757 : `extendDrvArgs` : An extension (overlay) of the argument set, like the one taken by [overrideAttrs](#sec-pkg-overrideAttrs) but applied before passing to `constructDrv`.
758 : `inheritFunctionArgs`: Whether to inherit `__functionArgs` from the base build helper (default to `true`).
759 : `transformDrv`: Function to apply to the result derivation (default to `lib.id`).
760
761 # Type
762
763 ```
764 extendMkDerivation ::
765 {
766 constructDrv :: ((FixedPointArgs | AttrSet) -> a)
767 excludeDrvArgNames :: [ String ],
768 extendDrvArgs :: (AttrSet -> AttrSet -> AttrSet)
769 inheritFunctionArgs :: Bool,
770 transformDrv :: a -> a,
771 }
772 -> (FixedPointArgs | AttrSet) -> a
773
774 FixedPointArgs = AttrSet -> AttrSet
775 a = Derivation when defining a build helper
776 ```
777
778 # Examples
779
780 :::{.example}
781 ## `lib.customisation.extendMkDerivation` usage example
782 ```nix-repl
783 mkLocalDerivation = lib.extendMkDerivation {
784 constructDrv = pkgs.stdenv.mkDerivation;
785 excludeDrvArgNames = [ "specialArg" ];
786 extendDrvArgs =
787 finalAttrs: args@{ preferLocalBuild ? true, allowSubstitute ? false, specialArg ? (_: false), ... }:
788 { inherit preferLocalBuild allowSubstitute; passthru = { inherit specialArg; } // args.passthru or { }; };
789 }
790
791 mkLocalDerivation.__functionArgs
792 => { allowSubstitute = true; preferLocalBuild = true; specialArg = true; }
793
794 mkLocalDerivation { inherit (pkgs.hello) pname version src; specialArg = _: false; }
795 => «derivation /nix/store/xirl67m60ahg6jmzicx43a81g635g8z8-hello-2.12.1.drv»
796
797 mkLocalDerivation (finalAttrs: { inherit (pkgs.hello) pname version src; specialArg = _: false; })
798 => «derivation /nix/store/xirl67m60ahg6jmzicx43a81g635g8z8-hello-2.12.1.drv»
799
800 (mkLocalDerivation (finalAttrs: { inherit (pkgs.hello) pname version src; passthru = { foo = "a"; bar = "${finalAttrs.passthru.foo}b"; }; })).bar
801 => "ab"
802 ```
803 :::
804
805 :::{.note}
806 If `transformDrv` is specified,
807 it should take care of existing attributes that perform overriding
808 (e.g., [`overrideAttrs`](#sec-pkg-overrideAttrs))
809 to ensure that the overriding functionality of the result derivation
810 work as expected.
811 Modifications that breaks the overriding include
812 direct [attribute set update](https://nixos.org/manual/nix/stable/language/operators#update)
813 and [`lib.extendDerivation`](#function-library-lib.customisation.extendDerivation).
814 :::
815 */
816 extendMkDerivation =
817 let
818 extendsWithExclusion =
819 excludedNames: g: f: final:
820 let
821 previous = f final;
822 in
823 removeAttrs previous excludedNames // g final previous;
824 in
825 {
826 constructDrv,
827 excludeDrvArgNames ? [ ],
828 extendDrvArgs,
829 inheritFunctionArgs ? true,
830 transformDrv ? id,
831 }:
832 setFunctionArgs
833 # Adds the fixed-point style support
834 (
835 fpargs:
836 transformDrv (
837 constructDrv (extendsWithExclusion excludeDrvArgNames extendDrvArgs (toFunction fpargs))
838 )
839 )
840 # Add __functionArgs
841 (
842 # Inherit the __functionArgs from the base build helper
843 optionalAttrs inheritFunctionArgs (removeAttrs (functionArgs constructDrv) excludeDrvArgNames)
844 # Recover the __functionArgs from the derived build helper
845 // functionArgs (extendDrvArgs { })
846 )
847 // {
848 inherit
849 # Expose to the result build helper.
850 constructDrv
851 excludeDrvArgNames
852 extendDrvArgs
853 transformDrv
854 ;
855 };
856}