Capri

From HaskellWiki
Jump to navigation Jump to search

Synopsis

Capri (abbreviation of CAbal PRIvate) is a wrapper program on top of cabal-install to operate it in project-private mode. In this mode, there is no global or user package databases; only one package database is defined, private to the project, located under the root directory of a project.

Capri invokes cabal-install and ghc-pkg in the way that only project's private package database is visible to them. Starting with minimally required set of packages, all necessary dependencies will be installed into that database, not affecting user or global databases.

Capri is mainly intended for use with projects organized as Cabal packages targeting executables rather than just libraries. Capri can currently be used with Glasgow Haskell Compiler only as it depends on its certain features. It is also recommended to use cabal-install of recent versions (as of July 2010, the most recent version is 0.8.2).

Introduction

A situation is possible, when a local (global or user or both) Cabal packages database contains a package of the same name, but of several versions. Other packages installed may depend on various versions of that package. Bad things happen when a new package is to be built, and its dependencies bring up several different versions of the package mentioned first.

While such situation may be cured by careful tracing of dependencies, removal of old versions of packages, and rebuilding of new packages, there is a way to avoid it from the beginning. For each project targeting an executable, create a private database of packages it depends upon. This makes practical sense mainly for packages targeting statically linked executables, ensuring a clean build environment. Other than this, project-private building may be used for test builds of library packages as well.

The Glasgow Haskell Compiler uses the GHC_PACKAGE_PATH environment variable to describe the location of Haskell packages database. A typical configuration of such database consists of global and user databases. Default locations of these databases are known to the compiler even when the variable is not set.

It is however possible to make GHC not to use any of these databases, and point it to an alternative location instead. In order to do this, the variable has to contain a single path, and not to be terminated with a path delimiter (colon or semicolon, depending on Unix/Windows platrorm). This is how project-private build is achieved at GHC level. Cabal-install in turn requires several options to be specified, to restrict itself to using only private packages database to look for installed packages, and the installation directory prefix which is also local to a project.

Source Location

Haskell source: http://hs-ogl-misc.googlecode.com/hg/capri/Main.hs

Hackage: TBD

Commands Summary

$ capri help
This program provides a wrapper over cabal-install to operate in project-private mode.

Usage: capri COMMAND [FLAGS]
   or: capri [GLOBAL FLAGS]

Global flags:
 -h --help            Show this help text
 -V --version         Print version information
    --numeric-version Print just the version number

Commands:
  bootstrap    Bootstrap private packages configuration
  list         List packages installed privately
  clone        Clone package(s) installed publicly into the private packages database
  ghc-pkg      Invoke the ghc-pkg program to run arbitrary action on private packages
  cabal        Invoke the cabal-install or Setup.{hs|lhs} program to run arbitrary action on private packages
  import       Build another package with respect to this package's private packages database and installation path
  install      Short-cut for cabal install command
  configure    Short-cut for cabal configure command
  build        Short-cut for cabal build command
  help         Help about commands

For more information about a command use
  capri COMMAND --help

Typical steps of building Haskell projects with Capri:
  capri bootstrap
  capri clone
  capri configure
  capri build
  capri install

Building Executables with Capri

This chapter covers the general scenario of building executables using Capri. We will call a Cabal package targeting one or more executables, containing its own private package database and build with use of Capri "the project". All other Cabal packages involved in building of the project will be referred to as just "packages".

Layout of Capri Files

Capri keeps its files under the .capri subdirectory of the project's root directory. Private packages database is located in .capri/packages, and compiled packages are installed in .capri/install subdirectories. Thus, typical location of executables built is .capri/install/bin relative to the project's root.

Bootstrapping Private Packages Database

Building of a package cannot start with entirely empty packages database: several essential packages have to be installed in order to build the project:

   base
   ffi
   ghc-prim
   integer-gmp
   rts

It is assumed that some minimal GHC installation that contains at least these packages is available to the developer who is using capri.

The capri bootstrap command creates the private packages database and installation directory. Next, it clones the above mentioned packages into the private database (actual versions may vary). The capri list command may be used to verify that all packages have been installed properly, and the project is ready to build.

Building and Installation

The easiest way to build a project with Capri is just to type a shortcut command:

capri install

at the shell prompt once the private packages database has been bootstrapped. This results in running cabal install command within the project's top directory, with GHC_PACKAGE_PATH environment variable set properly, and --package-db and --prefix options supplied. If any custom options are needed, another (more flexible) form of this command may be issued:

capri cabal -- install <any options and parameters>

Note the double hyphen after cabal: anything following it will never be treated as options, and will be passed to the cabal-install program.

