5 ms·
This usage of `orthogonal` feels misleading. Nix is built to be a purely functional software distribution model where the outputs can be computed from the speci
by pveierland 1y ago
This usage of `orthogonal` feels misleading. Nix is built to be a purely functional software distribution model where the outputs can be computed from the specified set of inputs. Although it is possible for derivations to not be reproducible, it seems incorrect to say that Nix is orthogonal to reproducible builds, as the point of the functional model is to nominally be able to get the same outputs given a set of inputs. Sure, Nix doesn't guarantee reproducibility of builds, but it certainly is designed to facilitate them (i.e. clearly correlated with reproducible builds and not being orthogonal to them).
- jchw 1y agoReproducible builds really are orthogonal to Nix, even if it seems like they're not. Nix was not built with reproducible builds in mind, and the problems it solves are ultimately independent even though they are related in some ways. The Nix PhD thesis by Eelco Dolstra, the founder of Nix, lays out the motivations for Nix very plainly. I decided I'd probably be better off quoting it directly than summarizing it poorly, so here goes: From The Purely Functional Software Deployment Model, "1.3. Motivation"[1]: From the previous discussion of existing deployment systems it should be clear that they lack important features to support safe and efficient deployment. In particular, they have some or all of the following problems: • Dependency specifications are not validated, leading to incomplete deployment. • Dependency specifications are inexact (e.g., nominal). • It is not possible to deploy multiple versions or variants of a component side-by-side. • Components can interfere with each other. • It is not possible to roll back to previous configurations. • Upgrade actions are not atomic. • Applications must be monolithic, i.e., they must statically contain all their depen- dencies. • Deployment actions can only be performed by administrators, not by unprivileged users. • There is no link between binaries and the sources and build processes that built them. • The system supports either source deployment or binary deployment, but not both; or it supports both but in a non-unified way. • It is difficult to adapt components. • Component composition is manual. • The component framework is narrowly restricted to components written in a specific programming language or framework. • The system depends on non-portable techniques. The objective of the research described in this thesis is to develop a deployment system that does not have these problems. Of course, part of the reason why reproducible builds was not considered for this is probably because it was simply not a hot topic at the time (had the term 'reproducible builds' even been coined yet?) and there were much bigger fish to fry with package management than reproducibility at that time, considering how relatively poorly packages were specified. Since then, "traditional" package managers and package repositories have put substantial work into cleaning up their package manifests and ensuring that they have accurate dependencies and other specifications such that today highly reproducible systems can be and have been built on top of them, limitations from the lack of hermetic guarantees notwithstanding. Despite this, because Nix does guarantee bit-exact external inputs to a derivation, it does indeed make an excellent starting point for reproducible builds, but Nix itself as a tool is definitely orthogonal to reproducible builds, as it solves an entirely different problem that just happens to be related. You don't need the purity guarantees Nix gives you to get reproducible builds, and having those purity guarantees don't automatically give you reproducible builds (though as seen by Nixpkgs, it isn't uncommon for a build to coincidentally be reproducible just as a result of packaging it into a Nix derivation... just, not really specifically guaranteed by anything.) [1]: https://edolstra.github.io/pubs/phd-thesis.pdf https://edolstra.github.io/pubs/phd-thesis.pdf
- pveierland 1y agoThe entire point of purity within Nix is to have reproducibility by its nature: `In this model a binary component is uniquely defined by the declared inputs used to build the component` (section 1.5). It is not clear to me how this is an entirely different problem than that of reproducible builds. Yes, there are more problems to solve regarding achieving bit-for-bit reproducible builds that Nix does not fully solve alone, but reproducible software builds and deployments clearly are goals of Nix as a technology.
- jchw 1y ago> The entire point of purity within Nix is to have reproducibility by its nature: `In this model a binary component is uniquely defined by the declared inputs used to build the component` (section 1.5). It is not clear to me how this is an entirely different problem than that of reproducible builds. Yes, there are more problems to solve regarding achieving bit-for-bit reproducible builds that Nix does not fully solve alone, but reproducible software builds and deployments clearly are goals of Nix as a technology. Sorry, but you pretty much quoted what I would've quoted to refute your claim: it's exactly right that binary components are uniquely defined by their declared inputs, but note the subtle consequence that has: they are not defined at all by their outputs, only their declared inputs. (Making them be defined by their outputs is entirely possible FWIW, this is pretty much what content-addressed Nix paths are for.) This also applies recursively: the bit-exactness of external inputs are guaranteed by cryptographic hashes, but if you have any inputs that are, themselves, derivations, you can extremely trivially add impurities, because the system is just simply not designed to stop you from doing this. An example: stdenv.mkDerivation { name = "trivialimpurity"; unpackPhase = "date>$out"; } It would be quite possible to make a system that is specifically designed to be resistant to this; consider that Nix goes great lengths to accomplish what it does, literally ripping apart ELF binaries to force dynamic symbols to be resolved in a static manner. There's no reason why you couldn't go further to force deeper reproducibility in a similar vein, it's just that Nix simply doesn't. I think it's actually OK that Nix doesn't attempt to resolve this problem, because it is a pretty hairy one. Obviously you can't practically make the build environment 100% completely reproducible as it would be painfully slow and weird, so the best you could really probably do is intercept syscalls and try to make threading behavior deterministic (which would also make builds slow as balls, but less slow than running every build in unaccelerated qemu or something like that.) What Nix does do is solve the living shit out of the problem it was designed to solve, something you can feel very viscerally when you compare the state of Nixpkgs to the state of the AUR (a package repo I consider to be very good, but definitely can give some perspective about the problems Nix is designed to solve IMO, based on some of the problems I've run into with it.)