Home Explore Blog Models CI



nixpkgs

11th chunk of `doc/stdenv/stdenv.chapter.md`
053d5f07b252f5a0f7b05be28c379ab1c98c469ee262295700000001000010ca
### Fixed-point arguments of `mkDerivation` {#mkderivation-recursive-attributes}

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" ];
})
```

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-passthru-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.

This generic command either invokes a script at *buildCommandPath*, or a *buildCommand*, or a number of *phases*. Package builds are split into phases to make it easier to override specific parts of the build (e.g., unpacking the sources or installing the binaries).

Each phase can be overridden in its entirety either by setting the environment variable `namePhase` to a string containing some shell commands to be executed, or by redefining the shell function `namePhase`. The former is convenient to override a phase from the derivation, while the latter is convenient from a build script. However, typically one only wants to *add* some commands to a phase, e.g. by defining `postInstall` or `preFixup`, as skipping some of the default actions may have unexpected consequences. The default script for each phase is defined in the file `pkgs/stdenv/generic/setup.sh`.

When overriding a phase, for example `installPhase`, it is important to start with `runHook preInstall` and end it with `runHook postInstall`, otherwise `preInstall` and `postInstall` will not be run. Even if you don't use them directly, it is good practice to do so anyways for downstream users who would want to add a `postInstall` by overriding your derivation.

While inside an interactive `nix-shell`, if you wanted to run all phases in the order they would be run in an actual build, you can invoke `genericBuild` yourself.

### Controlling phases {#ssec-controlling-phases}

There are a number of variables that control what phases are executed and in what order:

#### Variables affecting phase control {#variables-affecting-phase-control}

##### `phases` {#var-stdenv-phases}

Specifies the phases. You can change the order in which phases are executed, or add new phases, by setting this variable. If it’s not set, the default value is used, which is `$prePhases unpackPhase patchPhase $preConfigurePhases configurePhase $preBuildPhases buildPhase checkPhase $preInstallPhases installPhase fixupPhase installCheckPhase $preDistPhases distPhase $postPhases`.

Title: Nix `mkDerivation` `finalAttrs` and `stdenv` Build Phases
Summary
This chunk explains how `mkDerivation` in Nix uses a fixed-point argument `finalAttrs`, which is a function that receives the final, potentially overridden attributes. This mechanism allows for recursive attribute definitions and consistent overriding via `overrideAttrs`, eliminating the need for the `rec` keyword. An elaborate example demonstrates how `finalAttrs` and `finalPackage` can be used within `passthru` attributes. The text then transitions to `stdenv` build phases, detailing how `mkDerivation`'s `genericBuild` command splits builds into configurable stages like `unpackPhase`, `configurePhase`, and `installPhase`. These phases can be overridden or extended using `namePhase` environment variables or shell functions, with a recommendation to include `runHook pre<Phase>` and `runHook post<Phase>`. The `phases` variable is introduced as the primary way to control the execution order and inclusion of these build phases.