stdenv.mkDerivation also accepts a fixed-point function instead of a plain attribute set:
{ stdenv, fetchurl,}:stdenv.mkDerivation (finalAttrs: { pname = "hello"; version = "2.12";
src = fetchurl { url = "mirror://gnu/hello/hello-${finalAttrs.version}.tar.gz"; hash = "sha256-..."; };})The function’s input, conventionally named finalAttrs, is the final state of the attribute set. Here src reads finalAttrs.version instead of repeating the version string. A build helper like this is said to accept fixed-point arguments.
Attributes that reference each other through finalAttrs stay correct when changing any of them with overrideAttrs, because they all access the final values of the fixed-point computation.
rec cannot do this: its self-references are fixed when the set is defined and ignore later overrides.
See recursive-sets for the underlying mechanism.
Define a build helper with lib.extendMkDerivation
Use lib.customisation.extendMkDerivation to define a build helper with fixed-point support from an existing one.
Its argument extendDrvArgs takes an attribute overlay similar to <pkg>.overrideAttrs.
Besides overriding, lib.extendMkDerivation also supports excludeDrvArgNames to optionally exclude some arguments in the input fixed-point arguments from passing down to the base build helper (specified as constructDrv).
:::{.example #ex-build-helpers-extendMkDerivation}
Example mkLocalDerivation - a build helper over mkDerivation
Define a build helper named mkLocalDerivation that builds locally without using substitutes by default.
Use lib.extendMkDerivation:
{ lib, stdenv,}:lib.extendMkDerivation { constructDrv = stdenv.mkDerivation; excludeDrvArgNames = [ # Don't pass specialArg into mkDerivation. "specialArg" ]; extendDrvArgs = finalAttrs: { preferLocalBuild ? true, allowSubstitute ? false, specialArg ? (_: false), ... }@args: { # Arguments to pass inherit preferLocalBuild allowSubstitute; # Some expressions involving specialArg greeting = if specialArg "hi" then "hi" else "hello"; };}:::
To apply extra changes to the result derivation, pass transformDrv to lib.extendMkDerivation:
lib.customisation.extendMkDerivation { transformDrv = drv: /...; }Construct a wrapper derivation around another derivation using transformDrv
The wrapper has access to the original arguments
:::{.example #ex-build-helpers-extendMkDerivation-transformDrv-wrapper}
Define a custom build helper that downloads and builds
{ lib, stdenvNoCC, cacert, configure-example, download-example,}:
lib.extendMkDerivation { constructDrv = stdenvNoCC.mkDerivation;
excludeDrvArgNames = [ "bar" ];
extendDrvArgs = finalAttrs: { bar, foo, hash ? "", ... }@args: { inherit hash; nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [ cacert download-example ]; buildPhase = '' runHook preBuild download-example --foo="$foo" --out="$out" runHook postBuild ''; impureEnvVars = lib.fetchers.proxyImpureEnvVars; outputHash = if finalAttrs.hash != "" then finalAttrs.hash else lib.fakeHash; outputHashFormat = "recursive"; passthru = args.passthru or { } // { inherit bar; }; };
transformDrv = unwrapped: stdenvNoCC.mkDerivation (finalAttrs: { name = finalAttrs.src.name + "-wrapped"; src = unwrapped; nativeBuildInputs = [ configure-example ]; inherit (unwrapped) bar; buildPhase = '' runHook preBuild configure-example --bar="$bar" runHook postBuild ''; });}