Guix Manifests: Package Outputs and Inferiors

Package Outputs in Manifests

This post assumes you are using Guix manifest files (a snazzy feature of Guix) and want to know how to specify a non-default package output. I could not find this documented in the current revision of the Guix info manual. You have to use the procedure specification->package+output. Here is an example which has only a few packages (for readability) but you can have as many packages listed as you want:

(packages->manifest
 (map (compose list specification->package+output)
      '("abbaye"
        "emacs"
        "transmission:gui"
        "youtube-dl")))

The use of specification->package+output allows the specification "transmission:gui" to work. It is necessary to use the compose and list procedures also in this manner, because specification->package+output is a procedure which returns multiple values. (See 6.11.7 Returning and Accepting Multiple Values in the Guile Reference info manual.)

Inferiors

Inferiors are another great feature of Guix, and our documented in the manual. Stated informally, inferiors allow you to list packages from any version of Guix (any commit, or you might say, any time in history) in your manifest file. I use inferiors to install an older version of the linphone software, since I was having some trouble with the latest version. Here is a modification of the above example:

(use-modules (guix inferior)
             (guix channels)
             (srfi srfi-1))

     (define channels
       (list (channel
              (name 'guix)
              (url "https://git.savannah.gnu.org/git/guix.git")
              (commit
               "3f1b2bd322b6cdba99a43d08e5e8464f7424cbc5"))))

     (define inferior
       (inferior-for-channels channels))

(packages->manifest
 (cons (first (lookup-inferior-packages inferior "linphoneqt"))
       (map (compose list specification->package+output)
            '("abbaye"
              "emacs"
              "transmission:gui"
              "youtube-dl"))))

Now, the linphoneqt package is installed as well from older guix commit 3f1b2bd322b6cdba99a43d08e5e8464f7424cbc5.

Inferiors highlight one of the really awesome aspects of Guix: because guix uses “functional package management”, you can have packages installed in your profile from different versions of Guix, without conflicts or breakages. This would be like if you had the ability in Debian to installation packages from Debian Jessie, Debian Stretch, Debian Buster, and Debian Bullseye without conflicts or breakages. This is not a problem in Guix.[1]

[1] You could conceivably have a run-time conflict, e.g., if the old package depended on a linux kernel feature not available from your running linux kernel. I’ve never run into this sort of problem in any of my use cases. In guix, you don’t have to worry about conflicting package dependencies (e.g., library versions) but of course on a running system there are some services that can only have one version running at a time, the obvious example being the linux kernel. Guix does allow you to have multiple system generations selectable from the bootloader, meaning that you could at least boot into different versions of the linux kernel as would be suitable for running different packages.

Running Arduino IDE in Guix

Arduino IDE running on a Guix system

There is no Arduino IDE package for Guix. I asked why once, but I forgot what the reason was — something to do with the way that Arduino build process works I think. Anyway, this is how I get it running on my systems. I suspect this is not the best way, but it works for me. The process is a little convoluted, but I don’t use the IDE very often, so I haven’t been motivated to figure out something better. Typically all I need is avrdude, in order to load Forth firmware onto the chips, and there is an avrdude package available in Guix, as well as a avr-toolchain package and a few other tools.

First you need to make a clone of the git repo:

git clone https://github.com/arduino/Arduino.git

Specifically I am using the some old commit bf24880d7c559751765a43cd1669d893bba267e8, which is the commit for Arduino IDE version 1.8.14, but maybe a newer version would work also.

After changing into the build directory, you must setup the proper build/run environment. I do this by having the following manifest file saved at ~/Manifests/arduino-ide-run.scm:

(use-modules (gnu packages java))

