cabal sandbox with stackage - haskell

I want to point my global cabal config to use stackage LTS only.
Does cabal sandbox provide any value in that case?
As I understand there should be no cabal hell anymore as all projects will use a predetermined set of package that are guaranteed to build together.
Is there any way to prebuild all stackage LTS packages to speed up all future project builds?

Why Sandboxes?
I think there are still benefits to using sandboxes:
Not every package is in stackage, if you end up using a library or depending on something that is not part of stackage you have no guarantee that it will work with the rest of your packages.
Sandboxes have other uses outside of just preventing cabal hell. Their other main use is to be able to add local directories as sources of packages. For example, lets say you have checked out two packages on your local disk ~/code/a and ~/code/b and lets say that b depends on a. If you want to check that b works with some changes you've made to a you can add your local a checkout as a source to b's cabal sandbox.
cd ~/code/b
cabal sandbox add-source ~/code/a
cabal build
Pre-build LTS Packages
If you are set on pre-building all of your packages you can use the following to install all the packages listed in a cabal.config file.
cat cabal.config | sed -rn 's/^.* ([^ ]+) ==.*/\1/gp' | xargs cabal install

Related

Why do cabal configure?

In the Cabal User Guide it says that Cabal is often compared with autoconf and automake since the command line interface for actually configuring and building packages follows the same steps steps:
./configure --prefix=...
make
make install
compared to
cabal configure --prefix=...
cabal build
cabal install
My understanding is that ./configure uses a config file (produced by autoconf) to adapt the make process to the environment in which it will run and also to check dependencies. So ./configure therefore always have an "input" to conform to. But if cabal configure is not given any arguments what does it do, and why is it necessary before running cabal build?
The cabal configure step does at least two things I know of:
Check that the package description parses OK.
Check that all required dependencies are already installed (and report an error if not).
Basically it's running the constraint solver to decide exactly which packages you're going to build against. (E.g., if you have several versions of ByteString installed, which version are you going to use? Well it might depend on which version the packages you depend on are expecting...)
Also I believe it's possible to supply options at configure time which change exactly which features of the package get built (but I don't have experience with this).
I think originally you had to call configure before you could call build, but I believe now the cabal command-line tool does that step for you automatically in many cases. (E.g., cabal run now seems to automatically reconfigure if the package description file is newer than the configuration DB.)

How to create a Cabal Sandbox

I want to build an environment for tutorial programs for Haskell, as I want to try and learn the language. So I read about Cabal and already have it on my machine, because I updated pandoc sometimes. I followed some tutorials, which state that you should run:
$ cabal sandbox init
$ cabal install --only-dependencies
$ cabal build
To have the environment set up. However, if I try so, I receive the following message:
$ cabal sandbox init
Writing a default package environment file to
/home/xiaolong/development/Haskell/cabal.sandbox.config
Using an existing sandbox located at
/home/xiaolong/development/Haskell/.cabal-sandbox
(Output of ls command)
$ ls
cabal.sandbox.config
And then:
$ cabal install --only-dependencies
cabal: Error reading local package.
Couldn't find .cabal file in: .
Huh? Suddenly there needs to be a .cabal file? This is puzzling to me. What steps do I need to take to get an environment, in which I can simply install packages and then use that environment to run code of any tutorials I choose?
This is another tutorial suggesting the described workflow. Something is there I am missing.
(I am under the impression, that cabal sandboxes are comparable to python virtualenvs, being useful in the way, that one doesn't need to install packages system-wide, but can instead install them in a directory and then use that environment to run programs.)
You need to have a cabal file inside it which describes your project's name, package dependencies, license etc. A cabal file can be generated using cabal init which is followed by a series of question you have to answer.
Once the initial cabal configuration file is created, you can go inside the package directory and create sandbox inside it using the commands you have described above.
You may be also interested in Stack which is another alternate (better, if you would ask me :)) tool for developing Haskell projects.

Haskell Platform vs homebrew

