Ten Cache Misses

Crushing Haskell like a Tin Can

Building Large Haskell Projects with waf

I just published a little Cabal tool for waf to GitHub. We’ve been using it for quite a while for our builds, including a CI buildbot. Managing a moderate number of packages with cabal-install was getting to be a hassle… and supporting multiple languages (primarily concerning C++) in one build system was a looming requirement. cabal-dev might be an alternative for pure Haskell shops, though I haven’t used it.

There is a simple tutorial over on GitHub that should cover the basics, if you’re in need of a faster build. I’ll spare the details here.

In order to get decent parallel build performance I broke up the cabal install steps into smaller peices, and left out some features like Haddock support. The basic process is:

  1. cabal configure
  2. cabal build
  3. cabal copy
  4. cabal register –gen-pkg-config
  5. ghc-pkg update
  6. touch – a dummy step for enforcing cross package dependencies

cabal haddock should slot in somewhere up there, probably as a parallel task to cabal build.

ghc-pkg register is serialized across all packages to prevent the registration database from being corrupted. The remaining steps are always run in sequence for each package… unless you’re building executable-only packages. Then registration isn’t supported and just leads to build failures.

The rest of the build is handled in parallel, much like make. I added an additional dummy step to track cross package dependencies, something that should be cleaned up (by reading the registration script?). I’d also like to parse the .cabal scripts and tease out the in-tree dependencies so that they don’t need to be specified twice. Work for another day though.

This is what our build looks like. The heavy use of Rank-N types in a few packages leads to a slow first build (though they are carefully segregated to reduce rebuild times), as you can see here. This covers about 15 minutes. Charts are courtesey of parallel_debug:

Edit just one file, in this case a heavily used module in our Prelude overlay, and waf will rebuild the offending package first followed by all dependents in the correct order. This time around the build shows very good parallelism, keeping all 8 cores busy, finishing in about a minute.

Comments