Although the install command covers package configuration and building, two more shortcut commands are available: capri configure and capri build.

Cloning Already Compiled Packages

Cloning was mentioned earlier in the Bootstrapping paragraph. Any of the packages installed in the global or user package database can be "cloned" into the private packages database of the project.

Technically cloning is equivalent to running the ghc-pkg describe <package-name> command piping its standard output to the ghc-pkg register command while the first command runs with GHC_PACKAGE_PATH set to access the global and user package databases, and the second runs with GHC_PACKAGE_PATH set to access the project private packages database.

All dependencies required by the package being cloned have to have been installed in the project's private packages database (with exact ABI hashes), otherwise cloning will not succeed. Although ghc-pkg will suggest using the --force option, the capri clone command cannot pass this option to ghc-pkg.

Importing Local Source Packages

Cabal-install is capable of automatic chasing project dependencies, downloading, compiling, and installing their code. If however a package the project depends upon is not on Hackage or any other repository known to Cabal-install, the only way to bring it into the scope of the project's private package database is to manually compile it. This however should be done with respect to the project's private package configuration: all additional dependencies should be looked up in and installed into the project's packages database as well.

The capri import command serves this purpose. Its typical syntax is

capri import directory [-- command options]

The command is equivalent to running the cabal install in the other package's directory, but with GHC_PACKAGE_PATH set to the project's packages database, also supplying the --package-db and --prefix options as needed.

Simply typing capri import directory without any additional options results in execution of cabal install in directory. Note however that if double hyphen is used, command line parameters to the right of it should contain a command (configure, install, etc.)

Advanced Topics

Running ghc-pkg and cabal-install

The paragraphs above described shortcut commands (e. g. capri install or capri list) which execute cabal-install or ghc-pkg programs with predefined set of options. For more complex tasks such as manual unregistering of packages, or building the project with specific options, capri has two commands that allow running cabal-install or ghc-pkg with any parameters, ensuring at the same time that the project's private package database and installation prefix are addressed correctly.

These commands are capri ghc-pkg and capri cabal. Their syntax is similar:

capri [cabal|ghc-pkg] -- commands and options

Note the use of the double hyphen. It separates command line arguments that capri tries to interpret as options from command line arguments that will be passed to the program (cabal-install or ghc-pkg) to run.

This can be illustrated by these examples (compare the output, only few top lines shown):

$ capri cabal --help
capri cabal -- <cabal or Setup command options>
 -h --help            Show this help text
 -D --omit-package-db Omit the --package-db option for cabal commands that do
                      not understand it
 -P --omit-prefix     Omit the --prefix option for cabal commands that do not
                      understand it
 -S --setup           Use the Setup.{hs|lhs} installation program instead of
                      Cabal-install
..........................

vs.

$ capri cabal -- --help
This program is the command line interface to the Haskell Cabal infrastructure.
See http://www.haskell.org/cabal/ for more information.

Usage: cabal COMMAND [FLAGS]
   or: cabal [GLOBAL FLAGS]

Global flags:
 -h --help            Show this help text
 -V --version         Print version information
    --numeric-version Print just the version number
..........................

For example, if a particular package needs to be installed into the project's private packages database, and it can be downloaded by cabal-install, the following command will do:

capri cabal -- install package-name

If a package needs to be unregistered from the project's private packages database, use this command:

capri ghc-pkg -- unregister

and the --force option may be supplied as well.

Both cabal-install and ghc-pkg will be run with the GHC_PACKAGE_PATH environment variable set to the project's packages database. The capri cabal command has two additional options, -D and -P. Use them to omit the --package-db and --prefix options that would normally be passed to cabal-install: some of its commands do not understand these options, e. g.:

capri -DP cabal -- check

since cabal check would fail if any of these options appeared on its command line.

Running Setup.{hs|lhs} Instead of Cabal-Install

Capri commands import and cabal have additional option, -S or --setup. If used, capri will execute runghc Setup instead of cabal. This may pose a chicken-and-egg problem: typical Setup program needs the Cabal library to be in scope; Cabal itself has dependencies with their own Setup programs. So this option is not expected to be used frequently, perhaps in some marginal cases, mostly for buildability testing.

Case Study: Building Capri with Capri

Let's build capri with itself. Below portions of the build session transcript is shown.

capri$ ls -a
.  ..  capri.cabal  dist  LICENSE  Main.hs  Setup.hs

