Cabal + Package = Cabbage
In a directory with a
.cabal file, run
cabbage to build Nix
expressions for every dependency pinned to a specific set of versions
identified by the cabal solver. Next, run
nix-shell --command 'sh $setup' to ensure all dependencies are available in the Nix store and
are linked into the cabal sandbox in the current development directory
(this sandbox will be created for you if one doesn't exist). From this
point on, you can
cabal configure, etc. as you normally would with
cabal sandbox development.
To compile a library from hackage and
cache it in the Nix store, run
cabbage pandoc (to install, e.g., the
pandoc package). This does not link the named package in your Nix
environment, but makes the package available for re-use in subsequent
builds. If the named package includes executables that you do want
to link into your environment, follow the instructions in the last
line of output from the cabbage command (i.e.
To set flags for any package involved in a build, create a file
cabbage.config in your project's root directory. The file format
looks like this,
flags: PackageName: foo -bar
This will set flag
True and flag
False for the
cabbage tool will not overwrite a
shell.nix if one
exists, so, if you want
cabbage to generate a fresh default
shell.nix, delete the old one first.
See the overview section of the source code for more information.
The Nix packages collection,
nixpkgs, is geared towards supporting
NixOS. There is, therefore, an emphasis on maintaining a single set of
chosen versions of packages that NixOS users can expect will work
together. In the Haskell development world, on the other hand, the
cabal build system goes to great lengths to support the
specification of dependencies with specific versions or version
A limitation of the support for multiple versions of Haskell packages has been GHC's use of package databases populated by packages identified by names and version numbers. An example problem is that a record of which versions of its dependencies a package was built against is not reflected in the package's name or version number. This leads to situations where upgrading packages for one project breaks packages used for an entirely separate project. Unacceptable!
cabal has gained support for sandboxes that permit
the user to maintain distinct package databases for different
projects. These work very well, but have the drawback that they end up
requiring the user to recompile common packages again and again
because each package must be freshly compiled for each sandbox it is
to be used in, no matter if the results of those compilations are all
Cabbage uses the Nix tooling to identify packages not only by their name, version, and source code, but also by the versions of dependencies they are built against. All of the distinct ways of producing a compiled library are kept in the Nix store, but truly redundant recompilations are avoided.
I wish I could take credit for the name
cabbage, but it is entirely
due to Shae Erisson (shapr).