What is considered a build input when building a software project?

Semi-crossposting from Stackoverflow; to my defence, I was hoping to get theoretical (and tool-agnostic) answers to that question but then I started wondering what the Nix community opinion is.

When thinking of build inputs, I think of the source, and all of its dependencies.

But controls (build flags, CLI options of the build tool, module attributes, etc.) also affect the behaviour/feature set/etc. of the end result, and are also a sort of input, so what else am I missing?

Please support your answer with references to books, papers, blog posts etc. Thank you!


My biggest problem in finding relevant resources is that many of these terms are overloaded…

I dunno about the theory, but if you take a package like ffmpeg-full in nixpkgs as an example, you can see that in practice, many of the controls are very much considered build inputs.

1 Like

Found the talk OSSAT 2017 - Purely Functional Configuration Management with Nix and NixOS by Joël Franusic) by accident, that shows a comprehensive list of the items that I lumped together under the name “controls”, such as:

  • software configuration
  • system configuration
  • runtime options
  • runtime environment

Also really liked Joël’s explanation and visual representation of what a Nix closure is (paraphrasing here):

If you flip a single flag of the compiler, you get a different package. Same happens when the value of an environment variable is changed.

image

What is considered a build input when building a software project?

Derivation input is anything passed to derivation function. Nothing more and nothing less. (Use cat $(nix-instantiate -A hello) or nix show-derivation -f . hello with unstable Nix in the Nixpkgs repo to see the hello derivation inputs.)

Note that while this removes most common sources of non-determinism, it still does not guarantee fully reproducible builds as it is not feasible to shield the build from everything. For example, a build system can enable optimizations based on available CPU features (and to prevent this in all cases we ¿would have to run builds on some kind of abstract CPU? not my area of expertise). And then there is non-determinism caused by concurrency.

We have r13y (reproducibility) initiative precisely to battle this kind of non-determinism that cannot be captured by Nix model.


Just to be clear this refers to the flags of the compiler and environment at build time (so it is in fact run time from the compiler’s perspective but these terms might cause some confusion).

While the build inputs do affect the derivation and, as a result, the closure, the term closure usually refers to the graph of dependencies of a derivation/store path. That is more high-level view that only cares about the dependency relation.

You can view them using the following command (note xdot is very slow so it will take a while):

  • build-time closure: dependency graph of derivations nix-store -q --graph $(nix-instantiate -A hello) | xdot -
  • run-time closure: dependency graph of store paths nix-store -q --graph $(nix-build -A hello) | xdot -
1 Like