Pages

Wednesday, 21 December 2016

cabal-install-tutorial

How to cabal install
cabal is a command-line program for downloading and building software written in Haskell.
It can install all kinds of fascinating and useful software packages from the Hackage repository.
It is excellent and indispensable, but it currently has a troublesome flaw:
it sometimes mysteriously refuses to install things, leading to cries of “AAAGH! CABAL HELL!!”.
A little extra know-how prevents this.
This tutorial aims to show you how to install cabal packages with confidence,
especially if you are new to Cabal and Haskell.
Welcome and let's get started!
  1. Should I use cabal ?
  2. cabal, Cabal, cabal-install
  3. Getting cabal
  4. Installing things
  5. How to check what's installed
  6. When it won't install: cabal hell
  7. The easy solution: reset your packages
  8. The careful solution: use a sandbox
  9. The harder, quicker solution: clean your packages
  10. Dealing with bad dependencies
  11. Summary
  12. Further reading
  13. About this document

Should I use cabal ?
Your system may have a package manager, like apt-get, yum, or macports, and it might offer packages for the Haskell software you want to install.
In this case you may save time by using it instead of cabal. It probably offers more stable, better-integrated packages, and they may be pre-compiled.
Otherwise, yes, use cabal. It is cross-platform and can install the widest range of up-to-date Haskell software.
It is also an essential tool if you want to develop Haskell software.

cabal, Cabal, cabal-install
Let's clarify these now to avoid confusion later. The Cabal wiki page says:
> *“Cabal is a package and build system. Cabal is only involved in the creation of packages and the building of their contents. It does not manage packages.
>
Cabal-Install installs cabal packages. It is distinct from Cabal (the build system). This often confuses new users. Furthermore, Cabal-Install is not a fully featured package manager. For example, it cannot install non cabal packaged dependencies, it cannot uninstall packages, nor can it automatically upgrade installations.*
In short: this tutorial is about using cabal-install, which is cabal on the command line.
We'll just say cabal from now on.
It installs cabal packages, can't uninstall them, and can upgrade them only with supervision.
(Uninstalling is done with a lower-level tool called ghc-pkg, as we will see below.)

Getting cabal
cabal installs software, and can upgrade itself, but first you need get it installed by some other means.
It is often available as a system package, otherwise get it by installing the Haskell Platform,
or just GHC.
To check that it's installed, at a command prompt do:
$ cabal --version
cabal-install version 1.16.0.2
using version 1.16.0 of the Cabal library
$
You should avoid versions older than 0.14. (After 0.14 the version number jumped to 1.16).
If you do have a very old version, you might be able to upgrade like so (we take care not
to leave two versions of Cabal installed):
$ cabal update
Downloading the latest package list from hackage.haskell.org
$ cabal install cabal-install && ghc-pkg unregister Cabal
Resolving dependencies...
Downloading Cabal-1.16.0.3...
...
Installed cabal-install-1.16.0.2
$

Installing things
As we just saw, installing usually goes like this:
  1. find a package you want to install, eg from
  2. the Hackage package list
  3. or cabal list
  4. update your local list of available packages with cabal update
  5. download and install the package with cabal install PACKAGE.
  6. Some useful options:
  7. --dry-run to see what cabal plans to do (recommended),
  8. -jN to build N packages in parallel (faster, uses more memory),
  9. -fFLAG or -f-FLAG to turn build flags on or off (for packages that have them).
For example:
$ cabal update
Downloading the latest package list from hackage.haskell.org
$ cabal install --dry shelltestrunner
Resolving dependencies...
In order, the following would be installed (use -v for more details):
Diff-0.2.0
ansi-terminal-0.6
ansi-wl-pprint-0.6.6
filemanip-0.3.6.2
hostname-1.0
test-framework-0.8
test-framework-hunit-0.3.0
shelltestrunner-1.3.1
$ cabal install shelltestrunner -j2
Resolving dependencies...
Downloading Diff-0.2.0...
Downloading ansi-terminal-0.6...
Configuring filemanip-0.3.6.2...
..etc..
Downloading shelltestrunner-1.3.1...
Configuring shelltestrunner-1.3.1...
Building shelltestrunner-1.3.1...
Installed shelltestrunner-1.3.1
$
More tips:
  • If you have multiple packages to install, it's preferable to install them all together, so that cabal can make better decisions.
  • Eg instead of: cabal install A; cabal install B
  • do: cabal install A B.

