"couldn't read cabal file Cabal.cabal"
Installing Haskell on Ubuntu seems to be a challenge. But maybe I can help!
The root cause of the problem, as is often the case in Haskell, has to do with library versions. Ubuntu 13.04, the most recent version of Ubuntu at the time of writing, uses a version of ghc which isn't compatible with any version of the Haskell Platform. On the older Ubuntu 11.10, an equally-old version of the Haskell Platform is available, but its version of cabal-install cannot install anything! It always gives this error:
couldn't read cabal file Cabal/1.18.0/Cabal.cabal
Let me show you how this error can be fixed.
Packages from the future
Our first hint that the problem has to to with version numbers is that "
cabal --version" tells me that it is linked with Cabal 1.10.1, yet it complains about Cabal 1.18.0! How does Cabal even know about this newer version of itself?
The answer is that after its installation, Cabal has asked me to run "
cabal update", and foolishly, that's what I did.
cabal update" connects to the internet and fetches one
.cabal file for each version of all the packages which have ever been uploaded to hackage. The problem is that the most recent versions of those packages use the most recent Cabal format for their
.cabal files, a format which didn't exist in version 1.10.1; so of course, our old Cabal 1.10.1 cannot read them.
Death to visitors from the future
The solution is clear: we must get rid of those newer files. But which ones are too new?
.cabalfiles are supposed to specify which version of Cabal they need, but I have opted for a more pragmatic solution: automatically deleting each file which Cabal complains about until it stops complaining. Cabal only complains about one file at a time, so the process is a bit slow, but it works!
Cabal stores its file list inside a tar file, so our first step is to extract those files into the filesystem, where we can manipulate them more easily.
mkdir cabal-packages cd cabal-packages tar xvf ~/.cabal/packages/hackage.haskell.org/00-index.tar
There is also a
tar.gz, but it's not used.
Next, we need a way to update Cabal to reflect our changes. Here is the simple script "
update_tar.sh" which I have created for this purpose.
#!/bin/bash rm -f ~/.cabal/packages/hackage.haskell.org/00-index.tar tar cvf ~/.cabal/packages/hackage.haskell.org/00-index.tar *
The script "
remove_future_packages.sh" is only slightly more complicated. It runs an arbitrary Cabal command, watches it fail, extracts the name of the next problematic file, deletes it, and tries again. And again.
#!/bin/bash set -e while true; do ./update_tar.sh > /dev/null # capture errors of the form # cabal: Couldn't read cabal file "hashable/18.104.22.168/hashable.cabal" ERR="$(cabal install cabal-dev 2>&1 || true)" if [ "$(echo "$ERR" | grep "^cabal: Couldn't read cabal file")" ]; then FILE="$(echo "$ERR" | grep "^cabal: Couldn't read cabal file" | cut -d'"' -f2)" DIR="$(dirname "$FILE")" echo "removing $DIR" if [ -d "$DIR" ]; then rm -rf "$DIR" fi else echo "done!" break fi done
Lies, damn lies, and cabal version bounds
After the script was done removing all the problematic files, I could finally run Cabal... only to see it fail halfway through a build, with a different error. The specifics will vary depending on the package you are trying to install; in my case, I was installing
cabal-dev. After all the newer versions were removed by my script, the most recent version which Cabal 1.10.1 could still read was
cabal-dev-0.9.2. Its build failed while looking for
catchIOError, a relatively new function which was introduced in
base-4.4. My version of
base was older than that, but Cabal didn't think that was a problem, because the
.cabal file for
cabal-dev-0.9.2 states that it will work with
base-4.0 and above. Lies! It doesn't!
Fortunately, the solution was simple: I removed
cabal-dev/0.9.2 and re-ran
update_tar.sh to tell Cabal about my change. And then, finally,
cabal-dev-0.9.1 was installed without a fuss!
This adventure with problematic version numbers has encouraged me to test my Haskell packages with many versions of their dependencies, to make sure that my
.cabal files don't lie. And the tool which will help me do this is, let's see... oh, wait, it's
cabal-dev! How ironic.