One of the nice things with Guix is that, given a package definition, you can easily derive variants of that package—for a different upstream version, with different dependencies, different compilation options, and so on. Some of these custom packages can be defined straight from the command line (see Package Transformation Options). This section describes how to define package variants in code. This can be useful in “manifests” (see --manifest) and in your own package collection (see Creating a Channel), among others!
As discussed earlier, packages are first-class objects in the Scheme
(guix packages) module provides the
construct to define new package objects (see package Reference).
The easiest way to define a package variant is using the
keyword together with
package. This allows you to inherit from a
package definition while overriding the fields you want.
For example, given the
hello variable, which contains a
definition for the current version of GNU Hello, here’s how you
would define a variant for version 2.2 (released in 2006, it’s
(use-modules (gnu packages base)) ;for 'hello' (define hello-2.2 (package (inherit hello) (version "2.2") (source (origin (method url-fetch) (uri (string-append "mirror://gnu/hello/hello-" version ".tar.gz")) (sha256 (base32 "0lappv4slgb5spyqbh6yl5r013zv72yqg2pcl30mginf3wdqd8k9"))))))
The example above corresponds to what the --with-source package
transformation option does. Essentially
hello-2.2 preserves all
the fields of
which it overrides. Note that the original
hello variable is
still there, in the
(gnu packages base) module, unchanged. When
you define a custom package like this, you are really adding a
new package definition; the original one remains available.
You can just as well define variants with a different set of
dependencies than the original package. For example, the default
gdb package depends on
guile, but since that is an
optional dependency, you can define a variant that removes that
dependency like so:
(use-modules (gnu packages gdb) ;for 'gdb' (srfi srfi-1)) ;for 'alist-delete' (define gdb-sans-guile (package (inherit gdb) (inputs (alist-delete "guile" (package-inputs gdb)))))
alist-delete call above removes the tuple from the
inputs field that has
"guile" as its first element
(see SRFI-1 Association Lists in GNU Guile Reference
In some cases, you may find it useful to write functions
(“procedures”, in Scheme parlance) that return a package based on some
parameters. For example, consider the
luasocket library for the
Lua programming language. We want to create
for major versions of Lua. One way to do that is to define a procedure
that takes a Lua package and returns a
luasocket package that
depends on it:
(define (make-lua-socket name lua) ;; Return a luasocket package built with LUA. (package (name name) (version "3.0") ;; several fields omitted (inputs `(("lua" ,lua))) (synopsis "Socket library for Lua"))) (define-public lua5.1-socket (make-lua-socket "lua5.1-socket" lua-5.1)) (define-public lua5.2-socket (make-lua-socket "lua5.2-socket" lua-5.2))
Here we have defined packages
lua5.2-socket by calling
make-lua-socket with different
arguments. See Procedures in GNU Guile Reference Manual, for
more info on procedures. Having top-level public definitions for these
two packages means that they can be referred to from the command line
(see Package Modules).
These are pretty simple package variants. As a convenience, the
(guix transformations) module provides a high-level interface
that directly maps to the more sophisticated package transformation
options (see Package Transformation Options):
Return a procedure that, when passed an object to build (package, derivation, etc.), applies the transformations specified by opts and returns the resulting objects. opts must be a list of symbol/string pairs such as:
((with-branch . "guile-gcrypt=master") (without-tests . "libgcrypt"))
Each symbol names a transformation and the corresponding string is an argument to that transformation.
For instance, a manifest equivalent to this command:
guix build guix \ --with-branch=guile-gcrypt=master \ --with-debug-info=zlib
... would look like this:
(use-modules (guix transformations)) (define transform ;; The package transformation procedure. (options->transformation '((with-branch . "guile-gcrypt=master") (with-debug-info . "zlib")))) (packages->manifest (list (transform (specification->package "guix"))))
options->transformation procedure is convenient, but it’s
perhaps also not as flexible as you may like. How is it implemented?
The astute reader probably noticed that most package transformation
options go beyond the superficial changes shown in the first examples of
this section: they involve input rewriting, whereby the dependency
graph of a package is rewritten by replacing specific inputs by others.
Dependency graph rewriting, for the purposes of swapping packages in the
graph, is what the
package-input-rewriting procedure in
(guix packages) implements.
Return a procedure that, when passed a package, replaces its direct and indirect dependencies, including implicit inputs when deep? is true, according to replacements. replacements is a list of package pairs; the first element of each pair is the package to replace, and the second one is the replacement.
Optionally, rewrite-name is a one-argument procedure that takes the name of a package and returns its new name after rewrite.
Consider this example:
(define libressl-instead-of-openssl ;; This is a procedure to replace OPENSSL by LIBRESSL, ;; recursively. (package-input-rewriting `((,openssl . ,libressl)))) (define git-with-libressl (libressl-instead-of-openssl git))
Here we first define a rewriting procedure that replaces openssl with libressl. Then we use it to define a variant of the git package that uses libressl instead of openssl. This is exactly what the --with-input command-line option does (see --with-input).
The following variant of
package-input-rewriting can match packages to
be replaced by name rather than by identity.
Return a procedure that, given a package, applies the given
replacements to all the package graph, including implicit inputs
unless deep? is false. replacements is a list of
spec/procedures pair; each spec is a package specification such as
"guile@2", and each procedure takes a matching
package and returns a replacement for that package.
The example above could be rewritten this way:
(define libressl-instead-of-openssl ;; Replace all the packages called "openssl" with LibreSSL. (package-input-rewriting/spec `(("openssl" . ,(const libressl)))))
The key difference here is that, this time, packages are matched by spec and
not by identity. In other words, any package in the graph that is called
openssl will be replaced.
A more generic procedure to rewrite a package dependency graph is
package-mapping: it supports arbitrary changes to nodes in the
Return a procedure that, given a package, applies proc to all the packages depended on and returns the resulting package. The procedure stops recursion when cut? returns true for a given package. When deep? is true, proc is applied to implicit inputs as well.