(concatenate-manifests
 (list
  (specifications->manifest
   '("ant"
     "avr-toolchain"
     "bash"
     "coreutils"
     "git"
     "grep"
     "libx11"
     "libxrandr"
     "libxtst"
     "lbzip2"
     "sed"
     "tar"
     "unzip"
     "patchelf"
     "which"))
  (packages->manifest
   `((,icedtea "jdk")))))

Then I set up the environment with the command…

guix environment --pure --preserve='DISPLAY' --preserve='GDM' --preserve='DBUS' --preserve='GIO' --preserve='XDG' --preserve='WINDOW' --preserve='SESSION' --preserve='XCUR' --preserve='DESKTOP' --preserve='XAUTH' -m ~/Manifests/arduino-ide-run.scm

If you want to use the same environment as I am using right now, prefix the command above with guix time-machine --commit=079a7f2c65c51da7b53b0e5ef44c516dc8eaab6e --. (I’m running Gnome DE, but I’m not sure if that makes any difference.)

Then run the command ant run &. In a minute or so you should see the IDE appear.

I problem I have at this point is that, although the IDE runs, you are not able to compile sketches, because the executables in the avr-gcc toolchain are looking for linker & glibc stuff in the wrong place on your system. I fix this by running the following script after the IDE starts, which I have saved in the file ~/Scripts/arduino-patchelf.sh:

GLIBC=/gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/ld-linux-x86-64.so.2
RPATH=/gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/
BUILD_DIR=/home/christopher/Repos/Arduino/build

patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../libexec/gcc/avr/7.3.0/cc1plus
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/avr-g++
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/tools-builder/ctags/5.8-arduino11/ctags
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../lib/gcc/avr/7.3.0/../../../../avr/bin/as
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/avr-gcc
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../libexec/gcc/avr/7.3.0/cc1
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/avr-gcc-ar
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../lib/gcc/avr/7.3.0/../../../../avr/bin/ar
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../libexec/gcc/avr/7.3.0/collect2
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../lib/gcc/avr/7.3.0/../../../../avr/bin/ld
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../libexec/gcc/avr/7.3.0/lto-wrapper
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/../lib/gcc/../../libexec/gcc/avr/7.3.0/lto1
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/avr-objcopy
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/avrdude
patchelf --set-interpreter ${GLIBC} --set-rpath ${RPATH} ${BUILD_DIR}/linux/work/hardware/tools/avr/bin/avr-size

You will need to adjust the variables on top according to the location of things on your system. Unfortunately, it is necessary to run this script every time you call ant run, or at least I haven’t figured out a way to get around that. I’ve been told it is possible instead to just set a symbolic link from the “standard” location glibc location to the actual location, but I didn’t want to do this for fear that there might be some effect on the purity of my other build environments.

Hopefully somebody will put together a Guix package soon, but this is a workaround in the meantime.

Guix: List of Packages in Your Default Profile

(Some credit goes to the helpful folks in the #guix irc channel.)

If you are wanting to build a package manifest file, it is helpful to run code like in this example, which gives a list of packages in your profile by package name:

<username>@nightshade ~$ guix repl
GNU Guile 3.0.4
Copyright (C) 1995-2020 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guix-user)> ,use (guix profiles)
scheme@(guix-user)> (map manifest-entry-name (manifest-entries (profile-manifest "/home/<username>/.guix-profile")))
$1 = ("abbaye" "alex4" "astromenace" "audacity" "avr-toolchain" "bambam" "bombadillo" "bsd-games" "bzflag" "celestia-gtk" "chess" "corsix-th" "cool-retro-term" "cpupower" "curseradio" "dfu-programmer" "dosbox" "eboard" "edgar" "emacs" "emacs-arduino-mode" "emacs-doom-modeline" "emacs-doom-themes" "emacs-elpher" "emacs-geiser" "emacs-guix" "emacs-magit" "emacs-shell-pop" "emacs-spinner" "emacs-wget" "emacs-youtube-dl" "endless-sky" "file" "frozen-bubble" "ghex" "git" "gitg" "gforth" "glibc-locales" "gnome-shell-extensions" "gnucash" "gnupg" "gnuplot" "graphviz" "guile" "guile-colorized" "guile-hall" "guile-readline" "icedtea" "inkscape" "keepassxc" "kitty" "lm-sensors" "linphoneqt" "lure" "maxima" "meritous" "microscheme" "mps-youtube" "no-more-secrets" "openssh" "opensurge" "p7zip" "picocom" "pioneers" "qemu" "recutils" "screen" "starfighter" "stockfish" "strace" "supertux" "supertuxkart" "tig" "tree" "tuxpaint" "unzip" "warzone2100" "wget2" "wgetpaste" "wxmaxima" "xaos" "xboard" "xmoto" "xsensors" "youtube-dl" "youtube-viewer" "zip")

You can then copy and paste the list into a manifest file of this format:

(specifications->manifest '("abbaye" "alex4" ...etc... "zip"))

This is not quite a perfect conversion method as we have ignored some of the details of the profile entries like output type (e.g., out and utils). That could all be handled with some more guile scheme handling of the manifest entries, but I’m not feeling motivated to work out an example for this post.

Guix: How to Change Your Default CPU Frequency Governor

There are I believe a few ways to do this, but I think this is the simplest: Simply insert the following code, nested in your operating-system declaration:

  (kernel-arguments (cons "cpufreq.default_governor=conservative" %default-kernel-arguments))

Replace “conservative” with the governor you want. The same code in an example operating-system declaration:

(operating-system
  (locale "en_US.utf8")
  (timezone "America/Anchorage")
  (keyboard-layout
    (keyboard-layout "us" "altgr-intl"))
  (bootloader
    (bootloader-configuration
      (bootloader grub-bootloader)
      (target "/dev/sda")
      (keyboard-layout keyboard-layout)))
  (kernel-arguments (cons "cpufreq.default_governor=conservative" %default-kernel-arguments))
<etc...>

From what I was told (on IRC) this method will only work with linux kernel release 5.9 or later, which was only added to the Guix main repository five days ago. So you might need to run a guix pull first if you haven’t update Guix in a while. The newer kernel has a feature to allow you to pass in the default governor as a boot parameter, rather than having to recompile the kernel.

(As a side note, today’s commits of the Guix master repository have a broken gdm login manager so I actually used commit b618c15 from five days ago to test the feature being highlighted in this blog post.)

The cpupower command will give you a list of governors available for your system. I would recommend “ondemand” for most users, as that lowers your cpu frequency when the system is running at lower loads, saving you electricity and heat. However, I prefer “conservative”, which is the same, but waits a little longer before bumping up the frequency, so as to not overreact to quick load spikes. “Powersave”, I believe, keeps you running always at the lowest frequency, while “performance” keeps you running always at the highest frequency.

christopher@nightshade ~$ sudo cpupower frequency-info
analyzing CPU 0:
  driver: acpi-cpufreq
  CPUs which run at the same hardware frequency: 0
  CPUs which need to have their frequency coordinated by software: 0
  maximum transition latency: 4.0 us
  hardware limits: 800 MHz - 3.30 GHz
  available frequency steps:  3.30 GHz, 2.60 GHz, 2.10 GHz, 800 MHz
  available cpufreq governors: conservative ondemand userspace powersave performance schedutil
  current policy: frequency should be within 800 MHz and 3.30 GHz.
                  The governor "conservative" may decide which speed to use
                  within this range.
  current CPU frequency: 800 MHz (asserted by call to hardware)
  boost state support:
    Supported: no
    Active: no
    Boost States: 0
    Total States: 4
    Pstate-P0:  3300MHz
    Pstate-P1:  2600MHz
    Pstate-P2:  2100MHz
    Pstate-P3:  800MHz