The papercut thread - post your small annoyances/confusions here

Yeah, that explanation is really very internals-focused. Here’s a (hopefully) more comprehensible explanation that focuses more on how to use it, and only on implementation details that directly affect the use of it:

Putting a dependency a in the propagatedBuildInputs of derivation b has two main effects:

  1. It treats a as a dependecy of b, just as if you had buildInputs = [ a ]; in b
  2. It “propagates” this dependency relationship onwards to all derivations that depend (directly or transitively) on b

For example, if you have a derivation c with b specified as a buildInput, the underlying nixpkgs machinery will ensure that c also effectively has a as a propagatedBuildInput, meaning it gets a as a direct dependency (available in its builder) rather than simply depending on it transitively (as a result of b being built with it).

As a is effectively added to c’s propagatedBuildInputs, anything that depends on c will also get a added to their own propagatedBuildInputs. The overall effect is that anything that has b anywhere in its dependency closure gets a direct dependency on a (at least if we ignore cross-compilation cases).

This effect is used in several ways in nixpkgs and NixOS. A few of the language-specific infrastructures make use of it to ensure that executables have access to their run-time dependencies.

For example: Python library/module dependencies are specified as propagatedBuildInputs, and the Python mkDerivation wrapper (buildPythonPackage) wraps any Python executable scripts produced by it to give them references to the paths of all their Python dependencies. This ensures that Python scripts have access to their full (Python) dependency closure at run-time, which is necessary because it is an interpreted language.

For the languages-specific infrastructures that do this, propagatedBuildInputs can also be seen as “a list of dependencies that need to be available to $lang scripts at run-time”.

17 Likes