5. The Cabal simple build infrastructure

A package author must fulfil the specification of Section 4. In many cases, a Haskell package will consist of nothing more than a bunch of Haskell modules, with perhaps the odd C file. In that case, the Cabal provides a simple build infrastructure that fulfils the specification of Section 4, and provides some modest further facilities besides.

This simple build infrastructure is meant to automate the common case. (Think hmake.) The emphasis is on ``simple'': if you want something more elaborate, you can (a) modify the simple build infrastructure (which is written in Haskell) (b) use makefiles, or (c) implement something else entirely.

5.1. Overview

The simple build infrastructure works as follows. First, Angela puts the following Haskell file Setup.lhs in the root of her tree:

  #! /usr/bin/env runghc

  > import Distribution.Simple
Second, she writes a package description Setup.description in the syntax of Section 5.2, which describes the package and gives extra information to the simple build infrastructure.

Now Angela can build her package by saying

  ./Setup.lhs configure
  ./Setup.lhs build
She can even install it on her own machine by saying
  ./Setup.lhs install
She can build a Cabal source distribution:
  ./Setup.lhs source-dist
The full details are given in Section 5.3.

It is no coincidence that the interface is very similar to that for the setup script for an Cabal package distribution (Section 4). In fact, Distribution.Simple.defaultMain conforms to the specification of Section 4.2, and when it builds a distribution, it includes ./Setup.lhs in the tarball, ready to be run by Bob the Builder. However, Distribution.Simple.defaultMain of course implements a richer interface than that required by Section 4.2, because it's intended to support Angela as well as Bob. The full specification is in Section 5.3.

5.2. Package description in the simple build infrastructure

When using the simple build infrastructure, the package description file Setup.description contains not only the name of the package, its version and dependencies, but also a collection of information to explain to the simple build infrastructure how to build the package. This section gives the specific fields, and the syntax of those fields. For the general syntax of the file, please see Section 4.1.

Here is a sample package description file with all the fields understood by the simple build infrastructure:

        -- Required
        Name: Cabal
        License: LGPL
        Copyright: Free Text String
        -- Optional - may be in source?
        Stability: Free Text String
        Build-Depends: haskell-src, HUnit>=1.0.0-rain
        Modules: Distribution.Package, Distribution.Version,
        C-Sources: not/even/rain.c, such/small/hands
        HS-Source-Dir: src
        Exposed-Modules: Distribution.Void, Foo.Bar
        Extensions: OverlappingInstances, TypeSynonymInstances
        Extra-Libs: libfoo, bar, bang
        Include-Dirs: your/slightest, look/will
        Includes: /easily/unclose, /me, "funky, path\\name"
        Options-ghc: -fTH -fglasgow-exts
        Options-hugs: +TH

        -- Next is an executable
        Executable: somescript
        Main-is: SomeFile.hs
        Modules: Foo1, Util, Main
        HS-Source-Dir: scripts
        Extensions: OverlappingInstances
The Name, Version, License, and Copyright are compulsory.

All other fields, such as dependency-related fields, will be considered empty if they are absent. Any fields that the system does not understand will be ignored.

Note that in the future, though the Modules field will be available, it will not be necessary to provide it for building executables and libraries. Instead, the user will provide only the "Main-Is" field (for executables) and the "Exposed-Modules" field (for libraries). The system will chase down dependencies from those modules and include them in the library or source distributions.

The description file fields:

Table 3. Description File Fields