How to check what's installed
Note that cabal knows about only some installed packages:
$ cabal list --installed Diff
* Diff
    Synopsis: O(ND) diff algorithm in haskell.
    Default available version: 0.3.0
    Installed versions: 0.2.0
    License:  BSD3

$ cabal list --installed shelltestrunner
No matches found.
$
It's the same with ghc-pkg:
$ ghc-pkg list --simple Diff 
Diff-0.2.0
$ ghc-pkg list --simple shelltestrunner
$
Packages can contain libraries (for use by other packages), executables (for use by humans), or both.
cabal and ghc-pkg only keep track of installed library packages.
The shelltestrunner package provides only executables, so cabal and ghc-pkg do not care about it after installation.
To check for installed executables, we can do eg:
$ ls -lt ~/.cabal/bin | head -5
total 1852920
-rwxr-xr-x  1 simon  simon  10394608 Mar  2 07:17 shelltest
-rwxr-xr-x  1 simon  simon   4962612 Mar  2 07:10 gearbox
-rwxr-xr-x  1 simon  simon  12279756 Mar  1 06:56 cabal
-rwxr-xr-x  1 simon  simon   1083948 Mar  1 06:54 hakyll-init
$

When it won't install: cabal hell
Over time, as you install more packages, and as new versions are released on Hackage,
cabal install becomes more likely to fail due to unresolvable dependencies.
There are other reasons for install failure (bad dependencies, bad code, incompatible compiler version, missing C libraries),
but unresolvable dependencies is the most common.
When it happens, you'll see something horrible like:
$ cabal install hledger-0.18
Resolving dependencies...
cabal: Could not resolve dependencies:
rejecting: hledger-0.19.4/installed-402..., 0.19.3, 0.19.2, 0.19.1, 0.19,
0.18.2, 0.18.1 (global constraint requires ==0.18)
trying: hledger-0.18
trying: regexpr-0.5.4/installed-0da...
trying: process-1.1.0.2/installed-7b6...
rejecting: haskeline-0.7.0.3/installed-414..., 0.7.0.3, 0.7.0.2, 0.7.0.1,
0.7.0.0 (conflict: hledger => haskeline==0.6.*)
rejecting: haskeline-0.6.4.7 (conflict: process =>
unix==2.6.0.1/installed-ccb..., haskeline => unix>=2.0 && <2.6)
rejecting: haskeline-0.6.4.6 (conflict: regexpr =>
mtl==2.1.2/installed-538..., haskeline => mtl>=1.1 && <2.1)
rejecting: haskeline-0.6.4.5, 0.6.4.4, 0.6.4.3, 0.6.4.2, 0.6.4.1, 0.6.4.0,
0.6.3.2, 0.6.3.1, 0.6.3, 0.6.2.4, 0.6.2.3 (conflict: process =>
filepath==1.3.0.1/installed-a78..., haskeline => filepath>=1.1 && <1.3)
rejecting: haskeline-0.6.2.2, 0.6.2.1, 0.6.2, 0.6.1.6, 0.6.1.5, 0.6.1.3,
0.6.1.2, 0.6.1.1, 0.6.1, 0.6.0.1, 0.6 (conflict: process =>
filepath==1.3.0.1/installed-a78..., haskeline => filepath==1.1.*)
rejecting: haskeline-0.5.0.1, 0.5, 0.4, 0.3.2, 0.3.1, 0.3, 0.2.1, 0.2
(conflict: hledger => haskeline==0.6.*)
$
What has happened is that your installed packages,
plus the new packages cabal thinks should be installed,
plus a GHC restriction that only one version of each package is used in any build,
have formed a network of dependencies that cabal can't satisfy.
And, cabal's explanation of the problem is hard for a human to understand.
You are entering.. cabal hell!

