The Haskell Cabal

A Common Architecture for Building Applications and Tools

Isaac Jones

Simon Peyton Jones

Simon Marlow

Malcolm Wallace

Ross Patterson

The Haskell Library and Tools Infrastructure Project is an effort to provide a framework for developers to more effectively contribute their software to the Haskell community. This document specifies the Common Architecture for Building Applications and Tools(Cabal), which contributes to the goals of the Haskell Library and Tools Infrastructure Project.

Specifically, the Cabal describes what a Haskell package is, how these packages interact with the language, and what Haskell implementations must to do to support packages. The Cabal also specifies some infrastructure (code) that makes it easy for tool authors to build and distribute conforming packages.

The Cabal is only one contribution to the Library Infrastructure project. In particular, the Cabal says nothing about more global issues such as how authors decide where in the module name space their library should live; how users can find a package they want; how orphan packages find new owners; and so on.

The Cabal has been discussed by the implementors of GHC, Nhc98, and Hugs, all of whom are prepared to implement it. The proposal is now open for wider debate. Please contribute by emailing .

Table of Contents
1. The Haskell Package System: goals
1.1. Dramatis personae
1.2. An example
2. The Haskell Package System: overview
2.1. Packages
2.2. Packages and the Haskell language
2.3. Packages and compilers
2.4. Package distributions
2.5. The Setup script
3. What the compilers must implement
3.1. Building and registering a package
3.1.1. Global packages and user packages
3.1.2. Exposed packages and hidden packages
3.1.3. Registration invariants
3.2. The -package compiler flag
3.3. The interface to hc-pkg
3.4. Syntax of installed package description
4. The setup script
4.1. The package description
4.2. The setup script specification
4.2.1. configure
4.2.2. build
4.2.3. install
4.2.4. register and unregister
4.3. Examples
4.3.1. Bob the Builder and Sam Sysadmin
4.3.2. System packagers (Debian, RPM etc)
5. The Cabal simple build infrastructure
5.1. Overview
5.2. Package description in the simple build infrastructure
5.3. Distribution.Simple
5.4. The Makefile route
A. Layered Tools
B. Related Systems
B.1. Debian
B.2. Python Distutils
B.3. CPAN and Boost
B.4. FreeBSD's Ports System
B.5. The XEmacs Packaging System
B.6. Make-Based Systems
B.7. hmake

1. The Haskell Package System: goals

The Haskell Package System (Cabal) has the following main goal: to specify a standard way in which a Haskell tool can be packaged, so that it is easy for consumers to use it, or re-package it, regardless of the Haskell implementation or installation platform.

The Cabal also supports tool authors by providing an infrastructure that automates the process of building and packaging simple tools. It is not necessary to use this code—indeed complex libraries may exceed its abilities—but it should handle many cases with no trouble.

1.1. Dramatis personae

The Cabal serves a number of people in different ways:

  • Joe User is simply a Haskell user. He does not download new packages. Nevertheless, he needs to know about his Haskell compiler's -package flag (see Section 3).

  • Bob the Builder and Sam Sysadmin both download, build, and install new packages. The only difference between the two is that Sam has root permission, and can install packages in more globally-visible places.

  • Peter Packager builds operating system specific install files (e.g. .msi .rpm .deb) from packages supplied by Marcus or Angela. We might also call him Roland RPM, Donald Debian, and Willie Windows who build Linux RPM, Debian, and Windows installer packages respectively (this list is not exhaustive). They do this as a service to their platform's community, and may know little or nothing about the internal details of the Haskell packages they are wrapping up.

  • Isabella Installer installs binary packages supplied by Peter or Angela, (or Rowland, Donald, and Willie). Isabella requires only a Haskell compiler/interpreter. She can use rpm to install packages by Rowland. She cannot or will not build the packages herself, so she relies on Peter to provide them. She won't use the Setup script directly from Angela, but she might use a layered tool like haskell-install, which does all the work of downloading and installing simple packages.

  • Angela Author wants to write a simple Haskell tool, and distribute it with minimum fuss, in such a way that all the above folk can easily use it.

  • Marcus Makefile is like Angela, but more sophisticated. He has a complicated tool, and uses makefiles. Still, he wants to arrange that Roland, Donald, Bob, Sam, and Joe don't need to know about his internal complexity.

We describe Angela and Marcus as producers of their packages, and all the others as package consumers.

Note that though these users all have different names, it is very common for their roles to overlap when it comes to real people. For instance, if Bob builds packages for himself, he becomes Joe once they're built. These personas are use cases, and not meant to represent completely distinct individuals.

1.2. An example

To give the idea, here is a simple example. Angela has written a couple of Haskell modules that implement sets and bags; she wants to distribute them to Bob as a package called, say, angela-coll. Let's say that the modules are Data.Set, Data.Bag, Angela.Internals. (The Cabal says nothing about how Angela decides where in the name space to put her modules.) Angela only wants to expose the first two to Bob; the Angela.Internals module is (as its name suggests) internal to the package.

Angela decides to use the simple build infrastructure that the Cabal provides. She is working in a directory ~/coll. In there she puts the modules, in sub-directories driven by their module name: ~/coll/Data/Set.hs, ~/coll/Data/Bag.hs, and ~/coll/Angela/Internals.hs. Next, she writes a package description, which she puts in ~/coll/Setup.description:

Name: angela-coll
License: LGPL
Copyright: Copyright (c) 2004, Angela Author
Exposed-Modules: A, B, B.C
She also creates a small Haskell file ~/coll/Setup.lhs as follows:
  #! /usr/bin/env runhugs

  > module Main where
  > import Distribution.Simple( defaultMain )
  > main = defaultMain
This library implements the Cabal simple build infrastructure.

The first line arranges that when Angela, (or Joe, or Sam, etc.) executes Setup.lhs as a shell script, the shell will invoke runhugs, which will in turn run mainn imported from the library Distribution.Simple.

It is not necessary that the script be run this way, it is just a convinient way to run it. Sam or Joe may choose to compile the setup script into an executable with NHC or GHC and then run it directly (it is a literate Haskell script so that it can be compiled without the first line causing a syntax error). Another option is for that first line to read

!# /usr/bin/env runhaskell
where runhaskell is a symlink to runhugs, runghc, or runnhc.

Now she is ready to go. She types:

  ./Setup.lhs configure --ghc
  ./Setup.lhs build
  ./Setup.lhs sdist
The first line readies the system to build the tool using GHC; for example, it checks that GHC exists on the system. The second line checks that the tool does indeed build flawlessly. (At this point she can write and execute tests, as we discuss later.) The third line wraps up the package as a source distribution, making the file ~/coll/angela-coll-1.tar.gz.

Angela emails the tar file to Bob, who untars it into tmp/coll. He cd's to that directory and types

  ./Setup.lhs configure --ghc
  ./Setup.lhs build
  ./Setup.lhs install
He's all done. Now in his Haskell programs, Bob can simply import the new modules Data.Set and Data.Bag. He does not need to give extra flags to GHC to tell it to look for Angela's modules; they are there automatically. If Angela used the same module names as someone else, Bob may need finer control: see Section 3.

If Angela wrote her modules in a suitably portable variant of Haskell, Bob could also have said --hugs or --nhc in his configure line, and the package would have been built and installed for those compilers instead.