(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/
[email protected]
_______________________________________________
Haskell-platform mailing list
[email protected]
http://projects.haskell.org/cgi-bin/mailman/listinfo/haskell-platform