installed haskell package layout

Mark Lentczner markl at glyphic.com
Wed Dec 1 10:55:50 EST 2010


(This is about how cabal lays out installed packages... but it is motivated by concerns when packaging an installer for Haskell Platform. I thought it might be of interest to other Haskell Platform packagers...)

I've been looking at cabal's default layout of installed packages, as implemented in Distribution.Simple.InstallDirs. On non-Windows systems this ends up like:

 <prefix>          -- /usr/local if --global, ~/.cabal if --user
   bin             -- binaries ($bindir)
   lib             -- ($libdir)
     <pkgid>
       <compiler>  -- libraries & .hi files ($libdir/$libsubdir, $dynlibdir)
         include   -- include files ($includedir)
   libexec         -- private binaries ($libexecdir)
   share           -- ($datadir)
     <pkgid>       -- data files ($datadir/$datasubdir)    
     doc
       <pkgid>     -- documentation ($docdir)
         html      -- html doc ($htmldir, $haddockdir)
     man           -- man pages ($mandir)

There seem to be several problems with this layout:

1) It doesn't truly support multiple compilers (or even versions of the same compiler), because while the libraries and .hi files can be multiply resident, things like the doc and the binaries only get the last set built. But, the doc for a package could change depending on which compiler it is compiled for (perhaps not all of the API is available under an older version...)

2) If you want to remove a package, you've got to ferret all the pieces out of global bin, libexec, and man directories, and there are three separate directories named with <pkgid> to remove.

3) If you want to remove a compiler, you need to remove all the <compiler> directories out of all the packages. Then, if a package has no other <compiler> subtrees, remove that package (see #2).

Most other language library sets on other platforms seem to place things under per interpreter version sub-trees[1]. In keeping with that, and trying to better support the three use cases above, I developed and plan to use for the Mac install of HP:

 <prefix>          -- /usr/local/haskell and ~/.cabal on linux,
                      /Library/Haskell and ~/Library/Haskell on OS X
   <compiler>
     <pkgid>
       bin         -- binaries ($bindir)
       lib         -- libraries & .hi files ($libdir, $libdir/$libsubdir, $dynlibdir)
         include   -- include files ($includedir)
       libexec     -- private binaries ($libexecdir)
       share       -- data files ($datadir, $datadir/$datasubdir)    
       doc         -- documentation ($docdir)
         html      -- html doc ($htmldir, $haddockdir)
         man       -- man pages ($mandir)
     bin           -- symlinks to binaries
     doc
       html        -- master index of html doc
       man         -- symlinks to man pages
   current         -- symlink to current <compiler>
   bin             -- symlink to current/bin      
   doc             -- symlink to current/doc

The first big advantage is that a package can be installed for multiple compilers easily, and independently. The second is that removing an older compiler, and all the package versions for it, is really easy. And removing a package is quite a bit easier: just remove the <pkgid> under each <compiler>.

This structure is similar to what I proposed for Mac OS X awhile back[2], and have been running on my systems for about a year. Also, the GHC distribution, uses a somewhat different layout for the packages it includes[3], but shares with this structure the ordering of <compiler>/<pkgid> rather than the other way 'round. This structure also has no need for the special $libsubdir and $datasubdir processing (though I may be misunderstanding the need for those).

All these paths can be specified at configure time for a given haskell package - I'm already able to have the Mac OS X installer of Haskell Platform (HP) do this for the packages it installs. However, without a patched Cabal, then packages the user installs --global post-Haskell Platform installation will most likely be in a different location and layout. GHC's package db has no problem with this, but it isn't tidy. What I'm aiming at is that installing HP be identical to installing GHC and then installing the packages yourself.

Of course, I don't want to ship a patched Cabal with HP - sort of violates the spirit of the fixed version guarantee of HP. So for now, I won't, and the HP installed packages will be in a somewhat different layout and location that then user installed package's --global packages by default.

A solution is if rather then encoding a platform's default paths in the logic of Distribution.Simple.InstallDirs, it were read from a file from cabal's datadir (much like cabal-install does ~/.cabal/config). This would allow platform packagers to set a common location and layout of things for a given platform without having to patch Cabal.

In the meantime, an option would be to wrap the installed "cabal" binary on the user's system with a script that, if not already present, puts a .cabal/config file in the user's home dir that matches the HP package layout before exec'ing cabal.

Thoughts?

	- Mark

[1] See, for example, how Python installs things under /usr/lib/python<version>, and Perl uses /usr/lib/perl5/<version>.

[2] http://www.haskell.org/haskellwiki/Mac_OS_X_Common_Installation_Paths

[3] GHC's included packages are laid out as:

 <prefix>          -- /Library/Framewroks/GHC.framework/Versions/<ver>/usr on OS X
   bin             -- scripts (named same as binaries)
   lib             -- ($libdir)
     <compiler>    -- binaries ($bindir)
       <pkgid>     -- libraries & .hi files,  ($libdir/$libsubdir, $dynlibdir)
         include   -- include files ($includedir)
   libexec         -- private binaries ($libexecdir)
   share           
     <pkgid>       -- data files ($datadir)    
     doc
       ghc
         html
           libraries
             <pkgid> -- documentation & html doc ($docdir, $htmldir, $haddockdir)
     man           -- man pages ($mandir)

-------------------------------
Mark Lentczner
http://www.ozonehouse.com/mark/
mark at glyphic.com





More information about the Haskell-platform mailing list