Next: Build Systems, Previous: Defining Packages, Up: Programming Interface [Contents][Index]
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
language. The (guix packages)
module provides the package
construct to define new package objects (see package Reference).
The easiest way to define a package variant is using the inherit
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
vintage!):
(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 hello
, except version
and source
,
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)))))
The 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
Manual).
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 luasocket
packages
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.1-socket
and
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"))))
The 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
"gcc"
or "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
graph.
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.
Next: Build Systems, Previous: Defining Packages, Up: Programming Interface [Contents][Index]