-
-
Notifications
You must be signed in to change notification settings - Fork 19.3k
stdenv.mkDerivation: overlay style overridable recursive attributes #119942
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a4e7085
2afc03a
40ab3b8
2f21bc2
6d7efb3
41b3688
d629ba2
1bbb5a1
37ab5b4
2e0bd52
ca83dd1
f066ddd
0e00aca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -317,6 +317,60 @@ The script will be usually run from the root of the Nixpkgs repository but you s | |
|
|
||
| For information about how to run the updates, execute `nix-shell maintainers/scripts/update.nix`. | ||
|
|
||
| ### Recursive attributes in `mkDerivation` | ||
|
|
||
| If you pass a function to `mkDerivation`, it will receive as its argument the final arguments, including the overrides when reinvoked via `overrideAttrs`. For example: | ||
|
|
||
| ```nix | ||
| mkDerivation (finalAttrs: { | ||
| pname = "hello"; | ||
| withFeature = true; | ||
| configureFlags = | ||
| lib.optionals finalAttrs.withFeature ["--with-feature"]; | ||
| }) | ||
|
Comment on lines
325
to
330
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we please demonstrate how to use this with mkDerivation (final: {
pname = "hello";
version = "2.3";
src = fetchFromGitHub {
owner = "foo";
repo = final.pname;
ref = "v${final.version}";
sha256 = "hash goes here";
};
})and then subsequently override it like hello.overrideAttrs (super: {
version = "2.4";
src = super.src.overrideAttrs (_: {
sha256 = "updated hash";
});
})(and in the future hopefully we can slap
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
See relevant #158018
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's scope this out and follow it up in #158018. |
||
| ``` | ||
|
|
||
| Note that this does not use the `rec` keyword to reuse `withFeature` in `configureFlags`. | ||
| The `rec` keyword works at the syntax level and is unaware of overriding. | ||
|
|
||
| Instead, the definition references `finalAttrs`, allowing users to change `withFeature` | ||
| consistently with `overrideAttrs`. | ||
|
|
||
| `finalAttrs` also contains the attribute `finalPackage`, which includes the output paths, etc. | ||
|
|
||
| Let's look at a more elaborate example to understand the differences between | ||
| various bindings: | ||
|
|
||
| ```nix | ||
| # `pkg` is the _original_ definition (for illustration purposes) | ||
| let pkg = | ||
| mkDerivation (finalAttrs: { | ||
| # ... | ||
|
|
||
| # An example attribute | ||
| packages = []; | ||
|
|
||
| # `passthru.tests` is a commonly defined attribute. | ||
| passthru.tests.simple = f finalAttrs.finalPackage; | ||
|
|
||
| # An example of an attribute containing a function | ||
| passthru.appendPackages = packages': | ||
| finalAttrs.finalPackage.overrideAttrs (newSelf: super: { | ||
| packages = super.packages ++ packages'; | ||
| }); | ||
|
|
||
| # For illustration purposes; referenced as | ||
| # `(pkg.overrideAttrs(x)).finalAttrs` etc in the text below. | ||
| passthru.finalAttrs = finalAttrs; | ||
| passthru.original = pkg; | ||
| }); | ||
| in pkg | ||
| ``` | ||
|
|
||
| Unlike the `pkg` binding in the above example, the `finalAttrs` parameter always references the final attributes. For instance `(pkg.overrideAttrs(x)).finalAttrs.finalPackage` is identical to `pkg.overrideAttrs(x)`, whereas `(pkg.overrideAttrs(x)).original` is the same as the original `pkg`. | ||
|
|
||
| See also the section about [`passthru.tests`](#var-meta-tests). | ||
|
|
||
| ## Phases {#sec-stdenv-phases} | ||
|
|
||
| `stdenv.mkDerivation` sets the Nix [derivation](https://nixos.org/manual/nix/stable/expressions/derivations.html#derivations)'s builder to a script that loads the stdenv `setup.sh` bash library and calls `genericBuild`. Most packaging functions rely on this default builder. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| { runCommand, hello }: | ||
|
|
||
| runCommand "hello-test-run" { | ||
| nativeBuildInputs = [ hello ]; | ||
| } '' | ||
| diff -U3 --color=auto <(hello) <(echo 'Hello, world!') | ||
| touch $out | ||
| '' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,8 +9,72 @@ let | |
| # to build it. This is a bit confusing for cross compilation. | ||
| inherit (stdenv) hostPlatform; | ||
| }; | ||
|
|
||
| makeOverlayable = mkDerivationSimple: | ||
| fnOrAttrs: | ||
| if builtins.isFunction fnOrAttrs | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've considered it, but
|
||
| then makeDerivationExtensible mkDerivationSimple fnOrAttrs | ||
| else makeDerivationExtensibleConst mkDerivationSimple fnOrAttrs; | ||
|
|
||
| # Based off lib.makeExtensible, with modifications: | ||
| makeDerivationExtensible = mkDerivationSimple: rattrs: | ||
|
roberth marked this conversation as resolved.
Outdated
|
||
| let | ||
| # NOTE: The following is a hint that will be printed by the Nix cli when | ||
| # encountering an infinite recursion. It must not be formatted into | ||
| # separate lines, because Nix would only show the last line of the comment. | ||
|
|
||
| # An infinite recursion here can be caused by having the attribute names of expression `e` in `.overrideAttrs(finalAttrs: previousAttrs: e)` depend on `finalAttrs`. Only the attribute values of `e` can depend on `finalAttrs`. | ||
| args = rattrs (args // { inherit finalPackage; }); | ||
| # ^^^^ | ||
|
|
||
| finalPackage = | ||
| mkDerivationSimple | ||
| (f0: | ||
| let | ||
| f = self: super: | ||
| # Convert f0 to an overlay. Legacy is: | ||
| # overrideAttrs (super: {}) | ||
| # We want to introduce self. We follow the convention of overlays: | ||
| # overrideAttrs (self: super: {}) | ||
| # Which means the first parameter can be either self or super. | ||
| # This is surprising, but far better than the confusion that would | ||
| # arise from flipping an overlay's parameters in some cases. | ||
| let x = f0 super; | ||
| in | ||
| if builtins.isFunction x | ||
|
Artturin marked this conversation as resolved.
Outdated
|
||
| then | ||
| # Can't reuse `x`, because `self` comes first. | ||
| # Looks inefficient, but `f0 super` was a cheap thunk. | ||
| f0 self super | ||
| else x; | ||
| in | ||
| makeDerivationExtensible mkDerivationSimple | ||
| (self: let super = rattrs self; in super // f self super)) | ||
| args; | ||
| in finalPackage; | ||
|
|
||
| # makeDerivationExtensibleConst == makeDerivationExtensible (_: attrs), | ||
| # but pre-evaluated for a slight improvement in performance. | ||
| makeDerivationExtensibleConst = mkDerivationSimple: attrs: | ||
| mkDerivationSimple | ||
| (f0: | ||
| let | ||
| f = self: super: | ||
| let x = f0 super; | ||
| in | ||
| if builtins.isFunction x | ||
|
Artturin marked this conversation as resolved.
Outdated
|
||
| then | ||
| f0 self super | ||
| else x; | ||
| in | ||
| makeDerivationExtensible mkDerivationSimple (self: attrs // f self attrs)) | ||
| attrs; | ||
|
|
||
| in | ||
|
|
||
| makeOverlayable (overrideAttrs: | ||
|
|
||
|
|
||
| # `mkDerivation` wraps the builtin `derivation` function to | ||
| # produce derivations that use this stdenv and its shell. | ||
| # | ||
|
|
@@ -70,6 +134,7 @@ in | |
|
|
||
| , # TODO(@Ericson2314): Make always true and remove | ||
| strictDeps ? if config.strictDepsByDefault then true else stdenv.hostPlatform != stdenv.buildPlatform | ||
|
|
||
|
roberth marked this conversation as resolved.
Outdated
|
||
| , meta ? {} | ||
| , passthru ? {} | ||
| , pos ? # position used in error messages and for meta.position | ||
|
|
@@ -381,8 +446,6 @@ in | |
| lib.extendDerivation | ||
| validity.handled | ||
| ({ | ||
| overrideAttrs = f: stdenv.mkDerivation (attrs // (f attrs)); | ||
|
|
||
| # A derivation that always builds successfully and whose runtime | ||
| # dependencies are the original derivations build time dependencies | ||
| # This allows easy building and distributing of all derivations | ||
|
|
@@ -408,10 +471,12 @@ lib.extendDerivation | |
| args = [ "-c" "export > $out" ]; | ||
| }); | ||
|
|
||
| inherit meta passthru; | ||
| inherit meta passthru overrideAttrs; | ||
| } // | ||
| # Pass through extra attributes that are not inputs, but | ||
| # should be made available to Nix expressions using the | ||
| # derivation (e.g., in assertions). | ||
| passthru) | ||
| (derivation derivationArg) | ||
|
|
||
| ) | ||
Uh oh!
There was an error while loading. Please reload this page.