Guix Alchemy
Customisation with package transformations
Mastering Guix Packaging
- Rather than trying to learn it all pick a path
-
The main scenarios are
- Using an older package (downgrading)
- Rebuilding an existing package
- Modifying an existing package
- Creating a new package (with and without source)
- Contributing a package to the distribution
Package variant: the local build is different from the Guix archives
Learning Path
Profiles
Package
Commands
Shell
Command
Basic Build
Command
Manifests
Transform
Command
Manifests
Transforms in Manifests
Guix Build Overview
- Guix build is used to build a package (or a derivation)
- Receives:
- package definition
- Guix build options
- It outputs:
- build logs
- build derivation
- package
- Recommendation: use with guix shell for a clean build environment
$ guix build hello --no-substitutes --no-grafts
The following derivation will be built:
/gnu/store/xn12lv3ckihkai4044p28h5im78lvad5-hello-2.12.1.drv
[... lots of output as it builds the package ...]
successfully built /gnu/store/xn12lv3ckihkai4044p28h5im78lvad5-hello-2.12.1.drv
/gnu/store/5mqwac3zshjjn1ig82s12rbi7whqm4n8-hello-2.12.1
| Option | Description |
|---|---|
| --dry-run | Give output but don't take the action |
| --no-substitutes | Don't use binary substitutes |
| --no-grafts | Do not put security grafts onto packages |
| --verbosity=<lvl> | 0=no output; 1=quiet; 2=show urls; 3=build log |
| --cores=n | Use N CPU cores for each build job |
| --source | Build a source package |
| --max-jobs=N | Allow the Guix Daemon to run at most N build jobs. Each build can be limited to use --cores=N |
| --check |
Common Build Options
1
Create build environment with guix shell
3
Create a test environment with guix shell and test the new build
2
Build the current package to test dependencies
Package build steps
$ guix shell --container --nesting --development hello \
--network --no-grafts nss-certs
The following derivation will be built:
/gnu/store/jaz9fabc7l9iwkxf648iq0ajafzgs049-profile.drv
building CA certificate bundle...
listing Emacs sub-directories...
building fonts directory...
building directory of Info manuals...
building profile with 23 packages...Create a build environment
- nesting - run further package commands in the shell environment
- add nss-certs so that commands can use SSL
1
Rebuild the Package
$ guix shell --container --nesting --development hello \
--network --no-grafts nss-certs
The following derivation will be built:
/gnu/store/jaz9fabc7l9iwkxf648iq0ajafzgs049-profile.drv
building CA certificate bundle...
listing Emacs sub-directories...
building fonts directory...
building directory of Info manuals...
building profile with 23 packages...
[env]$ guix build --no-substitutes --no-grafts --source hello
The following derivation will be built:
/gnu/store/2p9bkv91gr64nm17qq0byavwg5q6w2lg-hello-2.12.1.tar.gz.drv
building /gnu/store/2p9bkv91gr64nm17qq0byavwg5q6w2lg-hello-2.12.1.tar.gz.drv...
Starting download of /gnu/store/3dq55rw99wdc4g4wblz7xikc8a2jy7a3-hello-2.12.1.tar.gz
From https://ftpmirror.gnu.org/gnu/hello/hello-2.12.1.tar.gz...
following redirection to `https://mirrors.tripadvisor.com/gnu/hello/hello-2.12.1.tar.gz'...
downloading from https://ftpmirror.gnu.org/gnu/hello/hello-2.12.1.tar.gz ...
hello-2.12.1.tar.gz 1009KiB 1.6MiB/s 00:01 [##################] 100.0%
successfully built /gnu/store/2p9bkv91gr64nm17qq0byavwg5q6w2lg-hello-2.12.1.tar.gz.drv
/gnu/store/3dq55rw99wdc4g4wblz7xikc8a2jy7a3-hello-2.12.1.tar.gz
download the source and put it into the store.
2
Rebuild the Package
[env]$ guix build --no-substitutes --no-grafts --source hello
The following derivation will be built:
/gnu/store/2p9bkv91gr64nm17qq0byavwg5q6w2lg-hello-2.12.1.tar.gz.drv
building /gnu/store/2p9bkv91gr64nm17qq0byavwg5q6w2lg-hello-2.12.1.tar.gz.drv...
Starting download of /gnu/store/3dq55rw99wdc4g4wblz7xikc8a2jy7a3-hello-2.12.1.tar.gz
From https://ftpmirror.gnu.org/gnu/hello/hello-2.12.1.tar.gz...
following redirection to `https://mirrors.tripadvisor.com/gnu/hello/hello-2.12.1.tar.gz'...
downloading from https://ftpmirror.gnu.org/gnu/hello/hello-2.12.1.tar.gz ...
hello-2.12.1.tar.gz 1009KiB 1.6MiB/s 00:01 [##################] 100.0%
successfully built /gnu/store/2p9bkv91gr64nm17qq0byavwg5q6w2lg-hello-2.12.1.tar.gz.drv
/gnu/store/3dq55rw99wdc4g4wblz7xikc8a2jy7a3-hello-2.12.1.tar.gz
[env]$ guix build --no-substitutes --no-grafts --verbosity=1 hello
The following derivation will be built:
/gnu/store/3zh2qpi897s2x229s93iakji86b08a20-hello-2.12.1.drv
building /gnu/store/3zh2qpi897s2x229s93iakji86b08a20-hello-2.12.1.drv...
/gnu/store/5mqwac3zshjjn1ig82s12rbi7whqm4n8-hello-2.12.1
2
$ guix shell --container --nesting --no-grafts
guix shell: warning: no packages specified; creating an empty environment
The following derivation will be built:
/gnu/store/jv8hws211gw8vbv9rcjnigl5xik1k8vq-profile.drv
building CA certificate bundle...
listing Emacs sub-directories...
building fonts directory...
building directory of Info manuals...
building profile with 1 package...Test the Package
- no network as we're installing locally
- no packages as we're just going to test it
- add testing packages through a manifest (for example coreutils)
- Install the package into a test shell - use it!
- 🏆 TIP: by avoiding installing it into a standard profile we can delete it:
$ guix gc --delete /gnu/store/<blah>
OR use --check
3
$ guix shell --container --nesting --no-grafts
guix shell: warning: no packages specified; creating an empty environment
The following derivation will be built:
/gnu/store/jv8hws211gw8vbv9rcjnigl5xik1k8vq-profile.drv
building CA certificate bundle...
listing Emacs sub-directories...
building fonts directory...
building directory of Info manuals...
building profile with 1 package...
[env]$ guix shell --install /gnu/store/3zh2qpi897s2x229s93iakji86b08a20-hello-2.12.1.drv
The following package will be installed:
hello 2.12.1
The following derivation will be built:
/gnu/store/kkf3dwfjy1mkll3m4wbcxx76v2p2yjyc-profile.drv
building CA certificate bundle...
listing Emacs sub-directories...
building fonts directory...
building directory of Info manuals...
building profile with 1 package...
hint: Consider setting the necessary environment variables by running:
GUIX_PROFILE="/home/steve/.guix-profile"
. "$GUIX_PROFILE/etc/profile"
Alternately, see `guix package --search-paths -p "/home/steve/.guix-profile"'.
$ /home/steve/.guix-profile/bin/hello
Hello,world!Test the Package
Success!
3
VIDEO
Guix Build
2:40 minutes
1
2
3
Package Transformations
- Modify an existing package
- Create a package variant by alterating
-
Elements we can change
-
Source
- latest available
- specific version
- git repository
- Inputs
- Build process
- Source alterations - patches
- Tuning for specific hardware
-
Source
-
The package transformation can take place:
- using the cli tools
- using a package definition
- using a manifest
CLI Package Transformations
$ guix build calcurse --with-source=https://calcurse.org/files/calcurse-4.8.1.tar.gz \
--no-substitutes --no-graftspackage to build
source URL
$ guix build calcurse --with-source=calcurse@4.8.1.01=https://calcurse.org/files/calcurse-4.8.1.tar.gz \
--no-substitutes --no-graftsnormal build options
version to use
| Option | Description |
|---|---|
| with-source | Build the package using a specified source. URL or file. Can be either source for the build, or an input. |
| with-input | Use a specified package as an input to the build. |
| with-git-url | The same as with-source but use a specified git URL. Builds from HEAD, unless --with-commit is used. |
| with-commit | Use the a set commit |
| with-branch | Build a particular branch, default is master |
| with-latest | Build a package using the latest upstream release of the source that the importer can detect. |
| with-version | Use a specific release of the upstream source release. |
| | |
| with-configure-flags | Customise by adding configure flags |
| with-patch | Customise the build's source with a patch |
Transformation Options
1
Create build environment with guix shell
3
Create a test environment with guix shell and test the new build
2
Build the current package to test dependencies
Package build steps
1
Create build environment with guix shell
3
Build the package using a transformation
2
Build the current package to test dependencies
4
Install the new package into a new test environment
Package build steps
$ guix shell --development fzf --container --nesting \
--network --no-grafts nss-certs
The following derivation will be built:
/gnu/store/fgc04pns05wp0yxwmm7xnvkpcybs3k1c-profile.drv
2.0 MB will be downloaded
go-github-com-mattn-go-isatty-0.0.11 4KiB 201KiB/s 00:00 ▕██████████████████▏ 100.0%
go-golang-org-x-crypto-0.4.0 1.4MiB 817KiB/s 00:02 ▕██████████████████▏ 100.0%
go-golang-org-x-sys-0.8.0-0.ca59eda 569KiB 90KiB/s 00:06 ▕██████████████████▏ 100.0%
go-golang-org-x-term-0.3.0 13KiB 74KiB/s 00:00 ▕██████████████████▏ 100.0%
building CA certificate bundle...
listing Emacs sub-directories...
building fonts directory...
building directory of Info manuals...
building profile with 37 packages...Git Package Transformation
- development: all the pkgs needed to build
- nesting: so we can run commands
- nss-certs pkg added for downloads
[env]$ guix build fzf --with-git-url=fzf=https://github.com/junegunn/fzf \
--with-commit=fzf=0.44.1 --no-substitutes --no-grafts
updating checkout of 'https://github.com/junegunn/fzf'...
retrieved commit d7d2ac39513f2068f70fbe717d212c9bce8750ed
The following derivation will be built:
/gnu/store/ix845m79aw8l08h7d7737x2gl0pn25mn-fzf-0.44.1.drv
building /gnu/store/ix845m79aw8l08h7d7737x2gl0pn25mn-fzf-0.44.1.drv...
[... lots of build output ...]
successfully built /gnu/store/ix845m79aw8l08h7d7737x2gl0pn25mn-fzf-0.44.1.drv
/gnu/store/ihlh8nip211l2lm6p3h0502jwbpzrps1-fzf-0.44.1Package to build
Package to build from git
- the package itself
- input to package
Commit to use
- commit hash
- tag
Git repository URL
VIDEO
Guix Transformation
~ minutes
TBD
Transformations in Manifests
- A manifest contains a collection of packages
- Often used to declaratively install packages into a profile
-
Actually manifests are code
- GNU Guile
- Uses lots Guix provided functions
-
Guile is in the Scheme family
- A lot of parentheses
- Be a rebel and space them vertically if it helps!
- For the most part consider it a DSL
(specifications->manifest (list "calcurse"))Package Transformations
(specifications->manifest
(list "calcurse" "cbonsai@1.3.1" "git:send-email")
)Lists hold multiple things
Different package specs using their names
$ guix shell --container --nesting --manifest=basic-manifest.scm
The following derivation will be built:
/gnu/store/4hr96x21bs1w23gfp6ynlghkfiav1zh6-profile.drv
applying 4 grafts for calcurse-4.5.1 ...
applying 3 grafts for cbonsai-1.3.1 ...
building CA certificate bundle...
listing Emacs sub-directories...
building fonts directory...
generating GLib schema cache...
building directory of Info manuals...
building XDG desktop file cache...
building XDG MIME database...
building profile with 4 packages...
[env]$ guix package --list-installed --profile=$GUIX_ENVIRONMENT
guix 31e736... out /gnu/store/caqz00i1b1qwhlsb7v5j6lgr5l9x78n8-profile
git 2.41.0 send-email /gnu/store/gdh0p...p14n6fsj1gz04mx-git-2.41.0-send-email
cbonsai 1.3.1 out /gnu/store/zbjphbd9v7rbadv2y8jb7k9qqvzf5s4q-cbonsai-1.3.1
calcurse 4.5.1 out /gnu/store/1bgjd0l2dlpjj29x8faik724xz2jzivn-calcurse-4.5.1A function that's called with the provided list
The Lisperati will hunt you down for this!!! It is evil OMG!!!!!
Create a manifest called basic-manifest.scm:
works with guix shell and guix package
- Reading from inside to the outside often helps
-
Lines 1-3: Guile code can contain modules
- The profile and transformations provide the Guix functions
- We need (gnu packages calcurse) so we can call the calcurse package
-
Lines 10: calcurse-transform the calcurse variable
- Next it's formed into manifest by package->manifest
-
Line 7-8: calcurse-transform
- calcurse-src is evaluated
- calcurse-src is transformed with options->transformation
- Line 5: calcurse-src is a Guile pair consisting of the 'with-source' transformation and a location for the code
Basic manifest transformation
(use-modules (guix profile)
(guix transformations)
(gnu packages calcurse))
(define calcurse-src '(with-source . "https://calcurse.org/files/calcurse-4.8.1.tar.gz"))
(define calcurse-transform
(options->transformation (list calcurse-src)))
(package->manifest (list (calcurse-transform calcurse)))1
Create build environment with guix shell
3
Build the package using the transformation
2
Build the current package to test dependencies
4
Install the new package into a new test environment
Package build steps
1
Create build environment with guix shell
3
Create a manifest
Install the new package into a new test environment
2
Build the current package to test dependencies
4
Build the package using the transformation
Package build steps
5
Git transformation
-
Conceptually the same as previously:
- we create a transformation and apply it to the package
- we convert from the transformed package to a manifest
- A bit more condensed as we're now familiar with the format
- Uses a list of git transformations
(use-modules (guix profiles)
(guix transformations)
(gnu packages terminals))
(define fzf-transform (options->transformation
(list '(with-git-url . "fzf=https://github.com/junegunn/fzf")
'(with-commit . "fzf=2024010"))))
(packages->manifest (list (fzf-transform fzf)))Advanced: multiple packages
Multiple packages and multiple transformations ...
- 4 and 8: two transforms
- 14-15: two transformations, converted into a list
- 13: a separate list of packages
- 12: add the transforms to the first list creating a big list
(use-modules (guix profiles)
(guix transformations))
(define fzf-transform (options->transformation
(list '(with-git-url . "fzf=https://github.com/junegunn/fzf")
'(with-commit . "fzf=2024010"))))
(define calcurse-transform (options->transformation
'((with-source . "calcurse@20231207=https://calcurse.org/files/calcurse-4.8.1.tar.gz"))))
(packages->manifest
(append
(specifications->packages (list "hello" "cbonsai" "gnupg"))
(list (fzf-transform (specification->package "fzf"))
(calcurse-transform (specification->package "calcurse")))))The equivalent of: guix shell --development mutt vim git
- 8-9: normal specification of packages
- 6-7: converts to a development manifest
- 5: create a list
- 4: turn into a manifest
Advanced: multiple manifests
(use-modules (guix profiles)
(guix transformations))
(concatenate-manifests
(list
(package->development-manifest
(specification->package "mutt"))
(packages->manifest
(specifications->packages (list "vim" "git")))))
Development manifest to install all required libraries ...
Advanced: package name
- What we did so far was create the same package but with some different inputs
-
This time we're doing a package inheritance
- inheritance uses Scheme records - bottom line we can change some fields
- We run the transform which outputs a package
- We then use package/inherit to change some fields: technically this is a new package
(use-modules (guix profiles)
(guix transformations)
(guix packages)
(gnu packages calcurse))
(define calcurse-transform
((options->transformation
(list '(with-source . "calcurse=https://calcurse.org/files/calcurse-4.5.0.tar.gz")))
calcurse))
(define calcurse-local (package/inherit
calcurse-transform
(name "calcurse-local")
(version "4.5.0")))
(packages->manifest (list calcurse-local))Give the package variant a different name ...
What we've seen
Package transformations give us sophisticated capabilities to build package variants
1
Transforms
Manifests are a declarative way to manage an environment
2
Manifests
Transforms and manifests together give us a lot of flexibility and repeatability
3
Alchemy
Package Transformation Alchemy
- Package transformations let us create locally build package variants
-
Implications
- They use the package definition (recipe) that's in the archive
- Only used to alter packages, not to create new ones
- The source location needs to be processable by the package definition
- The source can't have changed in some way the package definition isn't expecting
- Uncomfortable tracking which packages have been altered
Taking it further:
- Gentoo Use flags are a more flexible system
- Flags have to be exposed by the packager
- Examples: https://www.gentoo.org/support/use-flags/
- GSoC 2023: https://blog.lispy.tech/2023/05/parameterized-packages.html
Steps from here
Profiles
Package
Commands
Shell
Command
Basic Build
Command
Manifests
Transform
Command
Manifests
Transforms in Manifests
Package Definitions
Creating new packages
Thank You!
Questions?
Palette
By futurile
Palette
- 313