I recently downloaded the Haskell Platform from the Haskell website. Under the suggestion of the newer answers in this, I blindly ran brew install ghc cabal-install and cabal install cabal cabal-install. Did I install two versions of Haskell on my machine? What should I do to fix any problems?
It doesn't necessarily lead to problems to have multiple versions (I think I have three different versions installed). If you need the disk space uninstall one of the two (instructions for the brew one, for the packaged platform it seems you should be able to use the command sudo uninstall-hs but check it yourself first). If you don't mind the lost disk space, you only have to make sure you have your PATH set up correctly, with the directory containing the ghc binary you want to use in your PATH, before the directory of the other one.
Also, cabal install cabal-install (which you might need to run to update cabal) tends to install cabal in a different place than the platform/brew do, so there, again, you need to make sure your PATH is appropriately set. Normally cabal installs executables in ~/.cabal/bin (local installs) or /usr/local/bin (global installs). The directory containing cabal should go before the others, because an old version of cabal might stick around and you want the new one to be found first.
You probably know this but you can use which ghc and which cabal to check the location of the executable actually being used.
To make things even more complicated, lately it's popular to use Stack, which can also install ghc for you (I find this very convenient, everything is kept in a very controlled environment). So depending on your experience/use case this might be worth looking at as well (but if you just want to try Haskell I recommend you stick with the platform or the brew installation).

How to get cabal and nix work together

