Managing Projects with the Haskell Tool Stack
Stephen A. Edwards
Columbia University
Fall 2021
The Haskell Stack: Cross-Platform Build Tool
You specify a GHC version and which packages (and versions) to use, then can
build and test your project (executables and libraries).
[Link]
$ stack new my-project
$ cd my-project
$ stack setup
$ stack build
$ stack exec my-project-exe
$ stack run
$ stack install
Files generated by stack new
my-project/
.gitignore Files for git to ignore
LICENSE E.g., BSD3. Add your name
[Link] If you like
[Link] E.g., for github
→ [Link] GHC version, non-standard package details
→ [Link] Build instructions: packages, libraries, versions, etc.
[Link] Generated from [Link] as necessary
[Link] Part of Cabal build system; boilerplate
app/ Source files for executables
→ [Link] Main function for my-project-exe
src/ Source files for libraries
[Link] Sample library file
test/ Unit test files
[Link] Sample test file
YAML Ain’t (a) Markup Language (but it’s almost JSON)
# Single-line comments
key1: value1
key2: # Keys in a group should be distinct
key1: value2 # Value here is a dictionary
key2: 34 # Space-only indentation for grouping
key3:
- list-element # List element here is a string
- list-element # List elements may repeat
key4: [el1, el2] # Alternative syntax for lists
key5:
- item: foo
price: 42
name: "The first name" # Double-quotes forces a string type
- item: bar
price: 17
[Link]: Global build configuration
Main thing here is the “resolver”: a combination of GHC version and versions
for many (2500+) standard packages.
Use Long-Term Support packages from Stackage: [Link]
resolver: lts-16.23
This is GHC-8.8.4 plus containers-[Link], bytestring-[Link], etc.
See, e.g., [Link]
packages:
- .
Optional list of directories (this is the default value).
“There’s one package to be built in the current directory” (see [Link])
[Link] optional fields
extra-deps: # Packages outside the resolver
- acme-missiles-0.3
- git: [Link]
commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
require-stack-version: ">=2.5"
extra-include-dirs: # Searched during builds
- /opt/include
- baz/include
extra-lib-dirs: # Searched during builds
- foo/baz/lib
[Link]: Package-specific build rules
Translated into .cabal files by sparsely-documented hpack
[Link]
name: peng # The main name
version: [Link]
github: "sedwards-lab/peng"
license: BSD3
author: "Stephen A. Edwards"
maintainer: "sedwards@[Link]"
copyright: "2020 Stephen A. Edwards"
extra-source-files:
- [Link]
- [Link]
description: Please see the README on GitHub
[Link]: Common, optional directives
In executable, library, tests, or global
source-dirs: src # Directory in which to look for .hs files
ghc-options: # A list to pass to GHC while compiling
- -Wall
- -threaded
dependencies: # On which libraries to depend
- base >= 4.7 && < 5 # In resolver
- acme-missiles # or extra-deps in [Link]
build-tools:
- alex # Scanner generator, for .x files
- happy # Parser generator, for .y files
[Link]: the library directive
All but the smallest projects will include this
library:
source-dirs: src # Consider all the .hs files here
ghc-options: # Optional
- -Wall
build-tools: # Optional
- happy
[Link]: executables
executables:
my-exe: # Generates a my-exe executable
main: [Link] # Where to look for main
source-dirs: app # Consider all .hs files here
dependencies: # Optional
- peng # Name of the package (library)
another-exe: # Optional
main: [Link]
source-dirs: app2 # May want to make it distinct
[Link]: tests
tests:
basic-test: # Name of the particular test/executable
type: exitcode-stdio-1.0 # Interface to the test (default)
main: test/[Link] # Where to find the main function
dependencies: # We typically test the main library
- peng
another-test:
type: detailed-1.0 # More complicated than exitcode-stdio-1.0
main: test/[Link]
dependencies:
- peng
$ stack test # Runs all tests
$ stack test peng:basic-test # Run a single test
Approach
Mostly editing [Link] and source files in src/
Have app/[Link] include the main function, command-line stuff, and calls
into the library. Don’t put other .hs files in app/
Tests are set up for unit tests. See the documentation for cabal for more
information about how to structure tests