Field NameDescriptionExampleNotes
version[0-9.]+(-?)[-a-zA-Z]*: branch numbers, separated by dots, and optional tags separated by dashes. 
copyright--FREE TEXT--(c) 2004 Isaac Jones 
licenseGPL | LGPL | BSD3 | BSD4 | PublicDomain | AllRightsReservedBSD3If your license isn't on this list, use the license-file field.
license-file--PATH--doc/myLicense.txtSpecify the license you use as a relative path from the root of the source tree.
maintainer--FREE TEXT--T.S. Elliot <elliot@email.com>  
stability--FREE TEXT--Don't hook this up to your coffee machine 
executable--FREE TEXT--cpphsFor this Executable stanza, what is the name of the produced executable.
main-is--PATH--/foo/bar/bang/Baz.hsThe filename to look for the main module for this Executable stanza.
extra-libscomma list of --FREE TEXT-- and spaceslibfoo, libbar , libbangfor non-haskell libraries that this package needs to link to
build-dependspackage name (== | < | > | <= | >=) versionfoo > 1.2, bar < 3.3.5, bangIf the version isn't listed, it's assumed any version is OK.
c-sources--PATH--/foo/bar/bangC source files to build using the FFI.
include-dirs--PATH--"/foo/bar/ ,bang"Not Yet Used
includes--PATH--/foo/bar/bangNot Yet Used
hs-source-dir--PATH--srcA relative path from the root of your source tree. Look here for the Haskell modules.
modules--MODULE LIST--Foo.Bar, Bang.Baz, BooMay not be necessary in the future, since we'll chase dependencies from exposed modules and main module.
exposed-modules--MODULE LIST--Foo.Bar, Bang.Baz, BooFor a library package, which modules should be available for import by the end user?
extensionsOverlappingInstances | RecursiveDo | ParallelListComp | MultiParamTypeClasses | NoMonomorphismRestriction | FunctionalDependencies | RankNTypes | PolymorphicComponents | ExistentialQuantification | ScopedTypeVariables | ImplicitParams | FlexibleContexts | FlexibleInstances | EmptyDataDecls | TypeSynonymInstances | TemplateHaskell | ForeignFunctionInterface | AllowOverlappingInstances | AllowUndecidableInstances | AllowIncoherentInstances | InlinePhase | ContextStack | Arrows | Generics | NoImplicitPrelude | NamedFieldPuns | ExtensibleRecords | RestrictedTypeSynonyms | HereDocuments | UnsafeOverlappingInstancesForeignFunctionInterface, ArrowsNot all extensions are understood by all Haskell Implementations
options-ghc--OPTIONS---fth -cppFor command-line options not covered under extensions, add them here, separated by whitespace.
options-nhc--OPTIONS---P -tFor command-line options not covered under extensions, add them here, separated by whitespace.
options-hugs--OPTIONS---98 +gFor command-line options not covered under extensions, add them here, separated by whitespace.

Further details on some fields:

On hidden modules: Hidden modules form part of the implementation of the package, but not its interface: a client of the package cannot import an internal module. The system still must derive their existence, or they must be listed explicity for two reasons: (a) to allow the global program invariant to be checked (see Section 2.2) and (b) to enable a build system or programming environment to find the source files.

5.3. Distribution.Simple

This section gives the command line interface supported by Distribution.Simple.defaultMain. It supports all the commands described in Section 4.2, (except for "test" - FIX) and in addition the following:

Table 4. Extra commands supported by the simple build infrastructure setup script

./Setup.lhs sdist

Create a source tarball



Distribution.Simple.defaultMain provides interactive command-line help. For each command, a help string is available by typing "./Setup.lhs COMMAND --help".

5.4. The Makefile route

The Haskell libraries that support the simple build infrastructure can, of course, also be re-used to make setup scripts that work quite differently. At one extreme is a setup script that immediately shells out into make, which does all the work.

To support this, Cabal provides a trivial setup library Distribution.Make, which simply parses the command line arguments and shells out into make. Marcus uses the following Setup.lhs

  #! /usr/bin/env runhugs

  > module Main where
  > import Distribution.Make (defaultMain)
  > main = defaultMain
All the package description information is assumed to be known to the makefile system, and so does not appear in the setup script. Thus,
  ./Setup.lhs configure --ghc
  ./configure --with-hc=ghc
Similarly ./Setup.lhs build invokes make all And so on.

Marcus simply arranges that when his makefiles build a distribution, they include this simple setup script in the root of the distribution, where the Bob the Builder expects to find it.