
On 01/03/13 18:24, Max Bolingbroke wrote:
On 1 March 2013 14:15, Ian Lynagh
wrote: On Fri, Mar 01, 2013 at 03:02:41PM +0100, Jan Stolarek wrote:
fixing things. I would like cabal to prevent such things from ever happening, the same way that Linux rpm/deb managers keep packages on the system in a consistent state.
There's one big difference here: rpm/dpkg are only used to install things by the system administrator. But in the case of Cabal, a user could install 'mypackage' (in their user package database) and the next day the sysadmin could install a different instance of 'mypackage' in the global database.
I thought that "cabal install" should be viewed as installing an instance of the requested package by recompiling the whole transitive closure of dependencies from scratch, in a sort of NixOS-like way. Given this view, Cabal's reuse of already compiled and installed packages is purely an optimization that can prevent it from recompiling some things if it is absolutely certain that doing so is unnecessary. The problem then is just that Cabal is currently brokenly unable to handle multiple instances of an installed package with the same name and version.
Cabal comes under fire a lot, so I'd like to point out that it's not just Cabal that can't handle this right now, GHC can't either :-) And various people have been thinking a lot about how to fix it, there was even a SoC project last year to tackle it. The design notes are here: http://hackage.haskell.org/trac/ghc/wiki/Commentary/GSoCMultipleInstances
In this view, the existence of local and global databases is straightforward: packages should always be installed in the most-accessible DB to which you have write permissions (for maximum sharing) and should be sourced from whichever is convenient when they are required.
Right - when the DB is semantically just a cache, it doesn't matter whether stuff is installed in the global or local database. All those problems just go away.
It seems to me that the ideal mental model for "cabal install mylibrary-1.1" is that it appends to a global mapping from package name to version which are essentially the packages that are available when you do "ghc -package mylibrary" and when using ghci. Cabals promise should be that it adds the requested package to the global mapping and then recompiles *everything* on your system as necessary in order to make it possible for every package in that global mapping to be imported simultaneously into a GHCi session.
The new library that you just asked to be installed might be incompatible with some other libraries that you asked to be installed, and yet you want to be able to use them both with GHCi (just not at the same time). I don't think we should prevent the user from doing that. So whether "cabal install foo-1.0" should store some state somewhere that says the user prefers foo-1.0 over other versions of foo is an interesting question. (see the section "Simplistic Dependency Resolution" on the wiki page for some other thoughts on this). One stance is that "cabal install foo-1.0" should do nothing except populate the cache; that is, it is semantically a no-op. To have it modify some state breaks this nice no-op notion. Cheers, Simon