Introduction
Guile Load Path is a place (or more precisely places), where Guile looks for the source code. This is the first thing one needs to set correctly to work on a Guile Scheme project. It makes Guile aware both of your own modules and external dependencies. For more details refer to Load Paths page in Guile Reference Manual. This guide will focus on getting and setting the right values for it and discussing different approaches to do so.
Getting The Load Paths
The current value of all load paths for the current guile process is
stored in %load-path variable, so it's easy to obtain it in runtime
using CLI, REPL or your IDE.
To see what value it has you can just pretty print the variable.
> guile -c '((@ (ice-9 pretty-print) pretty-print) %load-path)'
("/home/bob/.guix-home/profile/share/guile/site/3.0"
"/run/current-system/profile/share/guile/site/3.0"
"/gnu/store/37m0a0ydy74wl2qrf2w1jdgqhxwbaxac-guile-3.0.9/share/guile/3.0"
…)By default with a clean Guile installation you should see only the
directory which contains Guile's own source code. In more real-world
scenarios, for example, in Guix System, I see two combined directories
containing my system's and home's guile packages respectively, the
directory with guile's sources and a few bogus entries, which I have
truncated with ellipsis (…).
> echo $GUILE_LOAD_PATH
/home/bob/.guix-home/profile/share/guile/site/3.0:/run/current-system/profile/share/guile/site/3.0The first two directories comes from the environment variable
$GUILE_LOAD_PATH. The rest are baked into guile distribution.
Getting a Clean Environment
To get a clean environment you can unset $GUILE_LOAD_PATH variable
(to ensure there are no dependencies added to the project
accidentally). You can also construct a pure environment with guix shell --pure guile, which has similiar effect, but for the sake of
clarity we will unset the variable manually.
> unset GUILE_LOAD_PATH
> guile -c '((@ (ice-9 format) format) #t "~y" %load-path)'
("/gnu/store/37m0a0ydy74wl2qrf2w1jdgqhxwbaxac-guile-3.0.9/share/guile/3.0"
…)The guile's libraries directory is still present in load paths. It is
hardcoded in the guile binary and not affected by GUILE_LOAD_PATH.
Setting GUILE_LOAD_PATH
Now, let's assume there is a project module (myproj core) in
./tmp/guile/myproj/core.scm' (usually it is src instead of tmp,
but we provide examples, which are easy to clean up by invoking rm ./tmp -r).
> mkdir -p tmp/guile/myproj \
echo "(define-module (myproj core))" > tmp/guile/myproj/core.scm \
echo "(define-public (main) (display 'hi))" >> tmp/guile/myproj/core.scmTrying to run guile -c '(begin (use-modules (myproj core)) (main))'
leads to no code for module (myproj core) because this module is not
on the load path yet. To fix this, you have to add tmp/guile to the
load path. Pay attention that we add tmp/guile and not tmp or
tmp/guile/proj. The module (myproj core) have to be in
myproj/core.scm file, which must be located in the root of a load
path, if this convention violated the module won't be found. Let's
temporary set GUILE_LOAD_PATH for the next invocation of guile.
> GUILE_LOAD_PATH="./tmp/guile" \
guile -c '(begin (use-modules (myproj core)) (main))'
hiVoila, we got a message printed by the main function.
The Order Matters
It's possible to have a few directories by separating them with colon.
> GUILE_LOAD_PATH="./test/guile:./tmp/guile" \
guile -c '((@ (ice-9 pretty-print) pretty-print) %load-path)'
("./test/guile"
"./tmp/guile"
"/gnu/store/37m0a0ydy74wl2qrf2w1jdgqhxwbaxac-guile-3.0.9/share/guile/3.0"
…)The order matters: if there are two modules with the same name on the load paths, the first one encountered will be used.
Also, there is a special three dots value (...) you can use when
setting GUILE_LOAD_PATH. It will get expanded to the path of
guile's own libraries. This is useful if you want to make sure your
library doesn't override any built-ins. Keep in mind that this three
dots is distinct from the ellipsis I have added when truncating the
output of the guile command for this blog post.
> GUILE_LOAD_PATH="./tmp/guile:...:./my-srfis" \
guile -c '((@ (ice-9 pretty-print) pretty-print) %load-path)'
("./tmp/guile"
"/gnu/store/37m0a0ydy74wl2qrf2w1jdgqhxwbaxac-guile-3.0.9/share/guile/3.0"
…
"./my-srfis")Adding to GUILE_LOAD_PATH
Sometimes the GUILE_LOAD_PATH is already provided and set and you
want to extend its value. It doesn't really matter if it comes from
guix shell, set by the script of your colleague or whatever. For
demonstration purposes, we will set it manually in our shell.
> export GUILE_LOAD_PATH="./path/set/by/someone-else"Almost always, you want to prepend the directories you need to the existing value.
> GUILE_LOAD_PATH="./dev/guile:./test/guile:${GUILE_LOAD_PATH}" \
guile -c '((@ (ice-9 pretty-print) pretty-print) %load-path)'
("./dev/guile"
"./test/guile"
"./path/set/by/someone-else"
"/gnu/store/37m0a0ydy74wl2qrf2w1jdgqhxwbaxac-guile-3.0.9/share/guile/3.0"
…)Pay attention that we set a variable only for the next invocation of guile. We do not mutate the variable value, and if we run this code a few times we won't see the duplicated values in the load paths.
To append to the existing GUILE_LOAD_PATH or order the directories
anyhow else, just move ${GUILE_LOAD_PATH} accordingly.
In addition to GUILE_LOAD_PATH, there are at least two more ways to
adjust load paths: via CLI and API. It's good to be aware of where
else load path values can come from, especially when you work on
someone else's project.
Modifying via CLI
For most cases GUILE_LOAD_PATH is enough and should be used, but
sometimes it may be tricky or inconvenient to set environment
variables. The guile command line program has the -L flag, which
allows for prepending a directory to the load paths.
> guile -L ./dev/guile -L ./test/guile -c '((@ (ice-9 pretty-print) pretty-print) %load-path)'
("./dev/guile"
"./test/guile"
"./path/set/by/someone-else"
"/gnu/store/37m0a0ydy74wl2qrf2w1jdgqhxwbaxac-guile-3.0.9/share/guile/3.0"
…)This is a complete equivalent to the example from the previous section. The order of added directories still matters.
Modifying via API
So far, we have used %load-path to get the value of load paths, but
we can also use it to set load paths with set!.
We do not recommend setting load paths dynamically (in runtime) via
API. All load paths should be known before the guile process is
started and thus they should be set via GUILE_LOAD_PATH, but if you
are really sure you want to, there are a couple of things to know.
%load-path must be modified before the expression is evaluated.
That means if you need to set load paths in the same expression you
want to use the new value it should be wrapped into (eval-when (expand)). See
Eval-when
for more details.
> guile -c '(begin (eval-when (expand) (set! %load-path (list "tmp/guile")))
(use-modules (myproj core)) (main))'Don't forget to preserve the necessary values of the %load-path,
otherwise things can break, such as goto definition, loading modules,
etc.
(set! %load-path (cons "new/dir" %load-path))There is a convenience wrapper macro, which does both of those things:
add-to-load-path, but we hope you will never need any info from this
section.
Clean Up
To wrap up all the things:
- Do
rm -r ./tmpto clean up all the tails. - Thank authors of this guide.
Acknowledgments
Edited by Joseph Turner.