"Guix drops" part 1: package transformations

by Marius Bakke — Mon 14 November 2022

This is the first part of a series where I'll showcase advanced features of Guix that may not be known to the average user.

They are inspired by the "Nix pills" series. I'm calling them "drops" as some pills are hard to swallow, and because I'm not a total fraud. The best medicines are often liquid, too.

One of the coolest features of Guix is the ability to transform packages "on the fly", directly from the command line. Software is, as its name implies, supposed to be malleable, unlike hardware and some humans.

Many transformation options are available, I'll demonstrate some of them here.

--with-source is useful when you want to build a package with a different source code than the one in Guix. I previously wrote about how guix shell is great for software development: --with-source makes it easy to also install your patched software, and test other packages against the patched version.

A real world example is trying software that I hack on:

guix shell zabbix-cli \
  --with-source=zabbix-cli=$HOME/src/zabbix-cli \
  -- zabbix-cli

This will build zabbix-cli with my local source checkout and enter a new shell environment with the patched zabbix-cli available. The -- zabbix-cli at the end instructs guix shell to also run the patched zabbix-cli executable directly instead of just giving that boring Bash prompt waiting for my input.

Another cool transformation option is --with-latest. Let's say you are a user of zabbix-cli and the package in Guix is older than the latest release (shame on me for that, as a contributor to both projects!). You can simply instruct guix shell (or guix install, guix package, etc) to use the latest version:

guix shell zabbix-cli --with-latest=zabbix-cli

Guix will download the latest tagged release and build it on the fly. All transformations are cached, so if you run the same command again it does not have to be built anew (unless an even newer version is released, of course, at which point Guix will hopefully consider it).

This can also be used to try newer versions of dependencies. For example, if I want to check whether zabbix-cli works with the latest requests package:

guix shell zabbix-cli --with-latest=python-requests

Now Guix will fetch the latest version of python-requests and build zabbix-cli against it (and run tests, etc). Neat!

For packages that are built from a Git checkout, you can also use specific commits or branches:

guix shell zabbix-cli --with-commit=zabbix-cli=abc123 \
  --with-branch=python-requests=late-bugfixes-2022 \
  --with-source=python=within

Here we also build the Python interpreter from a hypothetical within directory which presumably contains some long overdue performance improvements.

Creativity is the limit for these transformations; I often use them along with git bisect, for example to track down which change in SQLite lead to a test failure in NSS.

The amount of effort that has been put into making Guix such a developer-friendly tool is humbling! I wish I could take credit for some of it, but that honor is not mine to bear. I'm just a happy user of these parts of the Guix codebase.