Introduction to Guix Specifications

EDIT 2023-10-17: Package specifications in Scheme cannot have versions. IRC Logs

Guix has a notion of a package specification, and it is what Guix defaults to in many cases. From my understanding the reason Guix defaults to using specifications in automatically-generated places is because they are easier to programmatically handle. Using specifications means raw variables are not used, which could be renamed later. It also means that no modules need to be imported, as Guix looks up the packages at run-time.

This post is meant as an introduction to Guix's use of package specifications, and not a comprehensive block of documentation. If something is missing from here or you simply wish to read more, please see the manual. If you need to get cooking with specifications quickly, the cookbook is a good resource.

Package Specifications

Package specifications area convenient way to name packages with specific properties. For example, the libgccjit package has multiple versions defined and multiple outputs.

A package output is a way to split up the resulting files for distribution. This is typically done for particularly large packages or for ones that have somewhat independent output components. For example, libgccjit 12.3.0's out output is 279.4MiB, but its debug output is 669.0 MiB.

Specifications support two modifiers, the version to use and the package output to select. You must always provide the package's name, which can be found with guix search or by reading Guix's package definition's name field.

NOTE: A package's name does not have to correspond to its variable/symbol name.

So a fully-specified package is written:

package-name@version:output

NOTE: You must follow this ordering! The following will produce an error:

guix shell package-name:output@version # error: package `package-name@<default-version>' lacks output `output@version'

The reason this happens is because the Guix procedure which parses specifications will misunderstand your specification request. Typed incorrectly, it believes "output@version" is an output of the default package, which it certainly will not be.

However, you are not forced to always specify everything. You can do something like below:

package-name@version
package-name:output

You are more likely to use the package-name@version variant than package-name:output, as what you want is usually in the default out output.

An Example

If you ask Guix to give you libgccjit, Guix will give you the default libgccjit version's out (the default) output.

guix shell libgccjit

On Guix commit 1328c4c, libgccjit defaults to 12.3.0. This may (will probably) be different for different versions of Guix.

libgccjit is both the name of the package and the symbol that refers to the package. On the command-line (and almost everywhere else a specification is used), the package's name is what is used.

If we wanted, we could have manually asked for any other version Guix currently (1328c4c) supports.

guix shell libgccjit@10.4.0

This will put you in a shell where libgccjit 10.4.0 is available.

You want libgccjit's debug information for the currently-default libgccjit version?

guix shell libgccjit:debug

Guix strips debug information by default, as a majority of users and uses of a program do not require the debugging information, which consumes a significant amount of space.

But say you wanted the debug information for libgccjit 10.4.0, what would you type?

guix shell libgccjit@10.4.0:debug

Like stated previously, building the specification in the wrong order will produce an error.

guix shell libgccjit:debug@10.4.0 # guix shell: error: package `libgccjit@12.3.0' lacks output `debug@10.4.0'

With that, we have covered all possible ways to use a specification. The next section discusses how to use specifications on both the command-line (like I was just showing) and from within Scheme.

Using Specifications

All of the example above showed how to use specifications on the command-line, but that was only with guix shell. Extra information about using specifications on the command-line with other commands Guix has for packages are in the next section. Then we move on to discussing how to use specifications in Scheme.

On the Command Line

All of the examples from the previous section used the guix shell command, which allows you to use the full specification syntax on the command-line. However, not all commands support all of the specification options!

In particular, guix build only allows version numbers! This works:

guix build libgccjit@10.4.0

But this fails:

guix build libgccjit@10.4.0:debug # guix build: error: libgccjit: package not found for version 10.4.0:debug

This makes sense as guix build builds a package, which necessarily means all outputs need to be built.

As far as I can tell, all other package-operating commands allow the use of the full specification syntax. This includes:

In Scheme

If you want to use an exact specification in Scheme, replace the bare package's variable/symbol name with a list.

;; libgccjit:debug instead of the default
(list libgccjit "debug")

NOTE: You can only specify an output, not a version, and not the full specification.

In Scheme, you can replace a package with its list-specification anywhere a package is expected. As an example, let us assume there is a package named example that uses the default libgccjit version Guix sets that we want to replace the default output with the debug one.

(use-modules (gnu packages)
             (gnu packages gcc))

(package
 (name "example")
 ... ;; Unnecessary fields omitted
 ;; Commented-out portion below is the original definition
 ;; (native-inputs
 ;;  (list libgccjit))
 (native-inputs
  ;; libgccjit here is the SYMBOL for the package, NOT the package's name.
  ;; This is the only way a package's name is not used for a specification.
  (list (list libgccjit "debug"))))

As stated earlier, this replacement can be done anywhere a package is expected. That includes:

You can also provide the specification as a string, if you use the specification->package procedure. This procedure returns the specification's corresponding package object. This behaves the exact same way as on the command-line (in fact, the command-line tools use this exact procedure).

A common example you will see is creating a manifest out of specifications, which automates the process of going from specification to package to manifest.

(use-modules (gnu packages)) ;; To access specifications->manifest

;; Manifest with default libgccjit and debug information for libgccjit 10.4.0
(specifications->manifest
 ;; libgccjit here is the NAME of the package, NOT the symbol!
 (list "libgccjit@10.4.0:debug"
       "libgccjit"))

Reproducibility

As always, reproducibility is cornerstone of Guix. To make any Guix package specification reproducible, you need to know the Guix commit to use. This can be done with the guix describe command to lock the commits and guix time-machine to use those commits.

guix describe --format=channels > channels-lock.scm

I do not discuss guix describe or guix time-machine much here because this post is about specifications. Another post will be coming out soon about some Guix commands, or you can read the manual pages about guix describe and guix time-machine.


Conclusion

Guix uses a custom specification syntax to make specific package selection easier. The complete and correct syntax is:

package-name@version:output

Almost all package-operating commands in Guix accept the full syntax. The exception is guix build, which does not accept an output selection. Specifications are effectively packages, and as such, they can be used anywhere Guix expects a package object, in both Scheme and on the command-line; so long as the specification somehow corresponds to a package object. Finally, specifications can be made reproducible by locking the channels with guix describe and guix time-machine. This concise syntax makes working with Guix from the command-line simpler to read and type, and makes selecting the right thing easier.

I hope this post helped explain package specifications, as much of this was collected by testing, experience, and trawling the documentation. As always, please refer to the manual for complete documentation.