As far as I understood, Nix is alternative for cabal sandbox.
I finally managed to install Nix, but I still don't understand how it can replace a sandbox.
I understand you don't need cabal using Nix and the wrapped version of GHC; however if you want
to publish a package you'll need at some point to package it using cabal. Therefore, you need to be able to write and test your cabal configuration within NIX. How do you do that?
Ideally, I would like an environment similar to cabal sandbox but "contained" within NIX, is that possible? In fact, what I really would like is the equivalent of nested sandboxes — as I usually work on projects made of multiple packages.
Update about my current workflow
At the moment I work on 2 or 3 independent projects (P1, P2, P3) which are each composed of 2 or 3 cabal modules/packages, let's say for P1: L11, L12 (libraries)
and E11 (executables). E11 depends on L12 which depends on L11. I mainly split the executables from the library because they are private and kept on a private git repo.
In theory, each project could have this own sandbox (shared between its submodules). I tried that (having a common sandbox for L11 L12 and E11), but it's quickly annoying because, if you modify L11, you can't rebuild it because E11 depends on it, so I have to uninstall E11 first to recompile L11.
It might be no exactly the case, but I encounter the similar problem.
This would be fine if I were occasionally modifying L11, but in practice, I changed it more that E11.
As the shared sandbox doesn't work, so I went back to the one sandbox for every package solution. It's working but is less than ideal.
The main problem is if I modify L11, I need to compile it twice (once in L11, and then again in E11). Also, each time I'm starting a new sandbox, as everybody knows, I need to wait a while to get everything package downloaded and recompiled.
So by using Nix, I'm hopping to be able to set up separate cabal "environments" per project, which solves all the issue aboves.
Hope this is clearer.
I do all my development using Nix and cabal these days, and I can happily say that they work in harmony very well. My current workflow is very new, in that it relies on features in nixpkgs that have only just reached the master branch. As such, the first thing you'll need to do is clone nixpkgs from Github:
cd ~
git clone git://github.com/nixos/nixpkgs
(In the future this won't be necessary, but right now it is).
Single Project Usage
Now that we have a nixpkgs clone, we can start using the haskellng package set. haskellng is a rewrite of how we package things in Nix, and is of interest to us for being more predictable (package names match Hackage package names) and more configurable. First, we'll install the cabal2nix tool, which can automate some things for us, and we'll also install cabal-install to provide the cabal executable:
nix-env -f ~/nixpkgs -i -A haskellngPackages.cabal2nix -A haskellngPackages.cabal-install
From this point, it's all pretty much clear sailing.
If you're starting a new project, you can just call cabal init in a new directory, as you would normally. When you're ready to build, you can turn this .cabal file into a development environment:
cabal init
# answer the questions
cabal2nix --shell my-project.cabal > shell.nix
This gives you a shell.nix file, which can be used with nix-shell. You don't need to use this very often though - the only time you'll usually use it is with cabal configure:
nix-shell -I ~ --command 'cabal configure'
cabal configure caches absolute paths to everything, so now when you want to build you just use cabal build as normal:
cabal build
Whenever your .cabal file changes you'll need to regenerate shell.nix - just run the command above, and then cabal configure afterwards.
Multiple Project Usage
The approach scales nicely to multiple projects, but it requires a little bit more manual work to "glue" everything together. To demonstrate how this works, lets consider my socket-io library. This library depends on engine-io, and I usually develop both at the same time.
The first step to Nix-ifying this project is to generate default.nix expressions along side each individual .cabal file:
cabal2nix engine-io/engine-io.cabal > engine-io/default.nix
cabal2nix socket-io/socket-io.cabal > socket-io/default.nix
These default.nix expressions are functions, so we can't do much right now. To call the functions, we write our own shell.nix file that explains how to combine everything. For engine-io/shell.nix, we don't have to do anything particularly clever:
with (import <nixpkgs> {}).pkgs;
(haskellngPackages.callPackage ./. {}).env
For socket-io, we need to depend on engine-io:
with (import <nixpkgs> {}).pkgs;
let modifiedHaskellPackages = haskellngPackages.override {
overrides = self: super: {
engine-io = self.callPackage ../engine-io {};
socket-io = self.callPackage ./. {};
};
};
in modifiedHaskellPackages.socket-io.env
Now we have shell.nix in each environment, so we can use cabal configure as before.
The key observation here is that whenever engine-io changes, we need to reconfigure socket-io to detect these changes. This is as simple as running
cd socket-io; nix-shell -I ~ --command 'cabal configure'
Nix will notice that ../engine-io has changed, and rebuild it before running cabal configure.

Haskell cabal: I just installed packages, but now the packages are not found

Over here is the only reason I can find that packages I'm installing using cabal are not being found by GHC:
This happens when you install a package globally, and the previous packages were installed locally. Note that cabal-install install locally by default [...]
Presumably, "local installation" means putting packages in ~/.cabal/. First question: where are global installs?
I've been running cabal using sudo, so I guess that's a global install? The reason I've been doing this is that it complains about permissions when run without sudo, so this contradicts the statement "cabal-install install locally by default". Second question: how do I install locally and how do I install globally?
Trying to fix this mess, I've been randomly using sudo ghc-pkg unregister and randomly removing stuff from ~/.cabal/. Consequently my package tree is broken, probably locally and globally. Third question: How do I start again?
Edit: I'm running Ubuntu 10.10. I installed the Haskell Platform 2011.
Are you using Windows, OS X or some version of Linux? Are you using the Haskell Platform? Have you had a version of ghc or cabal before? For a Linux distribution, subtleties about your package manager may come in, of course. (Traces of an old ghc in particular, and an old ~/.ghc/ directory can be a source of trouble.)
Here are a few elementary thoughts of the type one goes through on #haskell with such problems. (My comprehension is not completely adequate, of course):
The chief question seems to be, Why you were being invited to do what should be local installs with sudo? A global install (cabal install pony --global) would of course require privileges if ghc and its libraries are in /usr/... or some other protected place, but otherwise sudo vs non-sudo is independent of the place of installation. What you do with cabal install pony --user (--user is the default, in theory) should not require superuser authority. (I have sometimes found on OS X that privileges are requested where the gcc needs to be called, but this has usually been due to curiosities about my setup.) But in any case sudo doesn't affect where cabal is putting them: the implicit --user and explicit --global, and more specific incantations for development, do that.
If you do ghc-pkg list, for example, it will divide the packages into the different places they are registered in according to two or more package.conf.d directories it is summarizing. On my laptop at the moment these are
/Users/applicative/.ghc/x86_64-darwin-7.0.3/package.conf.d/...
for the local things in ~/.cabal/lib/... and the protected
/Library/Frameworks/GHC.framework/Versions/7.0.3-x86_64/usr/lib/ghc-7.0.3/package.conf.d
for things that were installed globally with the Haskell Platform installer (this location involves some OS X peculiarities, ghc, ghci and so on are in the woods somewhere, but symlinked to /usr/bin). The conf files for different packages tell you exactly where the libraries were installed. So, for example about the sacred base library,
$ cat base-4.3.1.0-f5c465200a37a65ca26c5c6c600f6c76.conf
tells me:
import-dirs:
/Library/Frameworks/GHC.framework/Versions/7.0.3-x86_64/usr/lib/ghc-7.0.3/base-4.3.1.0
library-dirs:
/Library/Frameworks/GHC.framework/Versions/7.0.3-x86_64/usr/lib/ghc-7.0.3/base-4.3.1.0
In any case, where does ghc-pkg list say your cabal install-ed packages are going? In the ~/.cabal folder, look at the file config. If you haven't edited it, I think the commented and uncommented lines, if they state a preference, are stating the defaults for installation with --global and --user. In the ~.ghc/ directory check out the subdirectory myghcversion/package.conf.d and see if anything is there, which should be the same as what ghc-pkg tells you. (You might study the options for ghc-pkg in general, eg. ghc-pkg check and ghc-pkg recache, if you haven't. You may have installed something in some odd way.)
If you installed ghc and cabal and co. by installing the Haskell Platform with a binary installer or your package manager, which seems like a good idea, it is also a good idea, I think, to keep the Platform libraries as something sacred, and make sure you never install anything globally from Hackage; among other things this is likely to have you overwriting Platform libraries -- though this doesn't seem the difficulty here: it would be more obvious if it were.

Resources