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