Fixed-point arguments of build helpers
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
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
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
'';
});
}