Intro
This is the outline of a short session on Guix that I had the chance to organise at the 37th Chaos Communication Congress, or 37c3, in December 2023. It's not worth much, but I thought it was useful to have it here in case I want to reuse it or refer to it in the future.
What's Guix?
- A functional, transactional, declarative package manager and operating system. We'll see what this means in a minute.
- Inspired by the Nix project.
- Unprivileged package management.
- Written in Guile Scheme.
- Free Software, part of the GNU project.
Functional
A purely functional approach at package management. This is an example package definition.
(define-public hello (package (name "hello") (version "2.12.1") (source (origin (method url-fetch) (uri (string-append "mirror://gnu/hello/hello-" version ".tar.gz")) (sha256 (base32 "086vqwk2wl8zfs47sq2xpjc9k066ilmb8z6dn0q6ymwjzlm196cd")))) (build-system gnu-build-system) (synopsis "Hello, GNU world: An example GNU package") (description "GNU Hello prints the message \"Hello, world!\" and then exits. It serves as an example of standard GNU coding practices. As such, it supports command-line arguments, multiple languages, and so on.") (home-page "https://www.gnu.org/software/hello/") (license gpl3+)))
On a system where Guix is already installed, use guix search PACKAGE
to search
for packages, then guix edit PACKAGE
to look at the package definition.
guix search less guix edit less
Transactional
Package management operations via guix package
and related
commands. Operations are transactional, i.e. they either succeed or nothing
happens, and they can be rolled-back.
Some examples:
guix pull guix package --upgrade guix install emacs guix package --list-generations guix install vim guix package --list-generations guix package --roll-back guix package --switch-generation
Declarative
A base system definition
A base system definition can be created as follows.
(define-module (operating-system-base) #:use-module (gnu) #:export (operating-system-base)) (define operating-system-base (operating-system (host-name "host") (timezone "Europe/London") (locale "en_US.UTF-8") (bootloader (bootloader-configuration (bootloader grub-bootloader) (targets '("/dev/vda")))) (file-systems (cons (file-system (device "/dev/vda2") (mount-point "/") (type "ext4")) %base-file-systems)) (users (cons (user-account (name "user") (group "users") (password (crypt "password" "salt")) (home-directory "/home/user")) %base-user-accounts)))) operating-system-base
Build and run a system definition 1/2
Build a system image based on the definition above and run it with QEMU. This can be done with the following helper command.
$(guix system vm build/operating-system-base.scm)
When experimenting with the system in QEMU, note that ping
will not work, this
is expected because of -nic user
.
guix pull
also will not work, this is expected because the store is mounted
read-only. To have a fully working VM, build the image, make it writeable, and
launch it with QEMU, in separate steps, see below and this page on the manual.
Related commands: guix system image
, guix system reconfigure
.
A slightly more advanced system definition
This is a slightly more advanced system definition, where we add some packages and some services.
(define-module (operating-system-plus) #:use-module (gnu) #:use-module (gnu packages admin) #:use-module (gnu packages emacs) #:use-module (gnu services networking) #:export (operating-system-plus)) (define operating-system-plus (operating-system (host-name "host") (timezone "Europe/London") (locale "en_US.UTF-8") (bootloader (bootloader-configuration (bootloader grub-bootloader) (targets '("/dev/vda")))) (file-systems (cons (file-system (device "/dev/vda2") (mount-point "/") (type "ext4")) %base-file-systems)) (users (list (user-account (name "user") (group "users") (password (crypt "password" "salt")) (home-directory "/home/user")) (user-account (name "root") (group "users") (password (crypt "password" "salt")) (home-directory "/root")))) (packages (cons* emacs cloud-utils %base-packages)) (services (cons* (service dhcp-client-service-type) %base-services)))) operating-system-plus
This is another example where we include a typical desktop environment.
(define-module (operating-system-desktop) #:use-module (gnu) #:use-module (gnu packages admin) #:use-module (gnu packages emacs) #:use-module (gnu services desktop) #:export (operating-system-plus)) (define operating-system-desktop (operating-system (host-name "host") (timezone "Europe/London") (locale "en_US.UTF-8") (bootloader (bootloader-configuration (bootloader grub-bootloader) (targets '("/dev/vda")))) (file-systems (cons (file-system (device "/dev/vda2") (mount-point "/") (type "ext4")) %base-file-systems)) (users (list (user-account (name "user") (group "users") (password (crypt "password" "salt")) (home-directory "/home/user")))) (packages (cons* emacs cloud-utils %base-packages)) (services %desktop-services))) operating-system-desktop
And this is what the system looks like if booted with guix system vm
.
Figure 1: A Guix system run in QEMU.
Build and run a system definition 2/2
To have a fully working VM, build the image, make it writeable, and launch it with QEMU, in separate steps, see below.
orig=$(guix system image --image-type=qcow2 build/operating-system-plus.scm) dest=/tmp/qemu-image cp $orig $dest chmod +w $dest qemu-img resize -f qcow2 $dest +10G qemu-system-x86_64 \ -enable-kvm \ -m 8192 \ -nic user,model=virtio-net-pci \ -device virtio-blk,drive=myhd \ -drive if=none,file=$dest,id=myhd
Once deployed to a machine, an image can be resized so as to take all the
available space. We use growpart
, which is part of cloud-utils
:
Log in as root and use growpart
and resize2fs
as follows.
growpart /dev/vda 2 resize2fs /dev/vda2
Now log in as a user. It's finally possible to install new software:
guix install hello
How it works
$ guix describe Generation 274 Dec 23 2023 21:43:58 (current) guix a819663 repository URL: https://git.savannah.gnu.org/git/guix.git branch: master commit: a8196632647b343f8e03c8f12fbdc0cc84ff90f6
A quick introduction to: channels, package definitions, guix pull
, package
derivations, binaries in the store, path reconfiguration.
The Store
What is the Store? Let's have a look at the /gnu/store
folder.
$ ls /gnu/store | tail zzxqah5a58ns8dpsf0w6ka24vr562qns-valgrind-3.20.0.tar.bz2.drv zzyfc0d0z5h5c64n9bxarvkx3y48s2zd-rust-miniz-oxide-0.6.4.tar.gz.drv zzysk08z851qhwi42l6lq1f8nyn9k5vc-npth-1.6.drv zzyywykw7kriln18rxqd82f0k5kidla7-bash-static-5.1.16/ zzyzh5s2l4h5g47b8rwvnv8r7h8l4656-libffi-3.4.4.drv zzz15qg4lk5w5rgiiahaabz614vhy02x-enchant-1.6.0.tar.gz.drv zzzgxg4sdfim3crvarrfa9pm9zl30kbw-guix-system-tests-modules/ zzzpfppi800znv8vjd2ral25p3lzzz4l-ghc-strict-0.4.0.1.drv zzzv5j1c8yridwl52gvzlk5f2w4l78zl-ghc-generic-deriving-1.14.2.drv zzzyi178qx3pvmrk4sbdkr8mjqxama0r-cppcheck-2.10.3-checkout.drv
Let's see how any command links back to an item in the store.
$ which less
/home/user/.guix-home/profile/bin/less
$ namei $(which less)
f: /home/user/.guix-home/profile/bin/less
d /
d home
d user
l .guix-home -> /gnu/store/vx57sj8dzzl234y49hpmmk1jvaxjr6cs-home
d /
d gnu
d store
d vx57sj8dzzl234y49hpmmk1jvaxjr6cs-home
l profile -> /gnu/store/hms2bgscfj36sc5mm7a47j9msxqgkz26-profile
d /
d gnu
d store
d hms2bgscfj36sc5mm7a47j9msxqgkz26-profile
d bin
l less -> /gnu/store/30zfbjasrsk2wg8nhsd1xgi3q3n9796z-less-608/bin/less
d /
d gnu
d store
d 30zfbjasrsk2wg8nhsd1xgi3q3n9796z-less-608
d bin
- less
What's in a package?
$ tree $(guix build hello) | head
/gnu/store/6fbh8phmp3izay6c0dpggpxhcjn4xlm5-hello-2.12.1
├── bin
│ └── hello
├── etc
│ └── ld.so.cache
└── share
├── doc
│ └── hello-2.12.1
│ └── COPYING
├── info
...
Package dependencies
Guix provides a nice utility to visualise software dependencies.
guix graph coreutils | guix shell graphviz -- dot -Tjpg
Figure 2: Coreutils dependencies.
guix graph vim | guix shell graphviz -- dot -Tjpg
Figure 3: Vim dependencies.
guix graph emacs-minimal | guix shell graphviz -- dot -Tjpg -Gdpi=10
Figure 4: Emacs dependencies (emacs-minimal).
How many packages available?
Guix environments with guix shell
For instance:
guix shell python python-numpy -- python3
Containerisation:
guix shell --container python
A more advanced example to run Chromium with some lightweight isolation:
guix shell \ --container \ --network \ --no-cwd \ ungoogled-chromium \ --preserve="^DISPLAY$" \ --expose=/tmp/.X11-unix \ --expose=/home/user/.Xauthority \ -- chromium
A similar example to test Emacs with a particular font:
guix shell \ --no-cwd \ --container \ --expose=/tmp/.X11-unix \ --expose=/home/user/.Xauthority \ --preserve="^DISPLAY$" \ emacs fontconfig font-google-noto font-google-noto-emoji \ -- emacs
Guix for reproducibility
Let's refer to this paper: Vallet, Michonneau, Tournier, Toward practical transparent verifiable and long-term reproducible research using Guix.
[…] open tools like Guix can be used by any scientist to share their environment and allow peers to reproduce it.
Figure 5: Guix for scientific research reproducibility. Image: Vallet, Michonneau, Tournier.
Travelling in time is now possible, thanks to guix time-machine
.
guix time-machine \ --commit=769b96b62e8c09b078f73adc09fb860505920f8f \ -- shell gcc-toolchain
Guix as a package manager on a foreign distribution
E.g. on Debian, Ubuntu (with apt install guix
), or Arch (with pacman
guix-installer
or some variation thereof). On a foreign distro, after
installation it may be necessary to configure some environment variable, see the
manual for details.
After that, it will be possible to install Guix packages alongside your main operating system's package list.
Example on a Debian VPS
On the remote machine:
apt update apt install guix useradd -m -d /home/user -s /bin/bash user passwd user mkdir /home/user/.ssh
On the local machine:
scp /home/user/.ssh/id_rsa.pub root@IP-HERE:/home/user/.ssh/authorized_keys
Back on the remote machine:
chown -R user:user /home/user/.ssh chmod 700 /home/user/.ssh chmod 600 /home/user/.ssh/authorized_keys
After that, log in as a user and follow these instructions.
Guix Home
Users can declare all the packages and services that should be installed and configured for them, in their home/environment. See the relevant page on the manual.
For instance:
(use-modules (gnu home) (gnu home services) (gnu home services shells) (gnu services) (gnu packages admin) (guix gexp)) (home-environment (packages (list htop tree)) (services (list (service home-bash-service-type (home-bash-configuration (guix-defaults? #t) (bash-profile (list (plain-file "bash-profile" "export HISTFILE=$XDG_CACHE_HOME/.bash_history"))))) (simple-service 'test-config home-xdg-configuration-files-service-type (list `("test.conf" ,(plain-file "tmp-file.txt" "the content of ~/.config/test.conf")))))))
Guix Home in a container
Guix Home definitions can be instantiated and tested in a container, as follows.
guix home container build/home-configuration-base.scm
As expected, no command is available except htop
, tree
, and the basic Bash
utilities. Have a look at the files available with tree -pah
.
A more complicated example
See my Home configuration at file:///home/user/staging/guix-home/README-minimal.html.
Info on the current Guix Home
$ guix home describe Generation 813 Dec 23 2023 21:45:08 (current) file name: /var/guix/profiles/per-user/user/guix-home-813-link canonical file name: /gnu/store/5jvxybkjh2i7gg4ad1s61qgpql9wjy7z-home channels: guix: repository URL: https://git.savannah.gnu.org/git/guix.git branch: master commit: a8196632647b343f8e03c8f12fbdc0cc84ff90f6 configuration file: /gnu/store/...-configuration.scm
How to contribute
In (very) approximate order of difficulty:
- Simply using Guix, finding bugs, and submitting bug reports!
- Being part of the community, e.g. mailing lists and IRC.
- Updating existing package definitions or contributing new ones.
- Helping with code review, see this blog post.
- Contributing with patches (other than package definitions).
- Becoming a committer.
- …