This document is supposed to be a guide for packaging GNU Guile software for GNU Guix. The process of packaging depends on the GNU Guile software and its dependencies.
For offering a reproducible experience of running your code can create a GNU Guix environment as described in the following.
mkdir guix-env # in your project root directory pushd guix-env guix describe --format=channels channels.scm popd
The channels.scm
file at guix-env/channels.scm
looks something like the
following:
(list (channel
(name 'guix)
(url "https://git.savannah.gnu.org/git/guix.git")
(commit
"df0447be61
")
(introduction
(make-channel-introduction
"9edb3f66fd
"
(openpgp-fingerprint
"BBB0 2DDF 2CEA F6A8 0D1D E643 A2A0 6DF2 A33A 54FA")))))
It lists the exact commit of the repository at ~https://git.savannah.gnu.org/git/guix.git~, which the environment is based on. Unless someone retroactively changes the specified commit, which is best practice not to ever do, this makes sure, that the packages your project depends on will be exactly the same, every time you use the GNU Guix environment.
Once you have this, add the following GNU Bash script at ~guix-env/env.sh~:
#!/usr/bin/env bash
set -Eeuxo pipefail
DIR=$(dirname "$(readlink -f "${0}")")
guix time-machine \ --channels="${DIR}/channels.scm" -- \ environment \ --manifest="${DIR}/manifest.scm"
Here we are making use of the time-machine
facility of GNU Guix, which allows
us to specify a channels file, which contains the reference to the exact commit
of the GNU Guix repository. Using that commit, we further make use of the
~environment~ facility, which allows us to install dependencies specified inside
manifest file.
There are even more strict ways to create an environment, which also exclude environment variables set in the current shell, but for now we will leave it at this.
Next create a manifest.scm
file at guix-env/manifest.scm
, which specifies
GNU Guix packages, which your project depends on. It looks something like the
following example:
(specifications->manifest '("guile" "guile-hall"))
In this example case the GNU Guile project requires:
guile
, which is GNU Guile, currently in version 3.x.yguile-hall
, which helps with packaging GNU Guile projects -- Only includeThe manifest.scm
file in this case contains runtime and development
dependencies. Note, that we do not need to specify versions in this file, as
they are already indirectly specified by specifying the GNU Guix commit inside
the channels.scm
file.
If we ever want to update our GNU Guix environment, to work with newer package versions, we can update our GNU Guix profile as follows:
guix pull && guix package -u
This will bring the GNU Guix profile to the current commit of the original GNU Guix repository.
Then we can run the describe
command again:
guix describe --format=channels guix-env/channels.scm
This will write the new commit id into the channels.scm
file. Then we must
test our new GNU Guix environment by trying to activate it using:
guix time-machine \ --channels="guix-env/channels.scm" -- \ environment \ --manifest="guix-env/manifest.scm"
It could happen, that packages from our manifest.scm
file are no longer
available on a newer GNU Guix commit and that the environment creation
fails. Therefore it is important to run this test before committing the new
environment files to version control.
Finally you will be able to use the environment, which was prepared here by running the following command:
bash guix-env/env.sh
This will drop you into a new shell, which has the packages specified in ~manifest.scm~ installed.
"Why make a project specific environment, and not install the packages into the default profile?" you may ask. The reasons are the following:
This guide walks the reader through creating a GNU Guix package from a not yet packaged GNU Guile project using the tool guile-hall. Follow the steps in the guide from top to bottom to create a package. For a short refresh of what needs to be done to create a package, the TLDR section could be helpful.
guile-hall is specified inside the manifest.scm
file. After activating the
environment specified in guix-env
, the hall
command should be available.
guile-hall works in 2 modes. One is creating a new hall project, to which one then adds more and more files, developing the actual project. Such a project should be a valid GNU Guix package. The second mode is to convert an existing project into a hall project, making it a valid GNU Guix package.
This guide will focus on converting an existing project into a GNU Guix package using hall.
The next step is to actually run hall
as follows:
hall init \ --convert \ --author 'AUTHOR NAME' \ --prefix 'guile' \ --license='LICENSE_NAME' \ 'PROJECT_NAME' \ --execute
With this we tell hall to do the following things:
--license~: Tell hall to use the specified license to create the ~COPYING
guile-hall will create the following files:
Note: If your project used a different file for the license, for example
LICENSE
, it is advisable to change this and use the COPYING
file from now
on, because hall will generate the license in COPYING
, when running some
commands, when it does not find the license there and will also use the
COPYING
file for building the distribution tarball.
README~: Merely a symlink to ~README.org
.scripts
directory and files therein: In this directory hall organizesIf the project does not have need for such a command line interface, for
example in case of a GNU Guile library, which will only be used inside other
GNU Guile programs, then this directory is not needed and can be removed. If
removed, hall.scm
should be adapted correspondingly by changing the
programs
category of the files
attribute. HACKING
might need to be
adapted as well, to avoid having misleading information in it.
guix.scm~: See [[#using-guile-hall-guix-package-file-guix-scm][Guix package file ~guix.scm
]]guix.scm
This file contains the actual specification of your GNU Guix package. It contains information about:
propagated-inputs
See the package reference of GNU Guix for anMore information about the attributes can be found in the package reference of GNU Guix.
hall.scm
In this section, we take a closer look at what we find inside hall.scm
. With
this knowledge it should be possible to edit the hall.scm
file by hand, if
that is needed.
There are some attributes, which we have already seen in guix.scm
like name~
and ~prefix
, although now separately, version
, synopsis
, description
,
~home-page~ and license
. We will look at the other attributes.
All attributes are under a top level expression ~hall-description~:
There is a definition files
inside hall.scm
for all source code files of a
project. files
contains a multi-element nested definition of the files and
directories of the project. Some of the nested definitions can be scheme-file
,
~directory~, org-file
, symlink
, text-file
and probably others (TODO: Where
to find a list of all supported file types?). The files are sorted into separate
categories.
The actual files are then specified using either directory
as a container, or
one of the supported file types.
scheme-file
for example, like the other *-file
specifications, expects adirectory
expects a string as argument, which is the directory name, and* Libraries
Indicated by libraries
. Contains Scheme a nested list of files and directories
indicated by scheme-file
or directory
and recursively their files or
directories.
* Tests
Indicated by tests
. Contains a nested list of directories and files, which
contain tests.
hall will assume, that the tests are in the subdirectory tests
. If the tests
are not in that directory, the attribute needs to be changed accordingly.
* Programs
Indicated by programs
.
TODO: What are programs in this context?
* Documentation
Indicated by documentation
. Contains a nested list of the files or
directories, which contain the documentation of the package.
The following files and directories go here:
HACKING
COPYING
AUTHORS
doc
directorytexi
files of the documentation* Infrastructure
Indicated by infrastructure
. This category contains the following kinds of
files:
guix.scm
.git
.hall.scm
.Here is an example for a hall.scm
file:
(hall-description (name "fslib") (prefix "guile") (version "0.2.0") (author "Zelphir Kaltstahl") (copyright (2021)) (synopsis "file system utils for GNU Guile") (description "This library provides procedures for working with GNU/Linux file systems from GNU Guile.") (home-page "https://notabug.org/ZelphirKaltstahl/guile-fslib") (license agpl3+) (dependencies `()) (files (libraries ((scheme-file "fslib") (scheme-file "logging") (scheme-file "list-utils") (scheme-file "file-system") (scheme-file "file-reader") (scheme-file "string-utils"))) (tests ((directory "test" ;; hall automatically knows to add .scm to scheme files ((scheme-file "test-string-utils") (scheme-file "test-list-utils") (scheme-file "test-fslib"))))) (programs ()) (documentation ((org-file "todo") (org-file "README") (symlink "README" "README.org") (text-file "HACKING") (text-file "COPYING") (text-file "AUTHORS") (directory "doc" ((texi-file "fslib"))))) (infrastructure ((scheme-file "guix") (text-file ".gitignore") (scheme-file "hall")))))
hall generated some documentation in HACKING
and inside the doc
folder. They
should be adapted to the individual project.
hall also generated a script in the scripts
folder, which might not be
needed. For example if the project that is being packaged is a library, then it
does not need to have an executable script in the distributed tarball. If the
project does not need scripts like that, the scripts
folder can be removed and
removed from the hall.scm
. There are also parts inside the HACKING
file,
which should be adapted, in case the scripts
directory and its contents are
not needed.
hall by default specifies version "0.1"
for the version
attribute in
~guix.scm~ and in hall.scm
, as it would for a new and not converted
project. However, if we are converting a project, this version specification
might not be correct. It should be adapted to the correct version.
With the version
attribute being updated, we also need to change the source~
in ~guix.scm
attribute, to point to the correct distribution tarball filename.
Depending on the projects original structure, the location of tests, which is
specified in hall.scm
needs to be changed to the correct directory.
hall might not have added all GNU Guile files of the project automatically in
~hall.scm~. It depends on where the files are. hall seems to find all files in
the subdirectory which goes by the project name. However, if the files are on
the top level of the project, hall will not pick up those files. In such cases,
when hall does not pick up the files, they need to be added to hall.scm~
manually. See the ~hall.scm
example above.
The usual way to add files to hall.scm
, the configuration file hall makes use
of, is to run a scan for not yet added files as follows:
hall scan
Check, whether the dry run output contains the modifications you wish and, if that is the case, run it with ~--execute~:
hall scan --execute
Only if hall scan
does not what you want it to do, you need to edit ~hall.scm~
manually.
The hall scan
utility is useful, because we do not need to manually arrange
the file structure in hall.scm
, even, if the structure of source code files
inside the directory named after the project changes a lot. At the same time it
is useful, that hall.scm
is designed to be human-readable and human-editable.
Before building the distribution tarball, check critical things like the following:
hall.scm
contains all relevant GNU Guile files?Fix any mistakes you find.
hall created the guix.scm
file.
TODO: How does loading the guix.scm
file influence the guix environment, which
is activated? What does it add?
The guix.scm
file needs to be loaded inside a GNU Guix environment. To make
sure, that a clean environment is used, activate a new environment by running:
guix environment --load='guix.scm'
Clean the directory of old files that may be around from previous
Then create the distribution by running the following command in the new shell:
hall dist --execute autoreconf --verbose --install --force sh configure make dist
After creating a distribution, it should be tested.
Inside a GNU Guix environment try installing it using:
guix package --install-from-file='guix.scm'
If it succeeds, the package should be listed in the output of:
guix package --list-installed
The cleanup step is only needed, if there happen to be artifacts from previous packaging. This can for example be the case, when you are publishing a new version of your project, after already having packaged it before.
The cleanup step of hall will remove all files, which are not specified in ~hall.scm~. It is a possibly destructive action and one should use the dry run functionality of hall to ensure, that it is only performing the intended actions:
hall clean
If you notice it listing any files up for deletion, which you need and which
should be part of the project, you should add them to hall.scm
, rerun the dry
run and check again. Do this until the actions announced by the dry run fit what
you intend and then execute the cleanup step:
hall clean --execute
The clean command will only delete things, which are not specified in your
~hall.scm~ file. If you specified files in hall.scm
generated by hall during
previous packaging, for example a Makefile.am
or a configure
, sometimes it
can lead to problems, when trying to make a distribution. This is the case, if
those specified files contain obsolete information, such as a wrong file name of
a license file. Make sure to use fresh files when appropriate. Keeping files
like Makefile.am
or configure
might make sense, when the structure of the
project does not change, as they enable people without hall installed to build
the project and then install it in their GNU Guix environment.
In short you need to do the following:
hall init
as described in RunningFor pure GNU Guile packages, it should be possible to follow the guide at https://guix.gnu.org/cookbook/en/guix-cookbook.html. The following tries to elaborate a bit on the involved steps.
The example for the hello package makes use of the gnu-build-system
. However,
the gnu-build-system
adds an unnecessary amount of complexity to the packaging
process, such as probably having to use guile-hall
, to create the required
files and creating more points in the process, where things can go wrong or
simply fail. For pure GNU Guile projects it is therefore easier to use the
~guile-build-system~ instead.
When using the guile-build-system
, the method
to fetch the sources of a
package is git-fetch
, instead of url-fetch
.
For ways of calculating the hashsum see Calculate project hashsums.
The adapted example for guile-fslib
using guile-build-system
looks as follows:
(use-modules (guix packages) (guix download) (guix git-download) (guix build-system gnu) (guix build-system guile) (gnu packages guile) ((guix licenses) #:prefix license:))
(define-public guile-fslib (package (name "guile-fslib") (version "0.2.0") (source (origin (method git-fetch) (uri (git-reference (url "https://notabug.org/ZelphirKaltstahl/guile-fslib/") (commit version))) (file-name (git-file-name name version)) (sha256 (base32 "118d84p443w7hrslv8hjyhgws631ia08mggiyklkmk0b9plfdsvz")))) (build-system guile-build-system) (inputs `(("guile" ,guile-3.0))) (home-page "https://notabug.org/ZelphirKaltstahl/guile-fslib") (synopsis "File system utilities") (description "This package contains like super cool file system utilities and stuff. It's really good and so easy to install!") (license license:agpl3+)))
guile-fslib