nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at release-25.11 1021 lines 30 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 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}