The easy solution: reset your packages
There is an easy workaround that does not require cabal troubleshooting skills or special tools.
If we clear out all installed libraries, cabal may have to reinstall a few but will have a much better chance of success.
The easiest way to do this (on unix) is:
$ rm -rf ~/.ghc ~/.cabal
This is simplest and reclaims most disk space, but it also deletes executables and config files.
A less crude way is to use this bash script, which you can add to your ~/.bashrc:
# Uninstalls and deletes all installed GHC/cabal packages, but not binaries, docs, etc.
# Use this to get out of dependency hell and start over, at the cost of some rebuilding time.
function ghc-pkg-reset() {
    read -p &#39;erasing all your user ghc and cabal packages - are you sure (y/n) ? &#39; ans
    test x$ans == xy && ( \
        echo &#39;erasing directories under ~/.ghc&#39;; rm -rf `find ~/.ghc -maxdepth 1 -type d`; \
        echo &#39;erasing ~/.cabal/lib&#39;; rm -rf ~/.cabal/lib; \
        # echo &#39;erasing ~/.cabal/packages&#39;; rm -rf ~/.cabal/packages; \
        # echo &#39;erasing ~/.cabal/share&#39;; rm -rf ~/.cabal/share; \
        )
}
and:
$ source ~/.bashrc
$ ghc-pkg-reset
erasing all your user ghc and cabal packages - are you sure (y/n) ? y
$ ghc-pkg list --user
/Users/simon/.ghc/x86_64-darwin-7.6.1/package.conf.d
$
and then run the cabal install command again.

The careful solution: use a sandbox
Another approach is to keep separate installed package sets, known as sandboxes.
This costs more disk space and build time overall (for me, each package set takes about 0.5G of space).
But when you need to work on multiple projects whose dependencies are incompatible,
or to isolate projects from unrelated upgrades, this is the solution.
cabal does not yet provide this feature natively; for now it means using an additional tool, either cabal-dev or hsenv.

The harder, quicker solution: clean your packages
As you get familiar with diagnosing these failures,
you will more often be able to see how to clean up your installed package set to give cabal more freedom.
Sometimes just removing the right old package will get things unstuck. Use ghc-pkg unregister PACKAGE for this.
If other packages depend on it, you can add --force, then also remove those packages (which will now be in a broken state).
The following bash script makes this easier:
# Unregisters broken GHC packages. Run a few times until it finds no more.
# ghc-pkg-clean -f cabal/dev/packages*.conf also works.                                                                                                                                                                                     
function ghc-pkg-clean() {
    for p in `ghc-pkg check $* 2>&1  | grep problems | awk &#39;{print $6}&#39; | sed -e &#39;s/:$//&#39;`
    do
        echo unregistering $p; ghc-pkg $* unregister $p
    done
}
An example:
$ ghc-pkg unregister tls
ghc-pkg: unregistering tls would break the following packages: hakyll-4.1.4.0 http-conduit-1.8.9 http-conduit-1.8.7.1 tls-extra-0.6.1 (use --force to override)
$ ghc-pkg unregister tls --force
unregistering tls would break the following packages: hakyll-4.1.4.0 http-conduit-1.8.9 http-conduit-1.8.7.1 tls-extra-0.6.1 (ignoring)
$ ghc-pkg-clean
unregistering http-conduit-1.8.9
unregistering http-conduit-1.8.7.1
unregistering tls-extra-0.6.1
$ ghc-pkg-clean
unregistering hakyll-4.1.4.0
$ ghc-pkg-clean
$
Since cabal will reinstall whatever it needs, you can keep removing and cleaning until your install command works again.
This incremental removal might be preferable to a full reset.

Dealing with bad dependencies
If, after a reset or in a clean sandbox, there are still unresolvable dependencies,
it means the released packages on Hackage have bad (incorrect, out-of-date, too tight, too loose) dependency declarations,
or the packages are not compatible with your GHC version.
In this case identify the problem package(s) and get the maintainer's help,
and/or try fixing the dependencies yourself in a local copy of the package (cabal unpack is good for this).

Summary
  • cabal installs Haskell software from Hackage. It comes with GHC or the Haskell Platform or as a system package.
  • Use at least version 0.14, and preferably the newest.
  • Use it instead of your system's package manager when you want to install (or develop) the latest Haskell software.
  • The main subcommands are update, list and install.
  • install becomes more likely to fail over time, as packages are added locally and on Hackage. Understanding these failures can be hard.
  • The easy fix is to reset your packages, eg with ghc-pkg-reset.
  • Or, you can install packages in separate sandboxes with cabal-dev or hsenv.
  • Or, with experience quicker fixes may be apparent, eg uninstall old package versions with ghc-pkg unregister and ghc-pkg-clean.
  • Packages which fail to install even with a clean slate should be reported to their maintainers.
May you be free from cabal hell and enjoy haskell heaven!

Further reading

About this document

from http://hub.darcs.net/simon/cabal-install-tutorial