Haskell Cabal: locally fix a broken package DL'ed from Hackage - haskell

Suppose that I ran cabal sandbox init .. cabal install -j some-package and got a build failure in one of dependencies of some-package. One way to solve this is I notify the author of the failure and then wait for them to release a new version, but the process can sometimes be too slow. When the reason of the failure is obvious (which is often the case,) I want to launch my text editor and fix it by myself.
However when I ran find(1) for the filename from the error log in .cabal-sandbox cache directory, I could find no .hs files. Does the cabal command remove the entire source directory when GHC successfully or unsuccessfully finishes its execution? How can I intrude into cabal's task executions? Or, are there any standardized way to achieve my original goal of fixing software packages from Hackage by myself?

You can download package source with cabal get <package> then fix it and install into sandbox with cabal install <package-dir>.
E.g.
$ cabal get split
Unpacking to split-0.2.2/
$ vim split-0.2.2/split.cabal
$ cabal install ./split-0.2.2

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.

How to add documentation after packages have already been installed?

I have installed a bunch of packages to the snapshot database. I would now like a local copy of their documentation (even better if it's with hyperlinked source). Is there a way I can tell stack to run haddock on all of them?
EDIT (copied from my answer):
It seems that the obvious stack haddock package will install haddock for the package, so
$ cd ~/.stack/snapshots/x86_64-linux/lts-3.0/7.10.2/doc
$ stack haddock *
seems to do what I want, with two downsides:
I'll still need to remember to pass the --haddock flag to every build (there isn't a ~/.stack/config file, is there?)
It seems to rebuild them; is there a way to avoid that?
It seems that the obvious stack haddock package will install haddock for the package, so
$ cd ~/.stack/snapshots/x86_64-linux/lts-3.0/7.10.2/doc
$ stack haddock *
seems to do what I want, with two downsides:
I'll still need to remember to pass the --haddock flag to every build (there isn't a ~/.stack/config file, is there?)
It seems to rebuild them; is there a way to avoid that?
Step 1. Download and build the newest haddock. The build instructions are
in README.md.
git clone https://github.com/haskell/haddock.git
cd haddock
cabal sandbox init
cabal sandbox add-source haddock-library
cabal sandbox add-source haddock-api
cabal install --dependencies-only
cabal build
Then install the new haddock as haddock.real
cp dist/build/haddock/haddock /some/bin/dir/haddock.real
Step 2. Create a wrapper script named haddock:
#!/bin/sh
/some/bin/dir/haddock.real --hyperlinked-source "$#"
Don't forget to make it executable and put it in your path.
Step 3. Download and build standalone-haddock:
mkdir build-standalone-haddock
git clone https://github.com/feuerbach/standalone-haddock.git
cd standalone-haddock
cabal build
cp dist/build/standalone-haddock/standalone-haddock /some/bin/dir/
An example of how to use standalone-haddock:
mkdir temp
cd temp
cabal get heredoc-0.2.0.0
standalone-haddock -o doc heredoc-0.2.0.0
Then open doc/heredoc/index.html in your browser.
When you navigate to a type definition you should see a Source link on the right and that will bring you to the new hyperlinked source.

cabal sandbox with stackage

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

How can I change the directory where cabal stores the documentation

I installed a custom Haskell toolchain with the prefix $HOME/usr, so the compiler lives in $HOME/usr/bin/ghc and the documentation in $HOME/usr/share/doc/ghc/.... The toolchain consists of a ghc installation, a cabal installation and all the libs you need. I set up $PATH in a way, that all these programs are in it. There is no other installation of these tools on my system.
Now I tried to install some other libraries. But I always got the same error when cabal tried to install the documentation:
~$ cabal install --global binary
Resolving dependencies...
Configuring binary-0.5.0.2...
Preprocessing library binary-0.5.0.2...
Building binary-0.5.0.2...
... snip ...
Registering binary-0.5.0.2...
cabal: /usr/local/share/doc: permission denied
How can I tell cabal where the documentation should live? I don't want to give this information again and again in the shell, so the best would be a config file. I want to have all the haskell related stuff in my home tree, to avoid destroying my system with a wrong command.
Why are you installing with "--global"? By default this would put everything in /usr/local/. If you do a standard per-user install the docs will be installed into your home directory and it should work fine.
That being said, this is configurable via a file. The cabal config file is typically located at ~/.cabal/config/. Here's the relevant section of mine:
install-dirs global
-- prefix: /usr/local
-- bindir: $prefix/bin
-- libdir: $prefix/lib
-- libsubdir: $pkgid/$compiler
-- libexecdir: $prefix/libexec
-- datadir: $prefix/share
-- datasubdir: $pkgid
-- docdir: $datadir/doc/$pkgid
-- htmldir: $docdir/html
-- haddockdir: $htmldir
You can make whatever changes you like, just be sure to uncomment the lines. There is also an "install-dirs user" section, which is used in per-user installs.
I agree with the poster. Why is there no clear documentation for how to do
cabal install package --global
that prompts for sudo when permission is needed?
Doing
sudo cabal install package
is a bad idea because then you're building packages as root. And you have to allow an internet connection to write to a file owned by root (you will have to populate /root/.cabal or something like that).
Here is a good reason why one would want to do this:
If I install ghc and the haskell platform through my linux package manager (there are good reasons for this ;), then if I do cabal install package
it will not recognize the packages that globally recognized.
Well, someone actually posted a(n almost annoyingly) detailed description of how to do global installations (with either --global or install-dirs global) without running into permission errors. The trick is to use root-cmd sudo in the cabal config file.
See,
http://jdgallag.wordpress.com/2011/05/14/cabal-install-to-global-using-sudo-but-do-not-build-as-root/

Resources