Parameterized Packages: The Project Completion Update

September 18, 2023 • Sarthak Shah

This post is a small completion update for my GSoC project on adding Parameterized Packages to GNU Guix. You can find the source code for the same on the main notabug repository or on the github mirror. This post is broken into two parts; the first is a simple overview of the uses of parameters and the second answers some commonly asked questions.

What is Package Parameterization?

In its current state, Package Parameterization makes it possible to add compile-time options to any Guix package, regardless of whether it was defined with support for a given compile-time option or not. This makes it a very powerful tool for hackers seeking to extend their packages in unorthodox and interesting ways. But that's not all! Parameters can be used to make any kind of changes to package definitions conditionally, making them very useful substitutes for unimplemented package transformation options in a lot of cases.

What are compile-time options?

Compile-time options are package features that can be selected only when a package is being compiled from source. Most binary-based GNU/Linux distributions pick these options for the users, often selecting options that the user might not need while leaving out some options that they might really need. These become especially relevant in the context of High-Performance Computing and computing on alternate ISAs, where greater flexibility with compile-time options is greatly needed.

What makes Package Parameterization special?

The strength of package parameterization lies in the fact that users will now be able to create generic compile-time options that they will be able to apply to any number of packages they like. It's almost akin to being able to create custom package transformation options, with the caveat that only an enumerated set of options will be available for choosing.

Generic Compile-time Options

The compile-time options created by parameters will be generic if the author chooses to write a global parameter for a given parameterization. This means that if, for example, I write a global parameter that enables text-to-speech support, it will work on any package that satisfies this parameter's predicate. The predicate is a user-defined function that returns #t or #f after checking a number of things about the package passed to it like the package's build system, inputs or arguments among other things. This helps prevent the usage of parameters on packages that they are not compatible with.

What does this look like in action?

I have demonstrated this in great detail in this post, for a quick example please head to the section where I've parameterized a bunch of variants of Emacs ("What does using parameters look like?"). All of the examples in the post work and you can try them out by applying the parameterization patch to a local copy of Guix.

Reasons for trying Package Parameters

In no particular order, here are some good reasons why you should try using Package Parameters

1. Speeding up packages that you use very often

To maintain stability and ensure that packages work across a wide variety of devices, Guix usually does not build packages with a lot of compile-time speed optimizations. However, with parameterization it is possible to speed up packages that you use very often for a much smoother and faster computing experience.

2. Easily creating and accessing multiple variants for packages

Parameters make it easy to succinctly write packages with multiple variants and switch between them with the --with-parameter transform. It is also possible to take an existing package and add a number of variants to it, like in the Emacs example mentioned in the previous heading.

3. Applying compile-time customizations to a number of packages

Using global parameters, it's possible to have common parameterized options across a huge number of packages. This makes it easy to use parameterized variants of packages without having to rewrite each of them with the compile-time option you want to use.

4. Learning more about your packages

This last reason is a bit opinionated, but I think that you get to learn a lot more about how the packages you're using work when you tweak them like this. It makes you mindful of all the packages that you are using, and sometimes even helps you discover new things about them that you otherwise wouldn't know about!

Answers to some commonly asked questions

Changes in the Syntax

The main point of confusion so far has been the syntax for package parameterization, which has gone through a couple of changes over time.

The Parameter List

The parameter list is a fundamental component of this project. At any place that accepts a list of parameters, the user passes a parameter list. Parameter lists are lists of the form ((parameter value) (parameter-2 value-2) ...) The first value in the cell is the symbol of the parameter, and the second value in the cell is the value of the parameter.

Negation and !

Previously, we were using ! to denote the negation of a parameter. This has been removed in newer versions. The rationale behind this removal is that ! does not clearly denote negation, and having arbitrary restrictions behind what kind of symbols are allowed and what kind are not would again cause confusion. Instead, we now use #:off to denote the negative value for any given parameter.

;; old style
(parameter-if ((a val) b!)
    do-thing)

;; new style
(parameter-if ((a val) (b #:off))
    do-thing)

Handling of Global Parameters

This topic is still under debate, but for now I have opted to use a separate namespace for global parameters. I'm accomplishing this with the help of a global hash-table. This is for two main reasons:

  1. We can guarantee that global parameters are unique by adding checks for uniqueness in the global parameter definition macro
  2. Parameter names can stay small inside the various parameter lists in the parameter-spec

Furthermore, a lot of the existing processing functions work on unique symbols denoting the parameters and not the parameters themselves, so a massive rewrite would be necessary if we want to pass them parameters instead.

Support for setting Global Parameter Values

Due to the very alpha state of parameterization, this has not yet been implemented. However parameters are a package transformation option and can be used just like any other package transformation option, so it's possible to create manifest files with parameterization for the packages a user is using.

Documentation and Tests?

I have not written texinfo documentation or unit tests for Package Parameterization yet as they're expected to change considerably in the process of being merged into master.

When will Parameters be merged to master?

While Package Parameterization itself works great, among other things a host of tools for writing parameterized packages more easily and measuring the complexity of parameterized packages are necessary before this project is merged to master. In the meantime, I would really appreciate feedback and bug reports on the current parameterized packages patch. It can be added to a source install of Guix with a simple patch that does not affect any other component of Guix. Please raise issues on the notabug repository or send me an email if you encounter any issues with this patch, it would greatly help with development.

Installing the patch

To install the patch, you will need to build a git copy of Guix. You can find instructions to do the same here. After building Guix from git, copy the patch into the directory and run git apply parameterization.patch to apply it to the source. Using ./pre-inst-env (see Running Guix Before It Is Installed) now should give you access to parameters.

Thanks

I owe a great deal of credit for this project to my mentors Pjotr Prins and Gabor Boskovits as their guidance was instrumental to its completion. I would also like to thank Ludovic Courtes, Arun Isaac and Efraim Flashner for their feedback and suggestions, which shaped this project into something much more beautiful than what I had originally envisioned. I also learned a lot about writing good Scheme code in the process, and I'm very thankful to Arun Isaac in particular for his detailed and insightful explanations about good practices for writing Scheme code. I also really appreciate the Guix community's enthusiastic and helpful comments on this project, which motivated me to keep working on it.

Thank you and Happy Hacking!