Monday, November 10, 2014

Nix pill 17: nixpkgs, overriding packages

Welcome to the 17th Nix pill. In the previous 16th pill we have started to dive into the nixpkgs repository. Nixpkgs is a function, and we've looked at some parameters like system and config.

Today we'll talk about a special attribute: config.packageOverrides. Overriding packages in a set with fixed point can be considered another design pattern in nixpkgs.

Overriding a package


I recall the override design pattern from the nix pill 14. Instad of calling a function with parameters directly, we make the call (function + parameters) overridable.
We put the override function in the returned attribute set of the original function call.

Take for example graphviz. It has an input parameter xlibs. If it's null, then graphviz will build without X support.
$ nix-repl
nix-repl> :l <nixpkgs>
Added 4360 variables.
nix-repl> :b graphviz.override { xlibs = null; }
This will build graphviz without X support, it's as simple as that.

However let's say a package P depends on graphviz, how do we make P depend on the new graphviz without X support?

In an imperative world...


...you could do something like this:
pkgs = import <nixpkgs> {};
pkgs.graphviz = pkgs.graphviz.override { xlibs = null; };
build(pkgs.P)
Given pkgs.P depends on pkgs.graphviz, it's easy to build P with the replaced graphviz. On a pure functional language it's not that easy because you can assign to variables only once.

Fixed point


