Haskell packages gotcha: global vs. per-user package databases

This morning, I was having a problem involving Haskell’s Cabal build system. Since it’s something which could conceivably affect others, and since googling on the error text didn’t help me, I’m going to report my experience for the benefit of future travellers/googlers.

I was trying to (re)build xmonad, and got the following error:

[gimbo@orb xmonad] runghc -v Setup configure 
   Could not find module `Distribution.Simple':
       Use -v to see a list of the files searched for.

Vexing. Distribution.Simple is Cabal’s “simple build system”, and is the only dependency of the Setup script in question:

[gimbo@orb xmonad] cat Setup.lhs 
#!/usr/bin/env runhaskell
> import Distribution.Simple
> main = defaultMain

Now, I had actually already installed Cabal – the latest version from darcs, in fact:

[gimbo@orb ~] ls -l /usr/local/lib/Cabal-1.1.7/ghc-6.6 
total 4614
drwxr-xr-x  5 root  wheel      512 20 Apr 15:09 Distribution
-rwxr-xr-x  1 root  wheel  1836956 27 Apr 12:42 HSCabal-1.1.7.o
drwxr-xr-x  3 root  wheel      512 20 Apr 15:09 Language
drwxr-xr-x  2 root  wheel      512 20 Apr 15:09 include
-rwxr-xr-x  1 root  wheel  2829692 27 Apr 12:42 libHSCabal-1.1.7.a

and Simple really was there:

[gimbo@orb ~] ls -ld /usr/local/lib/Cabal-1.1.7/ghc-6.6/Distribution/Simple*
drwxr-xr-x  2 root  wheel    512 20 Apr 15:09 /usr/local/lib/Cabal-1.1.7/ghc-6.6/Distribution/Simple
-rwxr-xr-x  1 root  wheel  30049 27 Apr 12:42 /usr/local/lib/Cabal-1.1.7/ghc-6.6/Distribution/Simple.hi

So what was the problem? Why wasn’t it getting picked up? I started to realise the answer when I followed the advice of the original error message, and passed runghc the -v flag (I’ll snip non-relevant lines, of which there were many):

[gimbo@orb xmonad] runghc -v Setup configure 
Glasgow Haskell Compiler, Version 6.6, for Haskell 98, compiled by GHC version 6.6
Using package config file: /usr/local/lib/ghc-6.6/package.conf
Using package config file: /home/gimbo/.ghc/i386-freebsd-6.6/package.conf
hiding package Cabal-1.1.6 to avoid conflict with later version Cabal-1.1.7
    Could not find module `Distribution.Simple':
      locations searched:
Failed, modules loaded: none.

There are three things to notice here.

First, ghc is using two package config files: a global one and one off my home directory. This is perfectly normal, sane behaviour. More on this shortly.

Second, I have conflicting versions of Cabal installed, and it’s only using the latest one. All good: I want it to be using 1.1.7 (which I’d installed from darcs) anyway. I don’t know where 1.1.6 cae from: maybe an older darcs checkout, or maybe a snapshot. (Later I removed the old version using ghc-pkg, but that’s not what this story is about…)

Third, and most interestingly, where did it look for Distribution.Simple? Decidedly not in /usr/local/lib/Cabal-1.1.7/ghc-6.6/ (where, as we saw earlier, it would be found). Instead, it’s looking for it in /usr/home/gimbo/cabal/Cabal/dist/build/Distribution/Simple.hi. Suddenly I realised what the problem was.

When today started, my home directory contained a directory called cabal, in which I had downloaded the Cabal source, built it, and installed it (several days ago). One of my first actions today was to delete that directory, since Cabal was indeed built and installed. Little did I suspect that ghc would look for the code there, rather than in /usr/local/lib/...

So why did it? I realised the answer when I read the packages chapter of the GHC manual, which I should have done sooner. If you use Haskell and haven’t read this yet, do so! Very quickly I began to see that the key to debugging and solving my problem was the ghc-pkg utility which, among other things, can list all your installed packages:

[gimbo@orb ~] ghc-pkg list
    Cabal-1.1.7, GLUT-2.0, HGL-3.1, HUnit-1.1, HaXml-1.13.2,
    Haskore-0.0, OpenGL-2.1, QuickCheck-1.0, ShellPipe-0.0, X11-1.1,
    X11-1.2, X11-extras-0.0, base-2.0, cgi-2006.9.6, fgl-5.2,
    filepath-1.0, (ghc-6.6), haskell-src-1.0, haskell98-1.0, html-1.0,
    mtl-1.0, network-2.0, parsec-2.0, readline-1.0, regex-base-0.71,
    regex-compat-0.71, regex-posix-0.71, rts-1.0, stm-2.0,
    template-haskell-2.0, time-1.0, unix-1.0, xhtml-2006.9.13
    Cabal-1.1.7, HAIFA-0.11, HTTP-2006.7.7, Shellac-0.6,
    Shellac-readline-0.3, (hat-2.5), hxt-7.1, syb-generics-2.9

Here we see two versions of Cabal-1.1.7 referenced – one in the global package database, and one in my per-user package database. The per-user version “wins” by default, so the global Cabal-1.1.7 was getting ignored. I realised that at some point in the past I had configured/built/installed Cabal-1.1.7 using the options to install it as user rather than root (see the Cabal README for how). I deduce that this registers the code in the per-user package database and (critically) doesn’t copy it anywhere – ie it assumes you won’t delete the code from the place where it was compiled. Since I deleted that code this morning, it could no longer be found.

The fix was simply to delete the Cabal-1.1.7 entry from the per-user package database:

[gimbo@orb ~] ghc-pkg --user unregister Cabal                                  
Saving old package config file... done.
Writing new package config file... done.

Now ghc uses the Cabal-1.1.7 entry in the global package database, looks in the right place, and finds it – and I can build xmonad once again.

The moral of the story: RTFM. :-)

2 Responses to “Haskell packages gotcha: global vs. per-user package databases”

  1. Tim
    May 8th, 2007 | 3:24 am

    When you do the configure step in cabal, you can provide a –prefix argument to say where you want the results to be installed. For my testing, I generally do

    runghc Setup.hs configure –user –prefix ~/ghc-local

  2. Johannes
    December 1st, 2011 | 2:29 am

    A thousand thanks! :)