When it's not, there's still a possibility that a search will reveal somebody else has packaged what I want. For example, I share packages that I'm testing before I submit them upstream. Downloading a package definition to test it out on your machine is easy, but there are some tricks. It took me a while to figure out what to do, and I see other people get confused regularly due to unfortunate decisions in Guix's design. So here's a guide to get you on the right path.
First, a warning
Guix packages look a lot like data, since they mostly consist of URLs and descriptions and so on. But don't be fooled! Packages are code, and building a package runs arbitrary code on your computer. A malicious package can do dastardly things. So don't run packages from people you don't trust unless you've inspected them yourself and gain some understanding of what they're doing.
The Guile load path
Guix discovers what packages exist by loading all the Guile code on its
guile-load-path and collecting package definitions. That means you can add new packages just by adding files that define them to your Guix load path.
Here's an example using my repository:
git clone https://github.com/ryanprior/guix-packages.git cd guix-packages guix environment -L. --ad-hoc countdown -- countdown 10s
To break it down:
Cloning a repository
People often put Guix packages in a git repository. Cloning the whole repository is often the most convenient way to get access to those packages. Sometimes one file will refer to things defined in another, and by getting the whole repository you have a better chance to make sure you have everything that's needed, with the right directory structure.
If you don't have Git installed yet, run
guix install git before you start.
guix environment with the -L flag
guix environment command creates a subshell with new Guix packages added to its environment, without making any changes to your profile. This makes it great for trying things out.
With each use of the
-L flag, Guix will add an additional path to its Guile load path, allowing it to find more packages. So invoking
-L. instructs Guix to look in the current directory (called
.) for packages.
Everything after the
-- in the command is run inside the subshell. So when we put together the pieces, the command looks in all of Guix plus the current directory for a package called "countdown," adds it to the environment of a subshell, runs "countdown 10s" inside that subshell, and exits. If you want to interact with the subshell directly, you can omit the
-- countdown 10s portion entirely:
~/guix-packages$ countdown countdown: command not found ~/guix-packages$ guix environment -L. --ad-hoc countdown ~/guix-packages$ type countdown countdown is /gnu/store/w0gy4d14b2byir64jakpsrw3j73n916a-profile/bin/countdown ~/guix-packages$ exit ~/guix-packages$ type countdown bash: type: countdown: not found
This method is very sensitive to the current working directory, which is the directory you run the
guix command from. For example, if I run the same
guix environment command above inside the
guix-packages/testing directory, I get a ton of warnings and then an error message:
# […lots of warnings] guix environment: warning: failed to load '(vlang)': no code for module (vlang) ./vlang.scm:4:0: warning: module name (testing vlang) does not match file name 'vlang.scm' hint: File `./vlang.scm' should probably start with: (define-module (vlang)) guix environment: error: countdown: unknown package
If you run
guix environment in the parent directory of
guix-packages, it will first of all take ages as it tries to search every subdirectory for Scheme files, and then it will also print an error and not give you what you want.
Ugh! There's no way to make this work other than to ensure and triple-check you're in the exact right directory. If you're troubleshooting, you can try a few different directories and see if you hit on the right one. You can also look at the
module definition for clues. For example, at the top of
testing/countdown.scm we see:
(define-module (testing countdown) ;; snip )
The clue this gives you is that this file expects to be found at
./testing/countdown.scm, and thus it expects you to run Guix with a Guile load path that has not its directory, but that directory's parent.
If you have a single file that defines a package of interest, you can use the
-f flag to refer to the package it evaluates to. But you have to take care that the file actually evaluates to the desired package and doesn't merely define it.
For example, in my
guix-packages repository, the
countdown.scm file has a structure like this:
(define-module (testing countdown) …) (define-public countdown (package (name "countdown") …))
What's important to note is that the last form of the file is a
(define-public) form, which does not have any return value. A file evaluates to the return value of its last form, so while this file defines the
countdown package, it evaluates to nothing. So if you run
guix build -f countdown.scm it will give you an error message like so:
~/guix-packages/testing$ guix build -f countdown.scm guix build: error: #
: not something we can build hint: If you build from a file, make sure the last Scheme expression returns a package value. `define-public' defines a variable, but returns `# '. To fix this, add a Scheme expression at the end of the file that consists only of the package's variable name you defined, as in this example: (define-public my-package (package ...)) my-package
If you edit
countdown.scm to put a new line at the end that just says
countdown, then Guix will build the package:
~/dev/guix-packages/testing$ cat >>countdown.scm countdown ~/dev/guix-packages/testing$ guix build -f countdown.scm /gnu/store/6x2lmakp59vzdjbjqxha2560g2jrqdyv-countdown-1.0.0
countdown executable is available in the listed directory, and we can start a 10 second countdown like so:
~/dev/guix-packages/testing$ /gnu/store/6x2lmakp59vzdjbjqxha2560g2jrqdyv-countdown-1.0.0/bin/countdown 10s
What if I want
guix environment! But Guix does not provide us any easy way to use a file with
-f flag that is available on many other commands is not defined for
environment. However, with another silly workaround we can make this work.
Instead of putting a line with
countdown at the end of
countdown.scm, we can make it evaluate to a trivial wrapper around
;; …rest of countdown.scm (package (inherit countdown) (inputs `(("countdown" ,countdown))))
Now we can use
guix environment again:
~/guix-packages/testing$ guix environment -l countdown.scm ~/guix-packages/testing$ type countdown countdown is /gnu/store/4gc33v065h1hm0lq42j1fir7gs151j9s-profile/bin/countdown
Note that we are using
-l (lower case L) and not the
-L flag we were using before. This does not modify the Guile load path. Instead of creating an environment containing the package the file evaluates to, it creates an environment with the dependencies of that package. This is why we have to create that trivial wrapper which adds countdown as a dependency.
Note that while this method is fiddly in many ways, it is not so dependent as the last one on having everything in exactly the right directory structure and being in the exact right directory when you run your Guix command.
Epilogue: any easy, worry-free way to try people's Guix packages?
The currently available methods for testing a Guix package you find on the Internet are fraught with thorns and pitfalls for the unwary. This can give an overall unfriendly feeling to newcomers.
Suppose we were to come upon a clearing in the thicket where some hackers were having a merry potluck, where everybody brought their packages to try and there was a friendly uniform mechanism to try and share these packages?
Such a tool was proposed: Guix Potluck was submitted in 2017 to address this kind of use case. It never got a public release, but there may be lessons there for a hypothetical future tool that could make guides like this one obsolete.