summaryrefslogtreecommitdiffhomepage
path: root/tech/debstablehaskell.mdwn
blob: 700ddf0101f48f38c6dcb28e76994ebb705d10fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
[[!template id=note text="""
Please note that this page has not been updated since early 2015.  I now recommend [[stack|https://github.com/commercialhaskell/stack]].
"""]]

<!-- I'm now [doing -->
<!-- this](http://funloop.org/post/2015-02-10-using-nix-from-arch.html) -->
<!-- (under Debian) because some packages I want don't build with Debian -->
<!-- Wheezy's versions of happy, alex and GHC. -->

[[!toc]]

Rationale
=========

I'm trying to learn the Haskell programming language, and I'm tripping
over the `cabal-install` package management system sufficiently often
that it's putting me off putting time into learning the language. Here
are my requirements for a development environment I'm willing to learn
in:

1.  don't leave Debian Wheezy 32-bit;[[!template id=note text="Debian Jessie will be out soon, but its versions of GHC and the Haskell platform are still very old so upgrading early is not a way out."]]
2.  minimise how often I have to delete all of `~/.cabal` and `~/.ghc`;
3.  when using cabal sandboxes, again, minimise the number of core
    libraries that need to get rebuilt in every sandbox;
4.  be simple enough to integrate cleanly with the existing ways I
    manage my OS installation and the contents of my home directory;
5.  be simple enough that I can understand everything as a Haskell
    beginner and can get things working (again) quickly and get back to
    trying to write Haskell.

In this document I will describe the combination of home directory and
system-wide installations that fit these requirements, and the workflow
for sorting out packages so that I can get on with trying to make my
programs do input and output, and other fun Haskell beginner stuff.

Alternative approaches
----------------------

The following two approaches don't satisfy the requirements given above.

### Do everything manually

This involves having nothing installed system-wide, including the
Haskell Platform. Install GHC and Cabal in `~/local/src` and then
install things into their own sandboxes and add the `.cabal-sandbox/bin`
directories to your `$PATH`. [Someone on reddit
describes](http://www.reddit.com/r/haskell/comments/2al3vx/how_do_you_avoid_the_cabal_hell/ciw92mp)
a balance between installing stuff into `.cabal/bin` and having
sandboxes in which related packages are built and then symlinking those
directories. But this requires lots and lots of rebuilding over and over
and lots of manual `$PATH` additions. System-wide Debian packages
mitigate this.

[This](https://github.com/quchen/cabal-install-bin) might facilitate
such an approach.

Fails (2), (3) and (4).

### Use a clever automatic sandboxing solution

[Halcyon](http://halcyon.sh/) and the [Nix package
manager](https://ocharles.org.uk/blog/posts/2014-02-04-how-i-develop-with-nixos.html)
(which doesn't require the full NixOS) are the projects I've come across
that try to do this. They aim to avoid even more rebuilding than my
approach avoids. The Halcyon author [doesn't want to support 32-bit
Debian](https://github.com/mietek/halcyon/pull/45), and I don't want to
be a Nix early adoptor at the same time as trying to learn how to get my
programs to take input and produce output.

Fails (1) and (5).

Drawbacks of my approach
------------------------

We're living very far away from the edge: we're using GHC 7.4 and a
version of the Haskell Platform from 2012. [Someone on reddit
expresses](http://www.reddit.com/r/haskell/comments/2al3vx/how_do_you_avoid_the_cabal_hell/ciwd33h)
the view that since Haskell moves so fast, you'll end up rebuilding
everything all the time anyway so you can use your favourite packages
from Hackage. The only thing we're not getting from the Debian apt
repositories that we might is `haskell-mode` and `ghc-mod` for Emacs,
since we can have newer versions of those without repeated building.

We're doing a lot of rebuilding of libraries, and we're only avoiding
rebuilding those that come with Debian, which will become less and less
useful as time goes by and Hackage packages depend on newer versions.

This is okay because I'm a Haskell beginner, and I'm not a professional
software engineer, so even if I stick with learning Haskell it's going
to take me years before I'm writing anything that needs fancy
contemporary libraries. And maybe by then the `cabal-install` ecosystem
will have improved. I basically need Hackage only for building fancy
things like [Propellor](http://propellor.branchable.com/) and
[Structured Haskell
Mode](https://github.com/chrisdone/structured-haskell-mode) so it's okay
to sandbox those things and do a load of builds.

System setup
============

Debian packages and dotfiles
----------------------------

Get all our basic libraries installed system-wide:

``` {.nil}
# apt-get install ghc ghc-prof haskell-platform
```

or if you're using [Propellor](http://propellor.branchable.com/):

``` {.haskell}
workstationAptPackages :: Property NoInfo
workstationAptPackages = combineProperties "workstation apt packages"
                         [ Apt.installed ["ghc", "ghc-prof", "haskell-platform"]
                         , Apt.removed   ["haskell-mode", "ghc-mod"]
                         ]
```

Put cabal configuration file in place:

The most important thing here is `require-sandbox: True`. We're not
putting **anything** in `~/.cabal/bin`. So we need to include all
`.cabal-sandbox/bin` directories in our `$PATH`. I build stuff that is
to be built on every machine in `~/local/src`. So for each binary we
have a sandbox in a directory under `~/local/src`, e.g.
`~/local/src/propellor`. This code will prepend those directories to
`$PATH`. It comes from [my
`~/.shenv`](https://github.com/spwhitton/dotfiles/blob/master/.shenv#L36)
which is supposed to be a POSIX-compatible script to set up environment
variables that I can source in `.zshrc`, `.bashrc`, scripts run from
cron, my GNOME and XFCE startup scripts and wherever.

``` {.bash}
for bindir in $(find ~/local/src -path "*/.cabal-sandbox/bin"); do
    PATH="$bindir:$PATH"
done
export PATH
```

Upgrading `cabal-install`
-------------------------

Before doing anything else, we upgrade `cabal-install`. The version of
cabal-install in Wheezy is so old that it doesn't know about sandboxes,
and we don't want to pollute `~/.cabal/bin`. So we cheat and get it from
Jessie:

``` {.nil}
# apt-get install -t testing cabal-install
```

Be sure to have [set up apt
pinning](http://jaqque.sbih.org/kplug/apt-pinning.html) so that this
doesn't pull anything else in from Jessie!

Upgrading `cabal-install` again
-------------------------------

Since we want the smartest dependency resolution we can get, we now
upgrade cabal to the very latest and greatest.

``` {.nil}
$ cabal update
$ cd ~/local/src
$ cabal get cabal-install
$ cd cabal-install-*
$ cabal sandbox init
$ cabal install
```

Restart the shell (`hash cabal` isn't enough because we only just
created the sandbox) and type `cabal --version` to check that the second
decimal is higher than 20. Use `which cabal` to check that it's the one
from `~/local/src`.

Usage for Haskell projects
==========================

Installing other people's programs
----------------------------------

Maybe you want the `ghc-mod` or `structured-haskell-mode` executables
from hackage. Follow the procedure just used for upgrading
`cabal-install` for the second time.

Getting libraries for your project
----------------------------------

This section is a WIP. But some tips:
-   Basic workflow is `cabal init; cabal sandbox init; cabal build`.
-   Use `cabal repl` to launch ghci.
-   When you need a library, first try to find a debian package (the
    name will begin with `[lib]ghc-`).
-   If you can't find it, you can use `cabal install blah` to install
    into the sandbox for testing before adding to the .cabal file as
    a dependency. Try to install all required packages in one go on one
    `cabal install blah1 blah2` command as this gives cabal the best
    chance of getting the dependencies right.
-   Don't be afraid to clear out the sandbox: `rm -rf
     .cabal-sandbox-config .cabal-sandbox; cabal sandbox init`.
-   Try -v3 to enhance cabal's dependency resolution some more.

Sources & further reading
=========================

-   Useful reddit threads
    -   [How to avoid Cabal
        Hell](http://www.reddit.com/r/haskell/comments/2al3vx/how_do_you_avoid_the_cabal_hell/)
    -   [Best practices for avoiding Cabal
        Hell](http://www.reddit.com/r/haskell/comments/2ameew/best_practices_for_avoiding_cabal_hell/)
-   On configuring Emacs
    -   [Using Emacs for Haskell
        development](https://github.com/serras/emacs-haskell-tutorial/blob/master/tutorial.md)
        -- tools [I
        use](https://github.com/spwhitton/dotfiles/blob/master/.emacs.d/init-haskell.el)
    -   [Modern Emacs
        Haskell-Mode](http://blog.hoersten.co/post/110096363794/modern-emacs-haskell-mode)
        -- more experimental tools if you're willing to break out of
        Wheezy etc.
        -   [and the reddit
            thread](https://www.reddit.com/r/haskell/comments/2uspan/modern_emacs_haskellmode/)
-   More advanced stuff
    -   [Comprehensive Haskell
        Sandboxes](http://edsko.net/2013/02/10/comprehensive-haskell-sandboxes/)
-   Background reading
    -   [How we might abolish Cabal Hell, part
        1](http://www.well-typed.com/blog/2014/09/how-we-might-abolish-cabal-hell-part-1/)
    -   [The Cabal of
        Cabal](http://www.vex.net/~trebla/haskell/cabal-cabal.xhtml) (I
        think this is out-of-date)
    -   [Storage and Identification of Cabalized
        Packages](http://www.vex.net/~trebla/haskell/sicp.xhtml)