✦ For everyone, free.

Practical knowledge for real and everyday life

Home

Derivations and Build Inputs

Derivations and Build Inputs define how packages are built in Linux, specifying dependencies and inputs needed for consistent, reproducible software creation.

Derivations and Build Inputs are fundamental concepts in the Nix package management system, which operates on the principle of purely functional package management. A derivation is the core data structure in Nix that describes how to build a package. It is a low-level, immutable representation of the build action, containing all information necessary for the Nix build system to produce a package output deterministically.

Build inputs refer to the dependencies or resources required by a derivation to complete its build process. These inputs include other derivations, source files, patches, configuration flags, and environment variables that influence the build. By explicitly specifying build inputs, Nix ensures reproducibility and isolation, as the build environment only includes declared dependencies.


Derivations in Detail

Definition and Role

A derivation in Nix is a JSON-like data structure generated by the Nix expression language. It encodes the build instructions, including:

  • The builder program or script used to compile or assemble the package.
  • Arguments passed to the builder.
  • Environment variables required during the build.
  • Input dependencies (build inputs).
  • Output paths where the built package will be stored.
  • Platform and system constraints.

Derivations are stored as .drv files in the Nix store and are immutable. Each derivation has a unique hash derived from its contents, ensuring that any change in the build instructions or inputs leads to a new derivation and therefore a new build output.

Creation and Usage

Derivations are typically created automatically by Nix expressions written in the Nix language. For example, when using nix-build on a package expression, Nix evaluates the expression to produce a derivation, then builds it.

The derivation itself is not the package but a recipe for building the package. This separation allows Nix to cache builds, detect rebuild needs efficiently, and share build outputs across systems.


Build Inputs

Types of Build Inputs

Build inputs are the packages or files that a derivation depends on to successfully build its output. They fall into several categories:

  • Build-time dependencies: Tools and libraries required only during the build process (e.g., compilers, build tools).
  • Runtime dependencies: Libraries or resources needed for the package to function after installation. These are typically specified separately but can also influence the build.
  • Source inputs: Source code, patches, or archives that the build process compiles or packages.
  • Environment inputs: Variables or configuration files that affect the build.

Management and Specification

Build inputs are declared explicitly in the derivation. The Nix language provides attributes such as buildInputs and nativeBuildInputs:

  • buildInputs: Dependencies required for both build and runtime.
  • nativeBuildInputs: Dependencies needed only during the build (e.g., build tools like gcc or make).

These inputs are passed into the build environment, ensuring that the build process is hermetic — it only uses what is declared, preventing accidental dependencies on the host system.

Isolation and Reproducibility

Because build inputs are explicitly declared and isolated, Nix can reproduce builds reliably on any system. Nix constructs a sandboxed environment where only the specified inputs are visible, which guarantees deterministic builds and reduces "works on my machine" problems.


Interaction Between Derivations and Build Inputs

Dependency Graph Construction

Derivations form a directed acyclic graph (DAG) of dependencies, where nodes are derivations and edges are build inputs. This graph allows Nix to:

  • Parallelize builds where possible.
  • Cache and reuse build results of dependencies.
  • Track and update dependencies efficiently.

Hashing and Caching

The unique hash of a derivation incorporates the hashes of all its build inputs. This means if any build input changes, the derivation hash changes, triggering a rebuild. This content-addressed approach ensures consistency and cache correctness across builds and machines.

Build Execution

When Nix builds a derivation, it sets up a build environment containing all declared build inputs, passes the build instructions to the builder, and produces output stored in the Nix store. The resulting output can itself be a build input for other derivations, continuing the chain.


Practical Example

Consider a simple derivation for building a C program:

stdenv.mkDerivation {
  name = "hello-1.0";
  src = ./hello.c;
  buildInputs = [ gcc ];
  buildPhase = ''
    gcc -o hello hello.c
  '';
  installPhase = ''
    mkdir -p $out/bin
    cp hello $out/bin/
  '';
}
  • The derivation specifies a source file (src).
  • The buildInputs contains gcc, the compiler needed at build time.
  • buildPhase and installPhase are commands executed during the build.
  • The resulting package is stored at the $out path in the Nix store.

This derivation file (.drv) encodes the exact instructions and inputs required to build the "hello" program reproducibly.


Summary

Derivations are the fundamental building blocks in Nix that define how to build packages in a purely functional manner. They store immutable, content-addressed build instructions and their dependencies. Build inputs are the explicit dependencies needed during the build process, ensuring isolation, reproducibility, and determinism. Together, they enable Nix to manage packages reliably across different systems by constructing a precise, declarative build graph.