Building Haskell Projects
For this class, we recommend you use the new Stack Haskell build system. You will see many references to Cabal and cabal-install
on the Internet for Haskell projects. This document tries to quickly explain the situation.
Our motivation for recommending Stack is that we believe it is easier for beginners to work with, particularly as it manages the version of GHC used so that you aren't reliant on your OS package manager.
We will be using GHC 7.10
throughout this course.
Stack
Stack is a build system for Haskell that aims to give you extremely reproducible builds. To do this, it manages (and freezes) all your dependencies and the version of GHC being used for your project.
Stack is backed by the Stackage package system. Stackage uses the concept of 'snapshots', where all packages part of the same snapshot are meant to be compatible with each other. When installing a new package, you don't choose which version to install, instead when starting a project using Stack, you choose which Stackage snapshot to use. After that, all package versions are fixed, determined upstream by Stackage's snapshot mechanism.
Stack vs Cabal
Cabal is the package description format for Haskell. It describes what a package is and how packages interact with the language. It also provides common infrastructure for building and distributing packages.
Traditionally, Haskell programmers used a tool called cabal-install
that knows how to build a Cabal package. cabal-install
also interacts with a package hosting website, Hackage, for retrieving dependencies during the build process.
Each time a client of cabal-install
configured a package to prepare it for building or installation, cabal-install
would perform dependency resolution, resolving which version of packages A, B and C to use, such that all packages chosen are compatible with each other and all dependencies are satisfied. This works, but led to a problem known as 'cabal-hell' (similar to DLL-hell on Windows), where cabal-install
would fail to find a way to solve the dependency problem. This was particularly bad due to the use a single global package installation location, meaning all projects had to have compatible versions of packages. cabal-install
later adopted a 'sandbox' strategy where a project could install dependencies local to the project, which helps greatly.
However, cabal-install
doesn't do a great job of giving developers reproducible builds. It may resolve package A to version 1.0 on one developers machine, and resolve package A to version 1.1 on a different developers machine if run at different times. It also doesn't manage GHC itself, considering that out of scope.
Stack and it's backing website, Stackage, instead solve this problem globally and once for everyone. They create a set of packages called a 'snapshot' where they try to guarantee that all packages part of a snapshot are compatible with each other and have all their dependencies contained in the snapshot. A project using Stack simply declares the snapshot they are using, and no dependency resolution needs to be performed. Stack also manages the version of GHC used as part of a snapshot.
Stack in Relation to Cabal
Stack doesn't replace Cabal, but does replace cabal-install
. It also doesn't replace Hackage, but provides 'snapshots' of it through Stackage.
Installing
See stack documentation, but we present the cliffs notes below.
Apple OS X
Probably the easiest way to install is using homebrew:
brew install haskell-stack
Arch Linux
Stack is only available in AUR at this moment. You'll likely need the following two packages:
- https://aur4.archlinux.org/packages/libtinfo/
- https://aur4.archlinux.org/packages/haskell-stack/
Ubuntu
For Ubuntu 15.10:
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 575159689BEFB442
echo 'deb http://download.fpcomplete.com/ubuntu wily main' |sudo tee /etc/apt/sources.list.d/fpco.list
sudo apt-get update && sudo apt-get install stack -y
Configure Stack
First, configure some defaults:
$ vim ~/.stack/config.yaml
This file should look something like:
templates:
params:
author-email: rlloyd@richardlloyd.com
author-name: Richard Lloyd
copyright: Richard Lloyd
github-username: rlloyd
category: web
You can override these defaults on the command line:
stack new proj -p "category: testing"
Using Stack
stack new my-project
cd my-project
stack setup
stack build
stack exec my-project-exe
You can also load your project in GHCi (A Haskell REPL):
stack ghci
Or run your test suite:
stack test