First, I would first like to thank people that are supporting me via Librepay, your help is much appreciated.
Some history
When I started hacking on GNU Guix a few years ago, the image generation mechanism directly caught my attention. Turning a Scheme configuration file into a disk-image by running one command seemed futuristic to me.
At that time, I was working as an embedded software developer using Yocto and Buildroot, and constantly disappointed.
Turning Guix into an alternative quickly became a priority to me. The task wasn't easy. Guix System was only used as an x86_64 distribution, the only supported bootloader was Grub and the image generation used a complex mechanism spawning a virtual machine to produce a disk-image.
Thanks to pending patches from David Craven, I added support for extlinux and u-boot bootloaders. Then, some developments were necessary to support image generation, system reconfiguration and installation on ARMv7.
Soon, I was able to create a disk-image for my BeagleBone Black and wrote an article about it.
You can also have a look to the talk I gave at Fosdem 2020.
Further developments were required to make this first hack viable:
- Allow Guix System cross-compilation.
- Simplify the image generation mechanism by getting rid of the virtual machine step.
- Add an image API to ease image declaration.
Those developments kept me busy for the last two years, but were recently sped up thanks to Jan (janneke) Nieuwenhuizen and his tremendous work on the Hurd. Porting Guix System to the Hurd is achieved by cross-compiling a Guix System image for the i586-pc-gnu architecture. His work is detailed in this article.
Now, let's dive into this Guix System image API.
Guix System image API
Historically, Guix System is centered around an operating-system structure. This structure contains various fields ranging from the bootloader and kernel declaration to the services to install.
Turning this structure into a disk-image requires additional information such as the image label, size and partitioning. That's the purpose of the new image record.
(define-record-type* <image>
image make-image
image?
(name image-name ;symbol
(default #f))
(format image-format) ;symbol
(target image-target
(default #f))
(size image-size ;size in bytes as integer
(default 'guess))
(operating-system image-operating-system ;<operating-system>
(default #f))
(partitions image-partitions ;list of <partition>
(default '()))
(compression? image-compression? ;boolean
(default #t))
(volatile-root? image-volatile-root? ;boolean
(default #t))
(substitutable? image-substitutable? ;boolean
(default #t)))
This record also contains the operating-system to instantiate. The format
field defines the image type and can be disk-image
, compressed-qcow2
or
iso9660
. In the future, it could be extended to docker
or other image
types.
A new directory in the Guix sources is dedicated to images definition. For now there are two files:
- gnu/system/images/hurd.scm
- gnu/system/images/pine64.scm
Let's have a look to pine64.scm
. It contains the pine64-barebones-os
variable which is a minimal definition of an operating-system dedicated to the
Pine A64 LTS board.
(define pine64-barebones-os
(operating-system
(host-name "vignemale")
(timezone "Europe/Paris")
(locale "en_US.utf8")
(bootloader (bootloader-configuration
(bootloader u-boot-pine64-lts-bootloader)
(target "/dev/vda")))
(initrd-modules '())
(kernel linux-libre-arm64-generic)
(file-systems (cons (file-system
(device (file-system-label "my-root"))
(mount-point "/")
(type "ext4"))
%base-file-systems))
(services (cons (service agetty-service-type
(agetty-configuration
(extra-options '("-L")) ; no carrier detect
(baud-rate "115200")
(term "vt100")
(tty "ttyS0")))
%base-services))))
The kernel
and bootloader
fields are pointing to packages dedicated to
this board.
Right below, the pine64-image-type
variable is also defined.
(define pine64-image-type
(image-type
(name 'pine64-raw)
(constructor (cut image-with-os arm64-disk-image <>))))
It's using a record we haven't talked about yet, the image-type
record,
defined this way:
(define-record-type* <image-type>
image-type make-image-type
image-type?
(name image-type-name) ;symbol
(constructor image-type-constructor)) ;<operating-system> -> <image>
The main purpose of this record is to associate a name to a procedure transforming an operating-system to an image. To understand why it is necessary, let's have a look to the command producing a disk-image from an operating-system configuration file:
guix system disk-image my-os.scm
This command expects an operating-system configuration but how should we
indicate that we want an image targeting a Pine64 board? We need to provide an
extra information, the image-type
, by passing the --image-type
or -t
flag, this way:
guix system disk-image --image-type=pine64-raw my-os.scm
This image-type parameter points to the pine64-image-type
defined
above. Hence, the operating-system declared in my-os.scm
will be applied the
(cut image-with-os arm64-disk-image <>)
procedure to turn it into an image.
The resulting image looks like:
(image
(format 'disk-image)
(target "aarch64-linux-gnu")
(operating-system my-os)
(partitions
(list (partition
(inherit root-partition)
(offset root-offset)))))
which is the aggregation of the operating-system defined in my-os.scm
to the
arm64-disk-image
record.
But enough Scheme madness. What does this image API bring to the Guix user?
Image API usage
One can run:
mathieu@cervin:~$ guix system --list-image-types
The available image types are:
- pine64-raw
- hurd-raw
- hurd-qcow2
- iso9660
- uncompressed-iso9660
- raw
- qcow2
and by writing an operating-system file based on pine64-barebones-os
or
hurd-barebones-os
run:
guix system --image-type=pine64-raw my-pine-os.scm
or,
guix system --image-type=hurd-raw my-hurd-os.scm
to get a disk-image that can directly be written to a support and booted from.
Without changing anything to my-hurd-os.scm
, calling:
guix system --image-type=hurd-qcow2 my-hurd-os.scm
will instead produce a Hurd QEMU image.
This image API brings some flexibility to the image generation but there's still room for some improvements.
Future improvements
The first improvement would be to add support for new image-types so that Guix System can be used on other machines such as Novena, Pinebook Pro or MNT Reform. This task should now be relatively straightforward.
Some images built periodically by the CI are made available here. Adding images targeting new supported platforms, such as Pine64 LTS to this page would be nice.
Finally, images targeting foreign architectures are cross-compiled. As Guix cross-compilation support is not optimal yet, improving transparent emulation support could also help.
Now you are more familiar with the image API, feel free to join the party and help porting Guix System to your favourite machine!