\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename guix-cookbook.info @documentencoding UTF-8 @settitle GNU Guix Cookbook @c %**end of header @copying Copyright @copyright{} 2019 Ricardo Wurmus@* Copyright @copyright{} 2019 Efraim Flashner@* Copyright @copyright{} 2019 Pierre Neidhardt@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. @end copying @dircategory System administration @direntry * Guix cookbook: (guix-cookbook). Tutorials and examples for GNU Guix. @end direntry @titlepage @title GNU Guix Cookbook @subtitle Tutorials and examples for using the GNU Guix Functional Package Manager @author The GNU Guix Developers @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @c ********************************************************************* @node Top @top GNU Guix Cookbook This document presents tutorials and detailed examples for GNU@tie{}Guix, a functional package management tool written for the GNU system. Please @pxref{Top,,, guix, GNU Guix reference manual} for details about the system, its API, and related concepts. @c TRANSLATORS: You can replace the following paragraph with information on @c how to join your own translation team and how to report issues with the @c translation. If you would like to translate this document in your native language, consider joining the @uref{https://translationproject.org/domain/guix-cookbook.html, Translation Project}. @menu * Scheme tutorials:: Meet your new favorite language! * Packaging:: Packaging tutorials * System Configuration:: Customizing the GNU System * Advanced package management:: Power to the users! * Acknowledgments:: Thanks! * GNU Free Documentation License:: The license of this document. * Concept Index:: Concepts. @detailmenu --- The Detailed Node Listing --- Scheme tutorials * A Scheme Crash Course:: Learn the basics of Scheme Packaging * Packaging Tutorial:: Let's add a package to Guix! System Configuration * Customizing the Kernel:: Creating and using a custom Linux kernel @end detailmenu @end menu @c ********************************************************************* @node Scheme tutorials @chapter Scheme tutorials GNU@tie{}Guix is written in the general purpose programming language Scheme, and many of its features can be accessed and manipulated programmatically. You can use Scheme to generate package definitions, to modify them, to build them, to deploy whole operating systems, etc. Knowing the basics of how to program in Scheme will unlock many of the advanced features Guix provides --- and you don't even need to be an experienced programmer to use them! Let's get started! @node A Scheme Crash Course @section A Scheme Crash Course @cindex Scheme, crash course Guix uses the Guile implementation of Scheme. To start playing with the language, install it with @code{guix install guile} and start a @uref{https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop, REPL} by running @code{guile} from the command line. Alternatively you can also run @code{guix environment --ad-hoc guile -- guile} if you'd rather not have Guile installed in your user profile. In the following examples we use the @code{>} symbol to denote the REPL prompt, that is, the line reserved for user input. @xref{Using Guile Interactively,,, guile, GNU Guile Reference Manual}) for more details on the REPL. @itemize @item Scheme syntax boils down to a tree of expressions (or @emph{s-expression} in Lisp lingo). An expression can be a literal such as numbers and strings, or a compound which is a parenthesized list of compounds and literals. @code{#t} and @code{#f} stand for the booleans "true" and "false", respectively. Examples of valid expressions: @lisp > "Hello World!" "Hello World!" > 17 17 > (display (string-append "Hello " "Guix" "\n")) "Hello Guix!" @end lisp @item This last example is a function call nested in another function call. When a parenthesized expression is evaluated, the first term is the function and the rest are the arguments passed to the function. Every function returns the last evaluated expression as its return value. @item Anonymous functions are declared with the @code{lambda} term: @lisp > (lambda (x) (* x x)) #:24:0 (x)> @end lisp The above procedure returns the square of its argument. Since everything is an expression, the @code{lambda} expression returns an anonymous procedure, which can in turn be applied to an argument: @lisp > ((lambda (x) (* x x)) 3) 9 @end lisp @item Anything can be assigned a global name with @code{define}: @lisp > (define a 3) > (define square (lambda (x) (* x x))) > (square a) 9 @end lisp @item Procedures can be defined more concisely with the following syntax: @lisp (define (square x) (* x x)) @end lisp @item A list structure can be created with the @code{list} procedure: @lisp > (list 2 a 5 7) (2 3 5 7) @end lisp @item The @emph{quote} disables evaluation of a parenthesized expression: the first term is not called over the other terms. Thus it effectively returns a list of terms. @lisp > '(display (string-append "Hello " "Guix" "\n")) (display (string-append "Hello " "Guix" "\n")) > '(2 a 5 7) (2 a 5 7) @end lisp @item The @emph{quasiquote} disables evaluation of a parenthesized expression until a comma re-enables it. Thus it provides us with fine-grained control over what is evaluated and what is not. @lisp > `(2 a 5 7 (2 ,a 5 ,(+ a 4))) (2 a 5 7 (2 3 5 7)) @end lisp Note that the above result is a list of mixed elements: numbers, symbols (here @code{a}) and the last element is a list itself. @item Multiple variables can be named locally with @code{let}: @lisp > (define x 10) > (let ((x 2) (y 3)) (list x y)) (2 3) > x 10 > y ERROR: In procedure module-lookup: Unbound variable: y @end lisp Use @code{let*} to allow later variable declarations to refer to earlier definitions. @lisp > (let* ((x 2) (y (* x 3))) (list x y)) (2 6) @end lisp @item The keyword syntax is @code{#:}; it is used to create unique identifiers. @pxref{Keywords,,, guile, GNU Guile Reference Manual}. @item The percentage @code{%} is typically used for read-only global variables in the build stage. Note that it is merely a convention, like @code{_} in C. Scheme treats @code{%} exactly the same as any other letter. @item Modules are created with @code{define-module}. For instance @lisp (define-module (guix build-system ruby) #:use-module (guix store) #:export (ruby-build ruby-build-system)) @end lisp defines the module @code{guix build-system ruby} which must be located in @file{guix/build-system/ruby.scm} somewhere in the Guile load path. It depends on the @code{(guix store)} module and it exports two variables, @code{ruby-build} and @code{ruby-build-system}. @end itemize For a more detailed introduction, check out @uref{http://www.troubleshooters.com/codecorn/scheme_guile/hello.htm, Scheme at a Glance}, by Steve Litt. One of the reference Scheme books is the seminal ``Structure and Interpretation of Computer Programs'', by Harold Abelson and Gerald Jay Sussman, with Julie Sussman. You'll find a @uref{https://mitpress.mit.edu/sites/default/files/sicp/index.html, free copy online}, together with @uref{https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/, videos of the lectures by the authors}. The book is available in Texinfo format as the @code{sicp} Guix package. Go ahead, run @code{guix install sicp} and start reading with @code{info sicp} (or with the Emacs Info reader). An @uref{https://sarabander.github.io/sicp/, unofficial ebook is also available}. You'll find more books, tutorials and other resources at @url{https://schemers.org/}. @c ********************************************************************* @node Packaging @chapter Packaging @cindex packaging This chapter is dedicated to teaching you how to add packages to the collection of packages that come with GNU Guix. This involves writing package definitions in Guile Scheme, organizing them in package modules, and building them. @menu * Packaging Tutorial:: A tutorial on how to add packages to Guix. @end menu @node Packaging Tutorial @section Packaging Tutorial GNU Guix stands out as the @emph{hackable} package manager, mostly because it uses @uref{https://www.gnu.org/software/guile/, GNU Guile}, a powerful high-level programming language, one of the @uref{https://en.wikipedia.org/wiki/Scheme_%28programming_language%29, Scheme} dialects from the @uref{https://en.wikipedia.org/wiki/Lisp_%28programming_language%29, Lisp family}. Package definitions are also written in Scheme, which empowers Guix in some very unique ways, unlike most other package managers that use shell scripts or simple languages. @itemize @item Use functions, structures, macros and all of Scheme expressiveness for your package definitions. @item Inheritance makes it easy to customize a package by inheriting from it and modifying only what is needed. @item Batch processing: the whole package collection can be parsed, filtered and processed. Building a headless server with all graphical interfaces stripped out? It's possible. Want to rebuild everything from source using specific compiler optimization flags? Pass the @code{#:make-flags "..."} argument to the list of packages. It wouldn't be a stretch to think @uref{https://wiki.gentoo.org/wiki/USE_flag, Gentoo USE flags} here, but this goes even further: the changes don't have to be thought out beforehand by the packager, they can be @emph{programmed} by the user! @end itemize The following tutorial covers all the basics around package creation with Guix. It does not assume much knowledge of the Guix system nor of the Lisp language. The reader is only expected to be familiar with the command line and to have some basic programming knowledge. @subsection A "Hello World" package The “Defining Packages” section of the manual introduces the basics of Guix packaging (@pxref{Defining Packages,,, guix, GNU Guix Reference Manual}). In the following section, we will partly go over those basics again. ``GNU hello'' is a dummy project that serves as an idiomatic example for packaging. It uses the GNU build system (@code{./configure && make && make install}). Guix already provides a package definition which is a perfect example to start with. You can look up its declaration with @code{guix edit hello} from the command line. Let's see how it looks: @lisp (define-public hello (package (name "hello") (version "2.10") (source (origin (method url-fetch) (uri (string-append "mirror://gnu/hello/hello-" version ".tar.gz")) (sha256 (base32 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))) (build-system gnu-build-system) (synopsis "Hello, GNU world: An example GNU package") (description "GNU Hello prints the message \"Hello, world!\" and then exits. It serves as an example of standard GNU coding practices. As such, it supports command-line arguments, multiple languages, and so on.") (home-page "https://www.gnu.org/software/hello/") (license gpl3+))) @end lisp As you can see, most of it is rather straightforward. But let's review the fields together: @table @samp @item name The project name. Using Scheme conventions, we prefer to keep it lower case, without underscore and using dash-separated words. @item source This field contains a description of the source code origin. The @code{origin} record contains these fields: @enumerate @item The method, here @code{url-fetch} to download via HTTP/FTP, but other methods exist, such as @code{git-fetch} for Git repositories. @item The URI, which is typically some @code{https://} location for @code{url-fetch}. Here the special `mirror://gnu` refers to a set of well known locations, all of which can be used by Guix to fetch the source, should some of them fail. @item The @code{sha256} checksum of the requested file. This is essential to ensure the source is not corrupted. Note that Guix works with base32 strings, hence the call to the @code{base32} function. @end enumerate @item build-system This is where the power of abstraction provided by the Scheme language really shines: in this case, the @code{gnu-build-system} abstracts away the famous @code{./configure && make && make install} shell invocations. Other build systems include the @code{trivial-build-system} which does not do anything and requires from the packager to program all the build steps, the @code{python-build-system}, the @code{emacs-build-system}, and many more (@pxref{Build Systems,,, guix, GNU Guix Reference Manual}). @item synopsis It should be a concise summary of what the package does. For many packages a tagline from the project's home page can be used as the synopsis. @item description Same as for the synopsis, it's fine to re-use the project description from the homepage. Note that Guix uses Texinfo syntax. @item home-page Use HTTPS if available. @item license See @code{guix/licenses.scm} in the project source for a full list of available licenses. @end table Time to build our first package! Nothing fancy here for now: we will stick to a dummy "my-hello", a copy of the above declaration. As with the ritualistic "Hello World" taught with most programming languages, this will possibly be the most "manual" approach. We will work out an ideal setup later; for now we will go the simplest route. Save the following to a file @file{my-hello.scm}. @lisp (use-modules (guix packages) (guix download) (guix build-system gnu) (guix licenses)) (package (name "my-hello") (version "2.10") (source (origin (method url-fetch) (uri (string-append "mirror://gnu/hello/hello-" version ".tar.gz")) (sha256 (base32 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))) (build-system gnu-build-system) (synopsis "Hello, Guix world: An example custom Guix package") (description "GNU Hello prints the message \"Hello, world!\" and then exits. It serves as an example of standard GNU coding practices. As such, it supports command-line arguments, multiple languages, and so on.") (home-page "https://www.gnu.org/software/hello/") (license gpl3+)) @end lisp We will explain the extra code in a moment. Feel free to play with the different values of the various fields. If you change the source, you'll need to update the checksum. Indeed, Guix refuses to build anything if the given checksum does not match the computed checksum of the source code. To obtain the correct checksum of the package declaration, we need to download the source, compute the sha256 checksum and convert it to base32. Thankfully, Guix can automate this task for us; all we need is to provide the URI: @c TRANSLATORS: This is example shell output. @example sh $ guix download mirror://gnu/hello/hello-2.10.tar.gz Starting download of /tmp/guix-file.JLYgL7 From https://ftpmirror.gnu.org/gnu/hello/hello-2.10.tar.gz... following redirection to `https://mirror.ibcp.fr/pub/gnu/hello/hello-2.10.tar.gz'... …10.tar.gz 709KiB 2.5MiB/s 00:00 [##################] 100.0% /gnu/store/hbdalsf5lpf01x4dcknwx6xbn6n5km6k-hello-2.10.tar.gz 0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i @end example In this specific case the output tells us which mirror was chosen. If the result of the above command is not the same as in the above snippet, update your @code{my-hello} declaration accordingly. Note that GNU package tarballs come with an OpenPGP signature, so you should definitely check the signature of this tarball with `gpg` to authenticate it before going further: @c TRANSLATORS: This is example shell output. @example sh $ guix download mirror://gnu/hello/hello-2.10.tar.gz.sig Starting download of /tmp/guix-file.03tFfb From https://ftpmirror.gnu.org/gnu/hello/hello-2.10.tar.gz.sig... following redirection to `https://ftp.igh.cnrs.fr/pub/gnu/hello/hello-2.10.tar.gz.sig'... ….tar.gz.sig 819B 1.2MiB/s 00:00 [##################] 100.0% /gnu/store/rzs8wba9ka7grrmgcpfyxvs58mly0sx6-hello-2.10.tar.gz.sig 0q0v86n3y38z17rl146gdakw9xc4mcscpk8dscs412j22glrv9jf $ gpg --verify /gnu/store/rzs8wba9ka7grrmgcpfyxvs58mly0sx6-hello-2.10.tar.gz.sig /gnu/store/hbdalsf5lpf01x4dcknwx6xbn6n5km6k-hello-2.10.tar.gz gpg: Signature made Sun 16 Nov 2014 01:08:37 PM CET gpg: using RSA key A9553245FDE9B739 gpg: Good signature from "Sami Kerola " [unknown] gpg: aka "Sami Kerola (http://www.iki.fi/kerolasa/) " [unknown] gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. Primary key fingerprint: 8ED3 96E3 7E38 D471 A005 30D3 A955 3245 FDE9 B739 @end example You can then happily run @c TRANSLATORS: Do not translate this command @example sh $ guix package --install-from-file=my-hello.scm @end example You should now have @code{my-hello} in your profile! @c TRANSLATORS: Do not translate this command @example sh $ guix package --list-installed=my-hello my-hello 2.10 out /gnu/store/f1db2mfm8syb8qvc357c53slbvf1g9m9-my-hello-2.10 @end example We've gone as far as we could without any knowledge of Scheme. Before moving on to more complex packages, now is the right time to brush up on your Scheme knowledge. @pxref{A Scheme Crash Course} to get up to speed. @c TODO: Continue the tutorial @c ********************************************************************* @node System Configuration @chapter System Configuration Guix offers a flexible language for declaratively configuring your Guix System. This flexibility can at times be overwhelming. The purpose of this chapter is to demonstrate some advanced configuration concepts. @pxref{System Configuration,,, guix, GNU Guix Reference Manual} for a complete reference. @menu * Customizing the Kernel:: Creating and using a custom Linux kernel on Guix System. @end menu @node Customizing the Kernel @section Customizing the Kernel Guix is, at its core, a source based distribution with substitutes (@pxref{Substitutes,,, guix, GNU Guix Reference Manual}), and as such building packages from their source code is an expected part of regular package installations and upgrades. Given this starting point, it makes sense that efforts are made to reduce the amount of time spent compiling packages, and recent changes and upgrades to the building and distribution of substitutes continues to be a topic of discussion within Guix. The kernel, while not requiring an overabundance of RAM to build, does take a rather long time on an average machine. The official kernel configuration, as is the case with many GNU/Linux distributions, errs on the side of inclusiveness, and this is really what causes the build to take such a long time when the kernel is built from source. The Linux kernel, however, can also just be described as a regular old package, and as such can be customized just like any other package. The procedure is a little bit different, although this is primarily due to the nature of how the package definition is written. The @code{linux-libre} kernel package definition is actually a procedure which creates a package. @lisp (define* (make-linux-libre version hash supported-systems #:key ;; A function that takes an arch and a variant. ;; See kernel-config for an example. (extra-version #f) (configuration-file #f) (defconfig "defconfig") (extra-options %default-extra-linux-options) (patches (list %boot-logo-patch))) ...) @end lisp The current @code{linux-libre} package is for the 5.1.x series, and is declared like this: @lisp (define-public linux-libre (make-linux-libre %linux-libre-version %linux-libre-hash '("x86_64-linux" "i686-linux" "armhf-linux" "aarch64-linux") #:patches %linux-libre-5.1-patches #:configuration-file kernel-config)) @end lisp Any keys which are not assigned values inherit their default value from the @code{make-linux-libre} definition. When comparing the two snippets above, you may notice that the code comment in the first doesn't actually refer to the @code{#:extra-version} keyword; it is actually for @code{#:configuration-file}. Because of this, it is not actually easy to include a custom kernel configuration from the definition, but don't worry, there are other ways to work with what we do have. There are two ways to create a kernel with a custom kernel configuration. The first is to provide a standard @file{.config} file during the build process by including an actual @file{.config} file as a native input to our custom kernel. The following is a snippet from the custom @code{'configure} phase of the @code{make-linux-libre} package definition: @lisp (let ((build (assoc-ref %standard-phases 'build)) (config (assoc-ref (or native-inputs inputs) "kconfig"))) ;; Use a custom kernel configuration file or a default ;; configuration file. (if config (begin (copy-file config ".config") (chmod ".config" #o666)) (invoke "make" ,defconfig)) @end lisp Below is a sample kernel package. The @code{linux-libre} package is nothing special and can be inherited from and have its fields overridden like any other package: @lisp (define-public linux-libre/E2140 (package (inherit linux-libre) (native-inputs `(("kconfig" ,(local-file "E2140.config")) ,@@(alist-delete "kconfig" (package-native-inputs linux-libre)))))) @end lisp In the same directory as the file defining @code{linux-libre-E2140} is a file named @file{E2140.config}, which is an actual kernel configuration file. The @code{defconfig} keyword of @code{make-linux-libre} is left blank here, so the only kernel configuration in the package is the one which was included in the @code{native-inputs} field. The second way to create a custom kernel is to pass a new value to the @code{extra-options} keyword of the @code{make-linux-libre} procedure. The @code{extra-options} keyword works with another function defined right below it: @lisp (define %default-extra-linux-options `(;; https://lists.gnu.org/archive/html/guix-devel/2014-04/msg00039.html ("CONFIG_DEVPTS_MULTIPLE_INSTANCES" . #t) ;; Modules required for initrd: ("CONFIG_NET_9P" . m) ("CONFIG_NET_9P_VIRTIO" . m) ("CONFIG_VIRTIO_BLK" . m) ("CONFIG_VIRTIO_NET" . m) ("CONFIG_VIRTIO_PCI" . m) ("CONFIG_VIRTIO_BALLOON" . m) ("CONFIG_VIRTIO_MMIO" . m) ("CONFIG_FUSE_FS" . m) ("CONFIG_CIFS" . m) ("CONFIG_9P_FS" . m))) (define (config->string options) (string-join (map (match-lambda ((option . 'm) (string-append option "=m")) ((option . #t) (string-append option "=y")) ((option . #f) (string-append option "=n"))) options) "\n")) @end lisp And in the custom configure script from the `make-linux-libre` package: @lisp ;; Appending works even when the option wasn't in the ;; file. The last one prevails if duplicated. (let ((port (open-file ".config" "a")) (extra-configuration ,(config->string extra-options))) (display extra-configuration port) (close-port port)) (invoke "make" "oldconfig")))) @end lisp So by not providing a configuration-file the @file{.config} starts blank, and then we write into it the collection of flags that we want. Here's another custom kernel: @lisp (define %macbook41-full-config (append %macbook41-config-options %filesystems %efi-support %emulation (@@@@ (gnu packages linux) %default-extra-linux-options))) (define-public linux-libre-macbook41 ;; XXX: Access the internal 'make-linux-libre' procedure, which is ;; private and unexported, and is liable to change in the future. ((@@@@ (gnu packages linux) make-linux-libre) (@@@@ (gnu packages linux) %linux-libre-version) (@@@@ (gnu packages linux) %linux-libre-hash) '("x86_64-linux") #:extra-version "macbook41" #:patches (@@@@ (gnu packages linux) %linux-libre-5.1-patches) #:extra-options %macbook41-config-options)) @end lisp In the above example @code{%filesystems} is a collection of flags enabling different filesystem support, @code{%efi-support} enables EFI support and @code{%emulation} enables a x86_64-linux machine to act in 32-bit mode also. @code{%default-extra-linux-options} are the ones quoted above, which had to be added in since they were replaced in the @code{extra-options} keyword. This all sounds like it should be doable, but how does one even know which modules are required for a particular system? Two places that can be helpful in trying to answer this question is the @uref{https://wiki.gentoo.org/wiki/Handbook:AMD64/Installation/Kernel, Gentoo Handbook} and the @uref{https://www.kernel.org/doc/html/latest/admin-guide/README.html?highlight=localmodconfig, documentation from the kernel itself}. From the kernel documentation, it seems that @code{make localmodconfig} is the command we want. In order to actually run @code{make localmodconfig} we first need to get and unpack the kernel source code: @example shell tar xf $(guix build linux-libre --source) @end example Once inside the directory containing the source code run @code{touch .config} to create an initial, empty @file{.config} to start with. @code{make localmodconfig} works by seeing what you already have in @file{.config} and letting you know what you're missing. If the file is blank then you're missing everything. The next step is to run: @example shell guix environment linux-libre -- make localmodconfig @end example and note the output. Do note that the @file{.config} file is still empty. The output generally contains two types of warnings. The first start with "WARNING" and can actually be ignored in our case. The second read: @example shell module pcspkr did not have configs CONFIG_INPUT_PCSPKR @end example For each of these lines, copy the @code{CONFIG_XXXX_XXXX} portion into the @file{.config} in the directory, and append @code{=m}, so in the end it looks like this: @example shell CONFIG_INPUT_PCSPKR=m CONFIG_VIRTIO=m @end example After copying all the configuration options, run @code{make localmodconfig} again to make sure that you don't have any output starting with "module". After all of these machine specific modules there are a couple more left that are also needed. @code{CONFIG_MODULES} is necessary so that you can build and load modules separately and not have everything built into the kernel. @code{CONFIG_BLK_DEV_SD} is required for reading from hard drives. It is possible that there are other modules which you will need. This post does not aim to be a guide to configuring your own kernel however, so if you do decide to build a custom kernel you'll have to seek out other guides to create a kernel which is just right for your needs. The second way to setup the kernel configuration makes more use of Guix's features and allows you to share configuration segments between different kernels. For example, all machines using EFI to boot have a number of EFI configuration flags that they need. It is likely that all the kernels will share a list of filesystems to support. By using variables it is easier to see at a glance what features are enabled and to make sure you don't have features in one kernel but missing in another. Left undiscussed however, is Guix's initrd and its customization. It is likely that you'll need to modify the initrd on a machine using a custom kernel, since certain modules which are expected to be built may not be available for inclusion into the initrd. @c ********************************************************************* @node Advanced package management @chapter Advanced package management Guix is a functional package manager that offers many features beyond what more traditional package managers can do. To the uninitiated, those features might not have obvious use cases at first. The purpose of this chapter is to demonstrate some advanced package management concepts. @pxref{Package Management,,, guix, GNU Guix Reference Manual} for a complete reference. @menu * Guix Profiles in Practice:: Strategies for multiple profiles and manifests. @end menu @node Guix Profiles in Practice @section Guix Profiles in Practice Guix provides a very useful feature that may be quite foreign to newcomers: @emph{profiles}. They are a way to group package installations together and all users on a same system are free to use as many profiles as they want. Whether you're a developer or not, you may find that multiple profiles bring you great power and flexibility. While they shift the paradigm somewhat compared to @emph{traditional package managers}, they are very convenient to use once you've understood how to set them up. If you are familiar with Python's @samp{virtualenv}, you can think of a profile as a kind of universal @samp{virtualenv} that can hold any kind of software whatsoever, not just Python software. Furthermore, profiles are self-sufficient: they capture all the runtime dependencies which guarantees that all programs within a profile will always work at any point in time. Multiple profiles have many benefits: @itemize @item Clean semantic separation of the various packages a user needs for different contexts. @item Multiple profiles can be made available into the environment either on login or within a dedicated shell. @item Profiles can be loaded on demand. For instance, the user can use multiple shells, each of them running different profiles. @item Isolation: Programs from one profile will not use programs from the other, and they user can even install different versions of the same programs to the two profiles without conflict. @item Deduplication: Profiles share dependencies that happens to be the exact same. This makes multiple profiles storage-efficient. @item Reproducible: when used with declarative manifests, a profile can be fully specified by the Guix commit that was active when it was set up. This means that the exact same profile can be @uref{https://guix.gnu.org/blog/2018/multi-dimensional-transactions-and-rollbacks-oh-my/, set up anywhere, anytime}, with just the commit information. See the section on @ref{Reproducible profiles}. @item Easier upgrades and maintenance: Multiple profiles make it easy to keep package listings at hand and make upgrades completely friction-less. @end itemize Concretely, here follows some typical profiles: @itemize @item The dependencies of a project you are working on. @item Your favourite programming language libraries. @item Laptop-specific programs (like @samp{powertop}) that you don't need on a desktop. @item @TeX{}live (this one can be really useful when you need to install just one package for this one document you've just received over email). @item Games. @end itemize Let's dive in the set up! @node Basic setup with manifests @subsection Basic setup with manifests A Guix profile can be set up @emph{via} a so-called @emph{manifest specification} that looks like this: @lisp (specifications->manifest '("package-1" ;; Version 1.3 of package-2. "package-2@@1.3" ;; The "lib" output of package-3. "package-3:lib" ; ... "package-N")) @end lisp @pxref{Invoking guix package,,, guix, GNU Guix Reference Manual}, for the syntax details. We can create a manifest specification per profile and install them this way: @example GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles mkdir -p "$GUIX_EXTRA_PROFILES"/my-project # if it does not exist yet guix package --manifest=/path/to/guix-my-project-manifest.scm --profile="$GUIX_EXTRA_PROFILES"/my-project/my-project @end example Here we set an arbitrary variable @samp{GUIX_EXTRA_PROFILES} to point to the directory where we will store our profiles in the rest of this article. Placing all your profiles in a single directory, with each profile getting its own sub-directory, is somewhat cleaner. This way, each sub-directory will contain all the symlinks for precisely one profile. Besides, "looping over profiles" becomes obvious from any programming language (e.g. a shell script) by simply looping over the sub-directories of @samp{$GUIX_EXTRA_PROFILES}. Note that it's also possible to loop over the output of @example guix package --list-profiles @end example although you'll probably have to filter out @samp{~/.config/guix/current}. To enable all profiles on login, add this to your @samp{~/.bash_profile} (or similar): @example for i in $GUIX_EXTRA_PROFILES/*; do profile=$i/$(basename "$i") if [ -f "$profile"/etc/profile ]; then GUIX_PROFILE="$profile" . "$GUIX_PROFILE"/etc/profile fi unset profile done @end example Note to Guix System users: the above reflects how your default profile @samp{~/.guix-profile} is activated from @samp{/etc/profile}, that latter being loaded by @samp{~/.bashrc} by default. You can obviously choose to only enable a subset of them: @example for i in "$GUIX_EXTRA_PROFILES"/my-project-1 "$GUIX_EXTRA_PROFILES"/my-project-2; do profile=$i/$(basename "$i") if [ -f "$profile"/etc/profile ]; then GUIX_PROFILE="$profile" . "$GUIX_PROFILE"/etc/profile fi unset profile done @end example When a profile is off, it's straightforward to enable it for an individual shell without "polluting" the rest of the user session: @example GUIX_PROFILE="path/to/my-project" ; . "$GUIX_PROFILE"/etc/profile @end example The key to enabling a profile is to @emph{source} its @samp{etc/profile} file. This file contains shell code that exports the right environment variables necessary to activate the software contained in the profile. It is built automatically by Guix and meant to be sourced. It contains the same variables you would get if you ran: @example guix package --search-paths=prefix --profile=$my_profile" @end example Once again, see (@pxref{Invoking guix package,,, guix, GNU Guix Reference Manual}) for the command line options. To upgrade a profile, simply install the manifest again: @example guix package -m /path/to/guix-my-project-manifest.scm -p "$GUIX_EXTRA_PROFILES"/my-project/my-project @end example To upgrade all profiles, it's easy enough to loop over them. For instance, assuming your manifest specifications are stored in @samp{~/.guix-manifests/guix-$profile-manifest.scm}, with @samp{$profile} being the name of the profile (e.g. "project1"), you could do the following in Bourne shell: @example for profile in "$GUIX_EXTRA_PROFILES"/*; do guix package --profile="$profile" --manifest="$HOME/.guix-manifests/guix-$profile-manifest.scm" done @end example Each profile has its own generations: @example guix package -p "$GUIX_EXTRA_PROFILES"/my-project/my-project --list-generations @end example You can roll-back to any generation of a given profile: @example guix package -p "$GUIX_EXTRA_PROFILES"/my-project/my-project --switch-generations=17 @end example @node Required packages @subsection Required packages Activating a profile essentially boils down to exporting a bunch of environmental variables. This is the role of the @samp{etc/profile} within the profile. @emph{Note: Only the environmental variables of the packages that consume them will be set.} For instance, @samp{MANPATH} won't be set if there is no consumer application for man pages within the profile. So if you need to transparently access man pages once the profile is loaded, you've got two options: @itemize @item Either export the variable manually, e.g. @example export MANPATH=/path/to/profile$@{MANPATH:+:@}$MANPATH" @end example @item Or include @samp{man-db} to the profile manifest. @end itemize The same is true for @samp{INFOPATH} (you can install @samp{info-reader}), @samp{PKG_CONFIG_PATH} (install @samp{pkg-config}), etc. @node Default profile @subsection Default profile What about the default profile that Guix keeps in @samp{~/.guix-profile}? You can assign it the role you want. Typically you would install the manifest of the packages you want to use all the time. Alternatively, you could keep it "manifest-less" for throw-away packages that you would just use for a couple of days. This way makes it convenient to run @example guix install package-foo guix upgrade package-bar @end example without having to specify the path to a profile. @node The benefits of manifests @subsection The benefits of manifests Manifests are a convenient way to keep your package lists around and, say, to synchronize them across multiple machines using a version control system. A common complaint about manifests is that they can be slow to install when they contain large number of packages. This is especially cumbersome when you just want get an upgrade for one package within a big manifest. This is one more reason to use multiple profiles, which happen to be just perfect to break down manifests into multiple sets of semantically connected packages. Using multiple, small profiles provides more flexibility and usability. Manifests come with multiple benefits. In particular, they ease maintenance: @itemize @item When a profile is set up from a manifest, the manifest itself is self-sufficient to keep a "package listing" around and reinstall the profile later or on a different system. For ad-hoc profiles, we would need to generate a manifest specification manually and maintain the package versions for the packages that don't use the default version. @item @code{guix package --upgrade} always tries to update the packages that have propagated inputs, even if there is nothing to do. Guix manifests remove this problem. @item When partially upgrading a profile, conflicts may arise (due to diverging dependencies between the updated and the non-updated packages) and they can be annoying to resolve manually. Manifests remove this problem altogether since all packages are always upgraded at once. @item As mentioned above, manifests allow for reproducible profiles, while the imperative @code{guix install}, @code{guix upgrade}, etc. do not, since they produce different profiles every time even when they hold the same packages. See @uref{https://issues.guix.gnu.org/issue/33285, the related discussion on the matter}. @item Manifest specifications are usable by other @samp{guix} commands. For example, you can run @code{guix weather -m manifest.scm} to see how many substitutes are available, which can help you decide whether you want to try upgrading today or wait a while. Another example: you can run @code{guix pack -m manifest.scm} to create a pack containing all the packages in the manifest (and their transitive references). @item Finally, manifests have a Scheme representation, the @samp{} record type. They can be manipulated in Scheme and passed to the various Guix @uref{https://en.wikipedia.org/wiki/Api, APIs}. @end itemize It's important to understand that while manifests can be used to declare profiles, they are not strictly equivalent: profiles have the side effect that they "pin" packages in the store, which prevents them from being garbage-collected (@pxref{Invoking guix gc,,, guix, GNU Guix Reference Manual}) and ensures that they will still be available at any point in the future. Let's take an example: @enumerate @item We have an environment for hacking on a project for which there isn't a Guix package yet. We build the environment using a manifest, and then run @code{guix environment -m manifest.scm}. So far so good. @item Many weeks pass and we have run a couple of @code{guix pull} in the mean time. Maybe a dependency from our manifest has been updated; or we may have run @code{guix gc} and some packages needed by our manifest have been garbage-collected. @item Eventually, we set to work on that project again, so we run @code{guix environment -m manifest.scm}. But now we have to wait for Guix to build and install stuff! @end enumerate Ideally, we could spare the rebuild time. And indeed we can, all we need is to install the manifest to a profile and use @code{GUIX_PROFILE=/the/profile; . "$GUIX_PROFILE"/etc/profile} as explained above: this guarantees that our hacking environment will be available at all times. @emph{Security warning:} While keeping old profiles around can be convenient, keep in mind that outdated packages may not have received the latest security fixes. @node Reproducible profiles @subsection Reproducible profiles To reproduce a profile bit-for-bit, we need two pieces of information: @itemize @item a manifest, @item a Guix channel specification. @end itemize Indeed, manifests alone might not be enough: different Guix versions (or different channels) can produce different outputs for a given manifest. You can output the Guix channel specification with @samp{guix describe --format=channels}. Save this to a file, say @samp{channel-specs.scm}. On another computer, you can use the channel specification file and the manifest to reproduce the exact same profile: @example GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles GUIX_EXTRA=$HOME/.guix-extra mkdir "$GUIX_EXTRA"/my-project guix pull --channels=channel-specs.scm --profile "$GUIX_EXTRA/my-project/guix" mkdir -p "$GUIX_EXTRA_PROFILES/my-project" "$GUIX_EXTRA"/my-project/guix/bin/guix package --manifest=/path/to/guix-my-project-manifest.scm --profile="$GUIX_EXTRA_PROFILES"/my-project/my-project @end example It's safe to delete the Guix channel profile you've just installed with the channel specification, the project profile does not depend on it. @c ********************************************************************* @node Acknowledgments @chapter Acknowledgments Guix is based on the @uref{https://nixos.org/nix/, Nix package manager}, which was designed and implemented by Eelco Dolstra, with contributions from other people (see the @file{nix/AUTHORS} file in Guix.) Nix pioneered functional package management, and promoted unprecedented features, such as transactional package upgrades and rollbacks, per-user profiles, and referentially transparent build processes. Without this work, Guix would not exist. The Nix-based software distributions, Nixpkgs and NixOS, have also been an inspiration for Guix. GNU@tie{}Guix itself is a collective work with contributions from a number of people. See the @file{AUTHORS} file in Guix for more information on these fine people. The @file{THANKS} file lists people who have helped by reporting bugs, taking care of the infrastructure, providing artwork and themes, making suggestions, and more---thank you! This document includes adapted sections from articles that have previously been published on the Guix blog at @uref{https://guix.gnu.org/blog}. @c ********************************************************************* @node GNU Free Documentation License @appendix GNU Free Documentation License @cindex license, GNU Free Documentation License @include fdl-1.3.texi @c ********************************************************************* @node Concept Index @unnumbered Concept Index @printindex cp @bye @c Local Variables: @c ispell-local-dictionary: "american"; @c End: