guix commands let you specify package lists on the command line.
This is convenient, but as the command line becomes longer and less trivial,
it quickly becomes more convenient to have that package list in what we call
a manifest. A manifest is some sort of a “bill of materials” that
defines a package set. You would typically come up with a code snippet that
builds the manifest, store it in a file, say manifest.scm, and then
pass that file to the -m (or --manifest) option that many
guix commands support. For example, here’s what a manifest for a
simple package set might look like:
;; Manifest for three packages. (specifications->manifest '("gcc-toolchain" "make" "git"))
Once you have that manifest, you can pass it, for example, to
package to install just those three packages to your profile
(see -m option of
guix package -m manifest.scm
... or you can pass it to
guix shell (see
-m option of
guix shell) to spawn an ephemeral
guix shell -m manifest.scm
... or you can pass it to
guix pack in pretty much the same way
(see -m option of
guix pack). You can
store the manifest under version control, share it with others so they can
easily get set up, etc.
But how do you write your first manifest? To get started, maybe you’ll want
to write a manifest that mirrors what you already have in a profile. Rather
than start from a blank page,
guix package can generate a manifest
for you (see
guix package --export-manifest):
# Write to 'manifest.scm' a manifest corresponding to the # default profile, ~/.guix-profile. guix package --export-manifest > manifest.scm
Or maybe you’ll want to “translate” command-line arguments into a
manifest. In that case,
guix shell can help
guix shell --export-manifest):
# Write a manifest for the packages specified on the command line. guix shell --export-manifest gcc-toolchain make git > manifest.scm
In both cases, the --export-manifest option tries hard to generate a faithful manifest; in particular, it takes package transformation options into account (see 软件包转换选项).
注: Manifests are symbolic: they refer to packages of the channels currently in use (see 通道). In the example above,
gcc-toolchainmight refer to version 11 today, but it might refer to version 13 two years from now.
If you want to “pin” your software environment to specific package versions and variants, you need an additional piece of information: the list of channel revisions in use, as returned by
guix describe. See Replicating Guix, for more information.
Once you’ve obtained your first manifest, perhaps you’ll want to customize it. Since your manifest is code, you now have access to all the Guix programming interfaces!
Let’s assume you want a manifest to deploy a custom variant of GDB, the GNU Debugger, that does not depend on Guile, together with another package. Building on the example seen in the previous section (see Defining Package Variants), you can write a manifest along these lines:
(use-modules (guix packages) (gnu packages gdb) ;for 'gdb' (gnu packages version-control)) ;for 'git' ;; Define a variant of GDB without a dependency on Guile. (define gdb-sans-guile (package (inherit gdb) (inputs (modify-inputs (package-inputs gdb) (delete "guile"))))) ;; Return a manifest containing that one package plus Git. (packages->manifest (list gdb-sans-guile git))
Note that in this example, the manifest directly refers to the
git variables, which are bound to a
(see 软件包引用), instead of calling
specifications->manifest to look up packages by name as we did
use-modules form at the top lets us access the core
package interface (see 定义软件包) and the modules that define
git (see 软件包模块). Seamlessly, we’re
weaving all this together—the possibilities are endless, unleash your
The data type for manifests as well as supporting procedures are defined in
(guix profiles) module, which is automatically available to code
passed to -m. The reference follows.
Data type representing a manifest.
It currently has one field:
This must be a list of
manifest-entry records—see below.
Data type representing a manifest entry. A manifest entry contains essential metadata: a name and version string, the object (usually a package) for that entry, the desired output (see 有多个输出的软件包), and a number of optional pieces of information detailed below.
Most of the time, you won’t build a manifest entry directly; instead, you
will pass a package to
package->manifest-entry, described below. In
some unusual cases though, you might want to create manifest entries for
things that are not packages, as in this example:
;; Manually build a single manifest entry for a non-package object. (let ((hello (program-file "hello" #~(display "Hi!")))) (manifest-entry (name "foo") (version "42") (item (computed-file "hello-directory" #~(let ((bin (string-append #$output "/bin"))) (mkdir #$output) (mkdir bin) (symlink #$hello (string-append bin "/hello")))))))
The available fields are the following:
Name and version string for this entry.
A package or other file-like object (see file-like objects).
item to use, in case
item has multiple outputs
List of manifest entries this entry depends on. When building a profile, dependencies are added to the profile.
Typically, the propagated inputs of a package (see
propagated-inputs) end up having a corresponding manifest entry in
among the dependencies of the package’s own manifest entry.
The list of search path specifications honored by this entry (see Search Paths).
List of symbol/value pairs. When building a profile, those properties get serialized.
This can be used to piggyback additional metadata—e.g., the transformations applied to a package (see 软件包转换选项).
A promise pointing to the “parent” manifest entry.
This is used as a hint to provide context when reporting an error related to
a manifest entry coming from a
Concatenate the manifests listed in lst and return the resulting manifest.
of package package, where output defaults to
with the given properties. By default properties is the empty
list or, if one or more package transformations were applied to
package, it is an association list representing those transformations,
suitable as an argument to
The code snippet below builds a manifest with an entry for the default
output and the
send-email output of the
(use-modules (gnu packages version-control)) (manifest (list (package->manifest-entry git) (package->manifest-entry git "send-email")))
Return a list of manifest entries, one for each item listed in packages. Elements of packages can be either package objects or package/string tuples denoting a specific output of a package.
Using this procedure, the manifest above may be rewritten more concisely:
(use-modules (gnu packages version-control)) (packages->manifest (list git `(,git "send-email")))
of package for system, optionally when cross-compiling to target. Development inputs include both explicit and implicit inputs of package.
Like the -D option of
guix shell -D), the resulting
manifest describes the environment in which one can develop package.
For example, suppose you’re willing to set up a development environment for
Inkscape, with the addition of Git for version control; you can describe
that “bill of materials” with the following manifest:
(use-modules (gnu packages inkscape) ;for 'inkscape' (gnu packages version-control)) ;for 'git' (concatenate-manifests (list (package->development-manifest inkscape) (packages->manifest (list git))))
In this example, the development manifest that
package->development-manifest returns includes the compiler (GCC),
the many supporting libraries (Boost, GLib, GTK, etc.), and a couple of
additional development tools—these are the dependencies
(gnu packages) module provides higher-level facilities to
build manifests. In particular, it lets you look up packages by name—see
Given specs, a list of specifications such as
"guile:debug", return a manifest. Specs have the format that
command-line tools such as
guix install and
understand (see 调用guix package).
As an example, it lets you rewrite the Git manifest that we saw earlier like this:
(specifications->manifest '("git" "git:send-email"))
Notice that we do not need to worry about
use-modules, importing the
right set of modules, and referring to the right variables. Instead, we
directly refer to packages in the same way as on the command line, which can
often be more convenient.