The Cabal requires that the Haskell implementations be somewhat package-aware. This section documents those requirements.
Installing a package ultimately involves these steps:
Compiling the source files, by invoking the compiler. Even Hugs may require some processing (e.g running cpp or cpphs).
Copying the compiled files into some permanent place. Typically the compiler places no pre-conditions on where "some place" is; instead one usually follows the conventions of the host operating system.
Registering the package: telling the compiler about the existence of the package, and where its files are. To register the package one invokes a compiler-specific program hc-pkg (i.e. ghc-pkg, hugs-pkg etc), passing it an installed package description (IPD) describing the package. The format of an IPD is given in Section 3.4.
It must be possible to register many versions of the same package.
A package can be registered either as a global package or as a user package. The former means that anyone invoking hc will see the new package. The latter means that only the user who installed the package will see it.
User packages shadow global packages, in the following sense:
A Haskell import for module M will seek M in a user package first.
The hc-pkg commands that take package IDs will look for a user package first.
Each user has one package database per compiler and version. That is, the user packages for GHC 6.2 are separate from those for GHC 6.2.1. If there are multiple installations of a particular compiler version on the system, then they will all use the same user packages, so the user should refrain from using user packages with different installations of the same compiler version, unless they can guarantee that the different installations are binary compatible, such as if they were installed from identical binary distributions.
For instance, lets say that Joe User mounts his home directory on his Linux machine and on his Solaris machine. He also uses ghc-6.2 on both machines. His user packages are installed in ~/ghc-6.2-packages (or something) and are compiled for Linux. Now he had better not use these packages with the Solaris compiler, because they are in a spot where the Solaris compiler will find them!
An installed package can be exposed or hidden. An exposed package populates the module name space, while a hidden package does not. Hidden packages are nevertheless necessary. For example, the user might use package A-2.1 and B-1.0; but B-1.0 might depend on A-1.9. So the latter must be installed (else B-1.0 could not be installed), but should be hidden, so that user imports see A-2.1. (However, note that the whole-program invariant described in Section 2.2 implies that a program using B-1.0 could not also use A-2.1, because then both A-2.1 and A-1.9 would form part of the program, and they almost certainly use the same module names.)
The registration program hc-pkg provides operations to expose or hide an already-installed package. By default, installing a package installs it exposed, and hides any existing installed package of the same name (and presumably different version).
Hiding or exposing a package is an operation that can be performed, by hc-pkg, on any package. It is quite distinct from the question of which modules in a package are hidden or exposed (see Section 2.1), which is a property of the package itself. Only the exposed modules of an exposed package populate the module name space seen by a Haskell import statement.
The registration program hc-pkg checks the following invariants:
Before registering a package P, check all the packages that P depends on are already registered. If P is being registered as a global package, P's dependencies must also be global packages.
Before registering an exposed user package P, check that the modules that are exposed by P do not have the same names (in the hierarchical module name space) as any other module in an exposed user package Q. Similarly for system packages. (However, one may register a system package which exposes a module with the same name as a user package, and vice-versa.)
Before un-registering a package P, check that no package that depends on P is registered. The exception is that when un-registering a global package, hc-pkg cannot check that no user has a user package depending on P.
By default, the module namespace is populated only by the exposed modules of exposed packages. This can be overridden using the -package flag, which temporarily exposes a particular package, hiding any other packages of the same name.
Later options override earlier ones, so that for example -package hunit-1.2 -package hunit-1.3 will result in hunit-1.3 being exposed.
Additionally, compilers should provide a -hide-package flag, which does the opposite of -package: it temporarily hides a package for this run of the compiler.
When all the -package and -hide-package flags on the compiler's command line have been processed, the resulting module namespace must not contain any overlapping modules; the compiler should check this and report any errors.
Registering a package with a compiler records the package information in some implementation-specific way; how it does so is not constrained by the Cabal. Much of an IPD is independent of the compiler, but it may also include compiler-specific fields.
Each Haskell implementation hc must provide an associated program hc-pkg which allows a user to make a new package known to the compiler, and to ask what packages it knows. Here is a summary of its interface
Some of these commands (unregister, hide, and describe) make sense for package IDs which offer a range, such as "hc-pkg unregister hunit<2.3". |
Table 1. hc-pkg interface
hc-pkg register {filename | -} [--user | --global] | Register the package using the specified installed package description. The syntax for the latter is given in Section 3.4. |
hc-pkg unregister [pkg-id] | Unregister the specified package. |
hc-pkg expose [pkg-id] | Expose the specified package. |
hc-pkg hide [pkg-id] | Hide the specified package. |
hc-pkg list | List all registered packages, both global and user, hidden and exposed. |
hc-pkg describe {pkg-id } | Give the registered description for the specified package. The description is returned in precisely the syntax required by hc-pkg register. |
hc-pkg field {pkg-id } {field } | Extract the specified field of the package description for the specified package. |
Can we give the --user flag to hide, expose, describe? Can we register a package that is already registered? What if it's registered as a global package and we register it as a user package? |