Home Explore Blog CI



nixpkgs

5th chunk of `doc/stdenv/stdenv.chapter.md`
57d72d77c0e990c8337adb8ecaaea38d9fa5fd20ba34747700000001000010b6
As described in the Nix manual, almost any `*.drv` store path in a derivation’s attribute set will induce a dependency on that derivation. `mkDerivation`, however, takes a few attributes intended to include all the dependencies of a package. This is done both for structure and consistency, but also so that certain other setup can take place. For example, certain dependencies need their bin directories added to the `PATH`. That is built-in, but other setup is done via a pluggable mechanism that works in conjunction with these dependency attributes. See [](#ssec-setup-hooks) for details.

Dependencies can be broken down along these axes: their host and target platforms relative to the new derivation’s. The platform distinctions are motivated by cross compilation; see [](#chap-cross) for exactly what each platform means. [^footnote-stdenv-ignored-build-platform] But even if one is not cross compiling, the platforms imply whether a dependency is needed at run-time or build-time.

The extension of `PATH` with dependencies, alluded to above, proceeds according to the relative platforms alone. The process is carried out only for dependencies whose host platform matches the new derivation’s build platform i.e. dependencies which run on the platform where the new derivation will be built. [^footnote-stdenv-native-dependencies-in-path] For each dependency \<dep\> of those dependencies, `dep/bin`, if present, is added to the `PATH` environment variable.

### Dependency propagation {#ssec-stdenv-dependencies-propagated}

Propagated dependencies are made available to all downstream dependencies.
This is particularly useful for interpreted languages, where all transitive dependencies have to be present in the same environment.
Therefore it is used for the Python infrastructure in Nixpkgs.

:::{.note}
Propagated dependencies should be used with care, because they obscure the actual build inputs of dependent derivations and cause side effects through setup hooks.
This can lead to conflicting dependencies that cannot easily be resolved.
:::

:::{.example}
# A propagated dependency

```nix
with import <nixpkgs> { };
let
  bar = stdenv.mkDerivation {
    name = "bar";
    dontUnpack = true;
    # `hello` is also made available to dependents, such as `foo`
    propagatedBuildInputs = [ hello ];
    postInstall = "mkdir $out";
  };
  foo = stdenv.mkDerivation {
    name = "foo";
    dontUnpack = true;
    # `bar` is a direct dependency, which implicitly includes the propagated `hello`
    buildInputs = [ bar ];
    # The `hello` binary is available!
    postInstall = "hello > $out";
  };
in
foo
```
:::

Dependency propagation takes cross compilation into account, meaning that dependencies that cross platform boundaries are properly adjusted.

To determine the exact rules for dependency propagation, we start by assigning to each dependency a couple of ternary numbers (`-1` for `build`, `0` for `host`, and `1` for `target`) representing its [dependency type](#possible-dependency-types), which captures how its host and target platforms are each "offset" from the depending derivation’s host and target platforms. The following table summarize the different combinations that can be obtained:

| `host → target`     | attribute name      | offset   |
| ------------------- | ------------------- | -------- |
| `build --> build`   | `depsBuildBuild`    | `-1, -1` |
| `build --> host`    | `nativeBuildInputs` | `-1, 0`  |
| `build --> target`  | `depsBuildTarget`   | `-1, 1`  |
| `host --> host`     | `depsHostHost`      | `0, 0`   |
| `host --> target`   | `buildInputs`       | `0, 1`   |
| `target --> target` | `depsTargetTarget`  | `1, 1`   |

Algorithmically, we traverse propagated inputs, accumulating every propagated dependency’s propagated dependencies and adjusting them to account for the “shift in perspective” described by the current dependency’s platform offsets. This results is sort of a transitive closure of the dependency relation, with the offsets being approximately summed when two dependency links are combined. We also prune transitive dependencies whose combined offsets go out-of-bounds, which can be viewed as a filter over that transitive closure removing dependencies that are blatantly absurd.

Title: Dependency Propagation in Nix
Summary
This section elaborates on dependency propagation in Nix, where dependencies are made available to downstream dependencies, particularly useful for interpreted languages. It cautions against overuse due to potential conflicts and obscuring actual build inputs. It provides an example of how `propagatedBuildInputs` works. It takes cross-compilation into account when propagating dependencies, and defines the dependency type through ternary numbers representing the offset of host and target platforms. Finally, the text outlines an algorithm for dependency propagation, involving transitive closure and pruning to avoid absurd dependencies.