capri$ capri bootstrap
Reading package info from stdin ... done.
Reading package info from stdin ... done.
Reading package info from stdin ... done.
Reading package info from stdin ... done.
Reading package info from stdin ... done.
capri$ ls -a
.  ..  .capri  capri.cabal  dist  LICENSE  Main.hs  Setup.hs
capri$ capri list
.capri/packages
   base-4.2.0.1
   ffi-1.0
   ghc-prim-0.2.0.0
   integer-gmp-0.2.0.1
   rts-1.0
capri$ capri install
Resolving dependencies...
Configuring array-0.3.0.1...
Preprocessing library array-0.3.0.1...
Building array-0.3.0.1...
.....
Building containers-0.3.0.0...
.....
Building Cabal-1.8.0.6...
.....
Registering Cabal-1.8.0.6...
.....
Configuring capri-0.1...
Preprocessing executables for capri-0.1...
Building capri-0.1...
[1 of 2] Compiling Paths_capri      ( dist/build/autogen/Paths_capri.hs, dist/build/capri/capri-tmp/Paths_capri.o )
[2 of 2] Compiling Main             ( Main.hs, dist/build/capri/capri-tmp/Main.o )
Linking dist/build/capri/capri ...
Installing executable(s) in
.capri/install/bin
capri$ capri list
.capri/packages
   Cabal-1.8.0.6
   array-0.3.0.1
   base-4.2.0.1
   containers-0.3.0.0
   directory-1.0.1.1
   ffi-1.0
   filepath-1.1.0.4
   ghc-prim-0.2.0.0
   integer-gmp-0.2.0.1
   old-locale-1.0.0.2
   old-time-1.0.0.5
   pretty-1.0.1.1
   process-1.0.1.3
   rts-1.0
   unix-2.4.0.2

So, the transcript above shows build process not differing much from the use of Cabal-install.

Case Study: Building Darcs with Capri

Darcs is a much more complex project with numerous dependencies. This case study illustrates the building process. It does not go as smoothly as with building capri; it also highlights some things packages developers might consider for the future development.

darcs-2.4.4$ capri bootstrap
Reading package info from stdin ... done.
Reading package info from stdin ... done.
Reading package info from stdin ... done.
Reading package info from stdin ... done.
Reading package info from stdin ... done.
darcs-2.4.4$ capri cabal -- install --flags='http -curl'
Resolving dependencies...
cabal: cannot configure darcs-2.4.4. It requires base ==3.*
For the dependency on base ==3.* there are these packages: base-3.0.3.1 and
base-3.0.3.2. However none of them are available.
base-3.0.3.1 was excluded because of the top level dependency base -any
base-3.0.3.2 was excluded because of the top level dependency base -any

First, note that the capri cabal command uses a double-hyphen form because build flags have to be passed to cabal-install. Second, the process needs manual intervention: base-3 has to be installed manually.

darcs-2.4.4$ capri clone base-3*
Reading package info from stdin ... done.
base-3.0.3.2: dependency "syb-0.1.0.2-0917873f366b0be90a48082271223b4e" doesn't exist (use --force to override)

Another dependency has to be installed in order to install base-3.

darcs-2.4.4$ capri clone syb
Reading package info from stdin ... done.
darcs-2.4.4$ capri clone base-3*
Reading package info from stdin ... done.

Now continuing...

darcs-2.4.4$ capri cabal -- install --flags='http -curl'
Resolving dependencies...
Configuring array-0.3.0.1...
Preprocessing library array-0.3.0.1...
Building array-0.3.0.1...
Registering zlib-0.5.2.0...
Installing library in
.capri/install/lib/zlib-0.5.2.0/ghc-6.12.2
.....
Registering zlib-0.5.2.0...
cabal: Error: some packages failed to install:
darcs-2.4.4 depends on hashed-storage-0.4.13 which failed to install.
hashed-storage-0.4.13 failed during the configure step. The exception was:
user error (The package requires Cabal library version -any && >=1.6 but no
suitable version is installed.)
haskeline-0.6.2.2 failed during the configure step. The exception was:
user error (The package requires Cabal library version -any && >=1.6 but no
suitable version is installed.)
random-1.0.0.2 depends on time-1.2.0.3 which failed to install.
time-1.2.0.3 failed during the configure step. The exception was:
user error (The package requires Cabal library version -any && >=1.6 but no
suitable version is installed.)
darcs-2.4.4$ capri list
.capri/packages
   HTTP-4000.0.9
   array-0.3.0.1
   base-3.0.3.2
   base-4.2.0.1
   binary-0.5.0.2
   bytestring-0.9.1.7
   containers-0.3.0.0
   dataenc-0.13.0.2
   directory-1.0.1.1
   extensible-exceptions-0.1.1.2
   ffi-1.0
   filepath-1.1.0.4
   ghc-prim-0.2.0.0
   html-1.0.1.2
   integer-gmp-0.2.0.1
   mmap-0.4.1
   mtl-1.1.0.2
   network-2.2.1.7
   old-locale-1.0.0.2
   old-time-1.0.0.5
   parsec-2.1.0.1
   process-1.0.1.3
   regex-base-0.93.2
   regex-compat-0.93.1
   regex-posix-0.94.2
   rts-1.0
   syb-0.1.0.2
   terminfo-0.3.1.2
   unix-2.4.0.2
   utf8-string-0.3.6
   zlib-0.5.2.0

