Simple Cabal parsing

This is going to be a silly post, simply because it is so amazingly simple to do some basic parsing of Cabal files. It turns out to be true even for old versions of Cabal, the code below is for since that’s the version still found in Debian Unstable.1

First import the required modules:

import Distribution.PackageDescription
import Data.Version
import Distribution.Verbosity
import Distribution.Version

The a simplistic shortcut, I don’t care about setting flags or pretty much anything else

finPkgDesc = finalizePackageDescription [] Nothing "Linux" "X86_64" ("GHC", Version [6, 8, 2] [])

and I’m only interested in listing the package names of dependencies

getPackageName (Dependency name _) = name

After this it’s possible to do the following in ghci (ex01.cabal is a copy of the Cabal file for dataenc):

> gpd <- readPackageDescription silent "ex01.cabal"
> let pd = finPkgDesc gpd
> let deps = either (\_ -> []) (\ (p, _) -> buildDepends p) pd
> map getPackageName deps

  1. That’ll change when GHC 6.10 makes it onto my system. It’s already in Debian, just not on my system since some Xmonad-related packages haven’t been rebuilt yet.↩︎

Antoine Latter

For scraping deps from the newer parts of Cabal syntax, you can check out my attempt over here.

You’ll want to look at gPckgDeps :: GenericPackageDescription -> [Dependency].

It’s a bit gruesome, I admit.


Note that if you do not care about flags etc then you can use the even simpler flattenPackageDescription. However, be aware that that will give you the union of all possible dependencies. This is not the same as the set of dependencies in any particular configuration. Indeed the union of all version constraints may be impossible.

On the other hand finalisePackageDescription gives you the result for one particular configuration. So it does not reflect what the deps would be for another configuration if the .cabal file uses conditional dependencies.

So which one is right to use depends on what it is you are trying to do.


@Antoine, I believe I’d rather keep using finalizePackageDescription even for newer versions of Cabal. If I read it correctly gPckgDeps simply pulls out the PackageDescription, which AFAIU is at least similar to flattenPackageDescription. I really want to end up with the “default package description”, which I believe is what I get when using finalizePackageDescription with an empty set of flags.

@Duncan, actually I suppose I do care about flags, I want none to be set :-) AFAIU that will give me the “default package description”, which is what I’m after.


Just to clarify…

When you call finalizePackageDescription you get to say something about flag values. You can specify true or false or you can not specify it at all. Then finalizePackageDescription will come up with true/false values for the flags that you did not specify. It does this based on the default values for the flags (given in the .cabal file by the package author) but more interestingly based on the possible flag values given the flag-conditional dependencies and the set of available packages. Now you’re not specifying any set of available packages (not the same as specifying none, then we could not finalise any package). So all constraints (that are not self-contradictory) will be presumed to be ok.

The result is that (since you use Nothing for the set of available packages) you’re getting the default flag values specified by the package author. Which as you say, is what you want. Just keep in mind that it need not correspond to any real configuration a user might even encounter, though it’s probably the same or close most of the time.

Simple right? :-)

What we’re doing, sort-of, is partially evaluating the package description using the available information. I’m going to change this API in future to make it more flexible and to make the partial evaluation notion more explicit. We’ll be able to partially evaluate a generic package description using any partial set of information, OS, arch, ghc version (or range of versions), available packages (again, not necessarily all available package) etc and get back another generic package description. We’ve only finalised when we’ve resolved all the choices. As you’re doing above we should also be able to do that using default flag values and not using any set of available packages.


@Duncan, thanks, that does clarify it a bit. Not that simple though ;-)

Leave a comment