Franz Franz

Customize Guix Shell Environment

TL;DR A short guide on how to set environment variables like OPENSSL_DIR within a Guix shell manifest for project-specific development environments.

I run Guix on my laptop and do virtually all my development on it. Guix comes with a beautiful shell environment that allows you to cleanly isolate dependencies for specific projects. Unlike traditional distributions like Debian, Guix does things a little differently, and I sometimes find myself needing to customize the shell environment for specific projects.

Shell Environments

Here’s how you can spawn a Rust development environment:

guix shell rust rust-cargo gcc-toolchain openssl

The problem comes when any crate relies on openssl. The workaround is usually as simple as exporting an environment variable:

export OPENSSL_DIR=$(dirname $(dirname $(realpath $(which openssl))))

Shell Environments from Manifests

This quickly gets repetitive. Luckily, Guix has a nice feature that allows you to write manifests, from which you can spawn shell environments like so:

guix shell -m manifest.scm

A manifest is a simple scheme file that lists all required packages. Here’s an example:

(specifications->manifest '("rust" "rust-cargo" "gcc-toolchain" "openssl"))

Now the idea is simple: why don’t we use that manifest to also set the OPENSSL_DIR environment variable?

After some attempts, I came up with this:

(use-modules (guix profiles)
             (guix packages)
             (guix search-paths)
             (gnu packages rust)
             (gnu packages rust-apps)
             (gnu packages tls))

;; Create a custom OpenSSL package that exports OPENSSL_DIR pointing to itself
(define openssl-with-env-dir
  (package
    (inherit openssl)
    (name "openssl")
    (native-search-paths
     (append (package-native-search-paths openssl)
             (list (search-path-specification
                    (variable "OPENSSL_DIR")
                    (files '("."))
                    (file-type 'directory)
                    (separator #f)))))))

;; Create a custom GCC package that exports CC
(define gcc-with-env-cc
  (package
    (inherit gcc-toolchain)
    (name "gcc-toolchain")
    (native-search-paths
     (append (package-native-search-paths gcc-toolchain)
             (list (search-path-specification
                    (variable "CC")
                    (files '("bin/gcc"))
                    (file-type 'regular)
                    (separator #f)))))))

(packages->manifest
 (list rust
       rust-cargo
       gcc-with-env-cc
       openssl-with-env-dir))

When you spawn a shell from this manifest, OPENSSL_DIR will point to the correct location.

Conclusion

Guix can get in the way sometimes, but if you have some patience to learn, these are one-time problems.