Using multiple versions of GHC in parallel with GNU stow
Do any of the following apply to you?
- You sometimes hack on GHC.
- You sometimes want to try out an unreleased GHC version.
- You maintain a library and want to make sure it builds with several different versions of GHC.
- You want to try out a newly released version of GHC but without blowing away your existing (working!) GHC install.
As you can see, these are roughly in order from most to least “hard core”, and I expect that the last two are fairly common, even if the first two are not. The common thread, of course, is having multiple versions of GHC installed simultaneously.
The solution
A solution that I’ve found which works quite well (on Linux, and I expect it would work on OSX as well) and deserves to be better known is GNU stow. Here’s how it works: instead of installing things directly in /usr/local
(or $HOME/local
, or whatever), you instead install in sandboxed locations like /usr/local/stow/ghc-7.6.1
. You then tell stow
that you want to “install” ghc-7.6.1
, and it creates all the necessary symlinks to mirror the directory structure under the ghc-7.6.1
directory into /usr/local
. But of course it tracks everything so that you can easily uninstall all these symlinks as well. (And yes, it’s smart about symlinking an entire directory when possible, instead of all the individual files, and later “splitting up” such big-scale links when necessary.)
The pros of this sort of scheme should be clear:
-
Once you’ve “installed” a particular version you just use it as normal—no need to pass the right directories as flags to tools like
cabal
orghc-pkg
. - Switching to a different version of GHC is relatively quick (see below).
- Installing new versions is pain-free; it’s just as easy to have twenty different versions as it is to have two.
Of course, there are a few downsides as well:
-
Trusting a Perl script to munge your
/usr/local
. (Though for what it’s worth, I have been using it heavily for about a year now—I currently have six different versions of GHC installed—and have never once encountered a single problem.)
- You can’t use several versions of GHC at once—there is always exactly one “current” version. So if you want to, e.g., do test builds of a library under several versions of GHC in parallel, you need a different solution.
A step-by-step guide
So here’s how this works in more detail. First, of course, you have to install stow itself; I’ll assume you can get it from your OS package manager or know how to build it from source. What you get is simply an executable called stow
.
Now, when installing GHC (whether a binary distribution or from source), give the configure
step an extra prefix
argument, for example:
./configure –prefix=/usr/local/stow/ghc-7.6.1
Just take the directory where you would usually install GHC, and add stow
and then an additional subdirectory for the particular version you are installing. This directory doesn’t have to already exist; the installer will create it if it doesn’t.
(Note that if you already have GHC installed, you’ll have to uninstall it first and then reinstall it with stow
—stow
won’t work unless it can manage all your GHC installs.)
After the installation process completes, you have an unusable ghc
because, of course, …/stow/ghc-7.6.1
isn’t on any relevant paths. All you have to do to finish installing it is
cd /usr/local/stow && stow ghc-7.6.1
This instructs stow
to make symlinks into ghc-7.6.1
from /usr/local
. After this completes, that’s it! You can use your new GHC as usual.
To uninstall, follow the same procedure but give stow
the -D
option:
cd /usr/local/stow && stow -D ghc-7.6.1
To switch from one version of GHC to another just uninstall the current version and then install the new one. I actually have a script which automates this process: it looks in the stow
directory to see which versions are availble, prompts me to choose one from a list, then uninstalls the current version (obtained with ghc –numeric-version
) and installs the newly selected version. On my laptop this process takes just a couple seconds.
That’s it! Happy stowing!