4. The setup script

The sole requirement of an HPS package is that it should contain, in the root of its file structure, (a) a package description file pkg.desc, and (b) a setup script, Setup.lhs. This section specifies the syntax of the package description, and the command-line interface for the setup script.

4.1. The package description

Here is a sample package description file:

  name:    hunit
  version: 4.3
  deps:    [ foogle > 2.9, bargle = 2.5.1 ]
The first two lines are compulsory. The dependencies are optional, assumed empty if omitted. There can be more lines, all of the form name: stuff, specific to the particular setup script in use. For the HPS-provided simple build infrastructure, the package description syntax is given in Section 5.2.

The exact syntax is still undecided. Should we put everything in quotes?

  deps:    [ "foogle > 2.9", "bargle = 2.5.1" ]
If not, how can a program that doesn't understand a particular field safely ignore it? Skip to end of line? But there may be many lines in fields like deps. ToDo: pick a syntax, provide a parser in the Distribution libraries somewhere.

4.2. The setup script specification

Here is the command-line interface the setup script must satisfy.

Table 2. setup.lhs interface

./Setup.lhs configure [flags]

Prepare to build the package. Typically, this step checks that the target platform is capable of building the package, and discovers platform-specific features that are needed during the build.

./Setup.lhs build

Make this package ready for installation. For a true compiler, this step involves compiling the Haskell source code. Even for an interpreter, however, it may involve running a pre-processor.

./Setup.lhs install [install-prefix]

Copy the files into the install locations, and register the package with the compiler.

./Setup.lhs register

./Setup.lhs unregister

Register (or un-register) this package with the compiler. (NB: registration is also done automatically by install.)

./Setup.lhs test

Run the package's test suite.

For wrapped make-based systems (for instance), a command-line parser that understands the standard Setup.lhs command-line syntax will be provided as a library.

4.2.1. configure

The command ./Setup.lhs configure prepares to build the package. For sophisticated packages, the configure step may perform elaborate checks, to gather information about the target system. It may write a file to record its results, but the name and format of this file are not part of the specification.

All flags are optional. The flags are these:

  • --with-compiler=path, --ghc, --nhc, --hugs: specifies which compiler to use. At most one of the value of these flags may be specified. The configure step checks that the compiler is available, in a sufficiently up-to-date form for the package, and that the package expects to work with that compiler. If the compiler name is not specified, setup will choose one; some packages will come with one compiler baked in.

  • --prefix=path: specifies where the installed files for the package should be installed. Typically on Unix this will be /usr/local and on Windows it will be Program Files. The setup script will use a sensible default (often platform-specific) if the flag is not specified.

  • Unrecognized flags are errors in the default build system, but may be meaningful to wrapped make-based systems (for instance). Therefore, the provided command-line parser will pass unrecognized command-line flags on to the wrapped system.

It is OK for these flags to be "baked into" the compiled tool. In particular, the build system may bake the installation path into the compiled files. There is no provision for changing these baked-into values after configuration.

4.2.2. build

The command ./Setup.lhs build makes this package ready for installation. It takes no flags.

4.2.3. install

The command ./Setup.lhs install copies files from the built package to the right location for installed files, specified in the configure step. Then it registers the new package with the compiler, using the hc-pkg command.

  • --install-prefix=path has three effects. First, it over-rides the --prefix flag specified in the configure step, providing an alternative location. Second, it does not call hc-pkg to register the package. Instead, third, it creates an installed package description file, installed-pkg-descr, which can later be fed to hc-pkg.

  • --user: if present, this flag is passed to hc-pkg so that the package is registed for the current user only. This flag has no effect if --install-prefix is used, because in that case hc-pkg is not called.

  • --global: if present, this flag is passed to hc-pkg so that the package is registed globally (this is the default if neither --user or --global are given).

The reason for the --install-prefix flag is that Roland RPM wants to create an exact installation tree, all ready to bundle up for the target machine, but in a temporary location. He cannot use this location for --prefix in the configure step, because that might bake the wrong path into some compiled files. Nor does he want to register this temporary tree with the compiler on his machine. Instead, he bundles up the temporary installation tree, plus the installed-pkg-descr, and ships them all to the target machine. When they are installed there, the post-installation script runs hc-pkg on the installed-pkg-descr file.

Note that there is no uninstall command in the setup script. While it would be easy enough to implement in the simple build infrastructure, we don't want to require make-based build systems to implement make uninstall, which is fairly non-standard and difficult to get right. In the majority of cases, we expect libraries to be installed via a package manager (eg. RPM, Debian APT), which already provide uninstallation services.

4.2.4. register and unregister

The command ./Setup.lhs register registers the now-installed package with the compiler. Similarly, ./Setup.lhs unregister un-registers the package.

  • --global: registers/un-registers a package as global. This is the default.

  • --user: registers/un-registers a package for the current user only.

4.3. Examples

4.3.1. Bob the Builder and Sam Sysadmin

Bob the Builder can install a HPS source distribution thus. He downloads the source distribution and unpacks it into a temporary directory, cd's to that directory, and says

  ./Setup.lhs configure --ghc
  ./Setup.lhs build
  ./Setup.lhs install --user
Similarly, Sam Sysadmin does exactly the same, except that he says
  ./Setup.lhs install --global
in the final step, so that the package is installed where all users will see it.

For a binary distribution, both Bob and Sam would omit the first two steps, and just do the install step.

4.3.2. System packagers (Debian, RPM etc)

System packagers, such as Donald Debian, will run the configure and build steps just like Bob and Sam. A that point, Donald will say

  ./Setup.lhs install --install-prefix=/tmp/donald
to construct a ready-to-zip tree of all the installed files, plus a file installed-pkg-descr that describes the installed package. He arranges to deliver both these components to the target machine, and then feed installed-pkg-descr to hc-pkg on the target machine.

The file installed-pkg-descr also contains information he needs for building his Debian distribution, namely the package name, version, and (exact) dependencies.

We expect there to be additional tools to help System Packagers to prepare the materials necessary to build their packages from a source distribution. For example, an RPM tool could take a Haskell package source distribution and build an initial .spec file with as many of the fields as possible filled in automatically. In most cases some intervention by the System Packager will be necessary; for example platform-specific dependencies may need to be specified.