# Fixed-point arguments of build helpers {#chap-build-helpers-finalAttrs} `stdenv.mkDerivation` also accepts a [fixed-point function](#function-library-lib.fixedPoints.fix) instead of a plain attribute set: ```nix { 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`](#sec-pkg-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](https://nix.dev/manual/nix/stable/language/syntax#recursive-sets) for the underlying mechanism. ## Define a build helper with `lib.extendMkDerivation` {#sec-build-helper-extendMkDerivation} Use [`lib.customisation.extendMkDerivation`](#function-library-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 [`.overrideAttrs`](#sec-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`: ```nix { 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`: ```nix 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 ```nix { 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 ''; }); } ``` :::