The fixed point with lazy evaluation is crippling but about necessary in a language like Nix. It lets us achieve something similar to what we'd do imperatively.
Follows the definition of fixed point in nixpkgs:
# Take a function and evaluate it with its own returned value.
fix = f: let result = f result; in result;
It's a function that accepts a function f, calls f result on the result just returned by f result and returns it. In other words it's f(f(f(....
At first sight, it's an infinite loop. With lazy evaluation it isn't, because the call is done only when needed.
nix-repl> fix = f: let result = f result; in result
nix-repl> pkgs = self: { a = 3; b = 4; c = self.a+self.b; }
nix-repl> fix pkgs
{ a = 3; b = 4; c = 7; }
Without the rec keyword, we were able to refer to a and b of the same set.
  1. First pkgs gets called with an unevaluated thunk (pkgs(pkgs(...)
  2. To set the value of c then self.a and self.b are evaluated.
  3. The pkgs function gets called again to get the value of a and b.
The trick is that c is not needed to be evaluated in the inner call, thus it doesn't go in an infinite loop.

Won't go further with the explanation here. A good post about fixed point and Nix can be found here.

Overriding a set with fixed point


Given that self.a and self.b refer to the passed set and not to the literal set in the function, we're able to override both a and b and get a new value for c:
nix-repl> overrides = { a = 1; b = 2; }
nix-repl> let newpkgs = pkgs (newpkgs // overrides); in newpkgs
{ a = 3; b = 4; c = 3; }
nix-repl> let newpkgs = pkgs (newpkgs // overrides); in newpkgs // overrides
{ a = 1; b = 2; c = 3; }
In the first case we computed pkgs with the overrides, in the second case we also included the overriden attributes in the result.

Overriding nixpkgs packages


We've seen how to override attributes in a set such that they get recursively picked by dependant attributes. This approach can be used for derivations too, after all nixpkgs is a giant set of attributes that depend on each other.

To do this, nixpkgs offers config.packageOverrides. So nixpkgs returns a fixed point of the package set, and packageOverrides is used to inject the overrides.

Create a config.nix file like this somewhere:
{
  packageOverrides = pkgs: {
    graphviz = pkgs.graphviz.override { xlibs = null; };
  };
}
Now we can build e.g. asciidocFull and it will automatically use the overridden graphviz:
nix-repl> pkgs = import <nixpkgs> { config = import ./config.nix; }
nix-repl> :b pkgs.asciidocFull
Note how we pass the config with packageOverrides when importing nixpkgs. Then pkgs.asciidocFull is a derivation that has graphviz input (pkgs.asciidoc is the lighter version and doesn't use graphviz at all).

Since there's no version of asciidoc with graphviz without X support in the binary cache, Nix will recompile the needed stuff for you.

The ~/.nixpkgs/config.nix file


In the previous pill we already talked about this file. The above config.nix that we just wrote could be the content of ~/.nixpkgs/config.nix.

Instead of passing it explicitly whenever we import nixpkgs, it will be automatically imported by nixpkgs.

Conclusion


We've learned about a new design pattern: using fixed point for overriding packages in a package set.

Whereas in an imperative setting, like with other package managers, a library is installed replacing the old version and applications will use it, in Nix it's not that straight and simple. But it's more precise.

Nix applications will depend on specific versions of libraries, hence the reason why we have to recompile asciidoc to use the new graphviz library.

The newly built asciidoc will depend on the new graphviz, and old asciidoc will keep using the old graphviz undisturbed.

Next pill


...we will stop diving nixpkgs for a moment and talk about store paths. How does Nix compute the path in the store where to place the result of builds? How to add files to the store for which we have an integrity hash?

Pill 18 is available for reading here.

To be notified about the new pill, stay tuned on #NixPills, follow @lethalman or subscribe to the nixpills rss.

Tuesday, November 04, 2014

Nix pill 16: nixpkgs, the parameters

Welcome to the 16th Nix pill. In the previous 15th pill we've realized how nix finds expressions with the angular brackets syntax, so that we finally know where is <nixpkgs> located on our system.

We can start diving into the nixpkgs repository, through all the various tools and design patterns. Please note that also nixpkgs has its own manual, underlying the difference between the general "nix" language and the "nixpkgs" repository.

The default.nix expression


We will not start inspecting packages at the beginning, rather the general structure of nixpkgs.
In our custom repository we created a default.nix which composed the expressions of the various packages.
Also nixpkgs has its own default.nix, which is the one being loaded when referring to <nixpkgs>. It does a simple thing: check whether the nix version is at least 1.7 (at the time of writing this blog post). Then import pkgs/top-level/all-packages.nix. From now on, we will refer to this set of packages as pkgs.

The all-packages.nix is then the file that composes all the packages. Note the pkgs/ subdirectory, while nixos is in the nixos/ subdirectory.

The all-packages.nix is a bit contrived. First of all, it's a function. It accepts a couple of interesting parameters:
  • system: defaults to the current system
  • config: defaults to null
  • others...
The system parameter, as per comment in the expression, it's the system for which the packages will be built. It allows for example to install i686 packages on amd64 machines.

The config parameter is a simple attribute set. Packages can read some of its values and change the behavior of some derivations.

The system parameter


You will find this parameter in many other .nix expressions (e.g. release expressions). The reason is that, given pkgs accepts a system parameter, then whenever you want to import pkgs you also want to pass through the value of system. E.g.:

myrelease.nix:
{ system ? builtins.currentSystem }:

let pkgs = import <nixpkgs> { inherit system; };
...
Why is it useful? With this parameter it's very easy to select a set of packages for a particular system. For example:
nix-build -A psmisc --argstr system i686-linux
This will build the psmisc derivation for i686-linux instead of x86_64-linux. This concept is very similar to multi-arch of Debian.

The setup for cross compiling is also in nixpkgs, however it's a little contrived to talk about it and I don't know much of it either.

The config parameter


I'm sure on the wiki or other manuals you've read about ~/.nixpkgs/config.nix and I'm sure you've wondered whether that's hardcoded in nix. It's not, it's in nixpkgs.

The all-packages.nix expression accepts the config parameter. If it's null, then it reads the NIXPKGS_CONFIG environment variable. If not specified, nixpkgs will peek $HOME/.nixpkgs/config.nix .  

After determining config.nix, it will be imported as nix expression, and that will be the value of config (in case it hasn't been passed as parameter to import <nixpkgs>).

The config is available in the resulting repository:
$ nix-repl
nix-repl> pkgs = import <nixpkgs> {}
nix-repl> pkgs.config
{ }
nix-repl> pkgs = import <nixpkgs> { config = { foo = "bar"; }; }
nix-repl> pkgs.config
{ foo = "bar"; }
What attributes go in config is a matter of convenience and conventions.

For example, config.allowUnfree is an attribute that forbids building packages that have an unfree license by default. The config.pulseaudio setting tells whether to build packages with pulseaudio support or not where applicable and when the derivation obeys to the setting.

About .nix functions


A .nix file contains a nix expression. Thus it can also be a function.
I remind you that nix-build expects the expression to return a derivation. Therefore it's natural to return straight a derivation from a .nix file.
However, it's also very natural for the .nix file to accept some parameters, in order to tweak the derivation being returned.

In this case, nix does a trick:
  • If the expression is a derivation, well build it.
  • If the expression is a function, call it and build the resulting derivation.
For example you can nix-build the .nix file below:
{ pkgs ? import <nixpkgs> {} }:

pkgs.psmisc
Nix is able to call the function because the pkgs parameter has a default value. This allows you to pass a different value for pkgs using the --arg option.

Does it work if you have a function returning a function that returns a derivation? No, Nix only calls the function it encounters once.

Conclusion


We've unleashed the <nixpkgs> repository. It's a function that accepts some parameters, and returns the set of all packages. Due to laziness, only the accessed derivations will be built.
You can use this repository to build your own packages as we've seen in the previous pill when creating our own repository.

Lately I'm a little busy with the NixOS 14.11 release and other stuff, and I'm also looking toward migrating from blogger to a more coder-oriented blogging platform. So sorry for the delayed  and shorter pills :)

Next pill


...we will talk about overriding packages in the nixpkgs repository. What if you want to change some options of a library and let all other packages pick the new library? One possibility is to use, like described above, the config parameter when applicable. The other possibility is to override derivations.

Pill 17 is available for reading here.

To be notified about the new pill, stay tuned on #NixPills, follow @lethalman or subscribe to the nixpills rss.