diff options
-rw-r--r-- | doc/stdenv/meta.chapter.md | 2 | ||||
-rw-r--r-- | doc/stdenv/stdenv.chapter.md | 15 | ||||
-rw-r--r-- | pkgs/applications/misc/hello/default.nix | 2 | ||||
-rw-r--r-- | pkgs/stdenv/generic/make-derivation.nix | 78 |
4 files changed, 49 insertions, 48 deletions
diff --git a/doc/stdenv/meta.chapter.md b/doc/stdenv/meta.chapter.md index 64924dceb717f..e57669e261b31 100644 --- a/doc/stdenv/meta.chapter.md +++ b/doc/stdenv/meta.chapter.md @@ -187,7 +187,7 @@ all places. { stdenv, callPackage }: stdenv.mkDerivation (self: { # ... - passthru.tests.example = callPackage ./example.nix { my-package = self; }; + passthru.tests.example = callPackage ./example.nix { my-package = self.public; } }) ``` diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index 2994f7020b198..b54d68cb5ddd0 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -319,7 +319,7 @@ For information about how to run the updates, execute `nix-shell maintainers/scr ### Recursive attributes in `mkDerivation` -If you pass a function to `mkDerivation`, it will receive as its argument the final output of the same `mkDerivation` call. For example: +If you pass a function to `mkDerivation`, it will receive as its argument the final arguments, considering use of `overrideAttrs`. For example: ```nix mkDerivation (self: { @@ -331,9 +331,14 @@ mkDerivation (self: { ``` 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 `self`, allowing users to change `withFeature` consistently with `overrideAttrs`. +`self` also contains the attribute `public`, which represents the final package, +including the output paths, etc. + Let's look at a more elaborate example to understand the differences between various bindings: @@ -347,11 +352,11 @@ let pkg = packages = []; # `passthru.tests` is a commonly defined attribute. - passthru.tests.simple = f self; + passthru.tests.simple = f self.public; # An example of an attribute containing a function passthru.appendPackages = packages': - self.overrideAttrs (newSelf: super: { + self.public.overrideAttrs (newSelf: super: { packages = super.packages ++ packages'; }); @@ -363,9 +368,7 @@ let pkg = in pkg ``` -Unlike the `pkg` binding in the above example, the `self` parameter always references the final package. For instance `(pkg.overrideAttrs(x)).self` is identical to `pkg.overrideAttrs(x)`, whereas `(pkg.overrideAttrs(x)).original` is the same as `pkg`. - -This is also different from `mkDerivation rec { ..... }`, which binds the recursive references immediately, so it allows you to reference original _inputs_ only. +Unlike the `pkg` binding in the above example, the `self` parameter always references the final attributes. For instance `(pkg.overrideAttrs(x)).self.public` is identical to `pkg.overrideAttrs(x)`, whereas `(pkg.overrideAttrs(x)).original` is the same as `pkg`. See also the section about [`passthru.tests`](#var-meta-tests). diff --git a/pkgs/applications/misc/hello/default.nix b/pkgs/applications/misc/hello/default.nix index 0ea6570b32087..75887348730f1 100644 --- a/pkgs/applications/misc/hello/default.nix +++ b/pkgs/applications/misc/hello/default.nix @@ -28,7 +28,7 @@ stdenv.mkDerivation (self: { (nixos { environment.noXlibs = true; }).pkgs.hello; }; - passthru.tests.run = callPackage ./test.nix { hello = self; }; + passthru.tests.run = callPackage ./test.nix { hello = self.public; }; meta = with lib; { description = "A program that produces a familiar, friendly greeting"; diff --git a/pkgs/stdenv/generic/make-derivation.nix b/pkgs/stdenv/generic/make-derivation.nix index 2a47ea993839a..ac661d9429ff9 100644 --- a/pkgs/stdenv/generic/make-derivation.nix +++ b/pkgs/stdenv/generic/make-derivation.nix @@ -17,52 +17,50 @@ let else makeDerivationExtensibleConst mkDerivationSimple fnOrAttrs; # Based off lib.makeExtensible, with modifications: - # - lib.fix' -> lib.fix ∘ mkDerivationSimple; then inline fix - # - convert `f` to an overlay - # - inline overrideAttrs and make it positional instead of // to reduce allocs makeDerivationExtensible = mkDerivationSimple: rattrs: let - r = 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 - 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)) - (rattrs r); - in r; + args = rattrs (args // { inherit public; }); + public = + 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 + 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 public; # 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 - 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: attrs // f self attrs)) + mkDerivationSimple + (f0: + let + f = self: super: + let x = f0 super; + in + if builtins.isFunction x + then + f0 self super + else x; + in + makeDerivationExtensible mkDerivationSimple (self: attrs // f self attrs)) attrs; in |