So far, we failed on hashed-storage and two other packages that need the Cabal library in scope, yet cabal-install did not install it automatically.

darcs-2.4.4$ capri cabal -- install Cabal
Resolving dependencies...
Configuring pretty-1.0.1.1...
Preprocessing library pretty-1.0.1.1...
.....
Registering Cabal-1.8.0.6...

Now, continuing...

darcs-2.4.4$ capri cabal -- install --flags='http -curl'
Resolving dependencies...

/tmp/hashed-storage-0.4.1329214/hashed-storage-0.4.13/Setup.hs:13:7:
    Could not find module `System':
      Use -v to see a list of the files searched for.
[1 of 1] Compiling Main             ( /tmp/haskeline-0.6.2.229214/haskeline-0.6.2.2/Setup.hs, /tmp/haskeline-0.6.2.229214/haskeline-0.6.2.2/dist/setup/Main.o )
Linking /tmp/haskeline-0.6.2.229214/haskeline-0.6.2.2/dist/setup/setup ...
Configuring haskeline-0.6.2.2...
.....
Registering random-1.0.0.2...
cabal: Error: some packages failed to install:
darcs-2.4.4 depends on hashed-storage-0.4.13 which failed to install.
hashed-storage-0.4.13 failed during the configure step. The exception was:
ExitFailure 1

We still cannot install hashed-storage. Note the missing System module which belongs to the haskell98 package. It is needed by the Setup program of hashed-storage.

darcs-2.4.4$ capri cabal -- install haskell98
Resolving dependencies...
Configuring haskell98-1.0.1.1...
.....
Registering haskell98-1.0.1.1...

Now, continuing...

darcs-2.4.4$ capri cabal -- install --flags='http -curl'
Resolving dependencies...
[1 of 1] Compiling Main             ( /tmp/hashed-storage-0.4.1330334/hashed-storage-0.4.13/Setup.hs, /tmp/hashed-storage-0.4.1330334/hashed-storage-0.4.13/dist/setup/Main.o )
Linking /tmp/hashed-storage-0.4.1330334/hashed-storage-0.4.13/dist/setup/setup ...
Configuring hashed-storage-0.4.13...
Preprocessing library hashed-storage-0.4.13...
Preprocessing executables for hashed-storage-0.4.13...
Building hashed-storage-0.4.13...
.....
Installing executable(s) in .capri/install/bin
Registering darcs-2.4.4...
darcs-2.4.4$ .capri/install/bin/darcs --version
2.4.4 (release)
darcs-2.4.4$ capri list
/home/dima/src/darcs-2.4.4/.capri/packages
   Cabal-1.8.0.6
   HTTP-4000.0.9
   array-0.3.0.1
   base-3.0.3.2
   base-4.2.0.1
   binary-0.5.0.2
   bytestring-0.9.1.7
   containers-0.3.0.0
   darcs-2.4.4
   dataenc-0.13.0.2
   directory-1.0.1.1
   extensible-exceptions-0.1.1.2
   ffi-1.0
   filepath-1.1.0.4
   ghc-prim-0.2.0.0
   hashed-storage-0.4.13
   haskeline-0.6.2.2
   haskell98-1.0.1.1
   html-1.0.1.2
   integer-gmp-0.2.0.1
   mmap-0.4.1
   mtl-1.1.0.2
   network-2.2.1.7
   old-locale-1.0.0.2
   old-time-1.0.0.5
   parsec-2.1.0.1
   pretty-1.0.1.1
   process-1.0.1.3
   random-1.0.0.2
   regex-base-0.93.2
   regex-compat-0.93.1
   regex-posix-0.94.2
   rts-1.0
   syb-0.1.0.2
   terminfo-0.3.1.2
   time-1.2.0.3
   unix-2.4.0.2
   utf8-string-0.3.6
   zlib-0.5.2.0

Finally we got to build darcs.