Tuesday, November 25, 2008

Cabal is a fine piece of software

Many people in the Haskell community use a build-and-packaging library called Cabal. I used Cabal long ago, but that was in a simpler era. These days, I’ve found that a batch file that reads roughly:

@ghc –-make –O –hidir obj –odir obj –o target Main.hs
works just as well. However, I’m now part of a larger project in which the other members are using Cabal, and it’s given me an opportunity to appreciate how nice development with Cabal is these days. I thought I’d provide a couple of examples.

One nice thing about Cabal is that it really helps you appreciate the different parts of the build process. For instance, suppose that I change my cabal metadata file, and then attempt to build my project, for instance by saying
runghc Setup.hs build

Cabal will helpfully reply:

Setup.hs: interpreter.cabal has been changed, please re-configure.

Notice how Cabal has helpfully here noticed that there’s work to be done, and not done it. I found that this really helped me appreciate the details of the build, rather than unhelpfully hiding those details behind some veneer of “automation”.

I noticed another nice Cabal feature upon first adding the line
import qualified Data.Map as Map
to my program. Of course, recompiling produced the message:
Preprocessing executables for interpreter-0.1...
Building interpreter-0.1...

src/Core.hs:8:17:
Could not find module `Data.Map':
it is a member of package containers-0.1.0.2, which is hidden
This actually illustrates a couple of nice things. First, I really like the message about preprocessing executables. I haven’t said anything about preprocessors in my Cabal metadata file, but Cabal is helping me to realize that perhaps I could have. Or perhaps it’s telling me that it has to do some preprocessing as part of the build, even if I haven’t told it about preprocessors. This is good knowledge to have about the build process

Second, I’d like to highlight the line “building interpreter-0.1”. Cabal is actually building a file called dist\build\interp\interp.exe. But it’s not confusing me with that – rather, it’s reminding me of the project name and version I defined in my Cabal metadata file!

But really, my favorite feature is highlighted by the GHC error message about not being able to find Data.Map. Of course, Data.Map is on my system – GHC’s even found it, and told me where it is. But Cabal’s made an important distinction: just because I have software installed in my development environment doesn’t mean I want to use it! Rather, Cabal’s started out by hiding all the Haskell libraries installed on my system. This helps me really appreciate the packaging system, as I get to individually add each package I’ve previously installed and then wish to use to my metadata file. Of course, keep in mind, this is a per-project effort! Even if I’ve used a library in one project, I might not want to use it in my other projects.

Of course, this just scratches the surface of the many interesting and exciting features of Cabal. There are many others -- for example, the token that begins comments begins comments as long as it’s the first non-space character in a line – but not otherwise!. I’ve been really inspired in my work with Cabal so far – I only hope that someday I can write something nearly as useful!

2 diversions:

Don Stewart said...

Try managing your system with 900 haskell packages installed, without default hiding.

Default exposing of all packages doesn't scale.

Trevion said...

"Try managing your system with 900 haskell packages installed,"

Nah, I'd rather not.