[Haskell-cafe] ANNOUNCE: Blueprint 0.1 -- PREVIEW
Gregory Crosswhite
gcross at phys.washington.edu
Mon Nov 30 10:23:36 EST 2009
I earlier posted to this list asking for help in getting Cabal to play with a Fortran compiler. When it turned out that there was no answer to this, I of course did the obvious thing --- I wrote my own build system. :-)
It already boasts the following features:
* Fully self-hosting --- can both build and install itself.
* Implicitly detects and tracks module dependencies.
* Builds in parallel as much as possible.
* Can scan through a source directory to add all files, saving the trouble of adding them manually.
* Supports compiling C and Fortran sources in addition to Haskell sources, and linking everything together.
* Utilizes a “tool” system to make it easy to extend its functionality, such as by adding a new language.
* Flexible configuration system: tool options (e.g., path to the Fortran compiler) can be detected automatically, set in a configuration file, or specified on the command line.
* Provides help messages both to list the targets and to explain the configuration command-line options.
* Does not terminate at the first error, but instead tries to do as much as possible and then report all errors. (This is a general philosophy that holds both for the build, the configuration, etc.)
* Easily supports multiple targets that can depend on the results from other targets.
* Automatically resolves package dependencies, as read from .cabal file. Detects when a module is not in any known dependency, and reports an error that also lists all packages that export this module.
What separates this system apart from others is that it uses Haskell’s built-in laziness to handle dependency ordering and parallelism. That is, one expresses the desired build result as a function of the input sources; when the result is demanded, it causes Haskell to go through and execute on-demand all of the necessary build steps. To get parallelism, just tell GHC to use multiple threads with the “+RTS -N# -RTS” option, where # is the number of threads. (All that I had to do to get this to work was put parLists in a couple of places.) This is a big win for me because it means that I get the correct behavior without having to write and test my own complicated graph data structure for tracking the dependencies between build steps.
The philosophy of building up a big calculation of which only parts need be lazily demanded can be extended further to the build phases, which I call “targets”. For example, the first line of the code defining the build target is:
build = configure >>= \configuration -> ...
This demands the configuration target, and then uses the result in the build. So when you run “./Setup configure”, you only demand that Setup compute the value of “configure”, but when you run “./Setup build” you demand both “build” and also “configure”.
All of the errors that are reported are “composable” in the sense that they can be combined into a new error message that leaves nothing out and also has no duplicates. As much as possible the system tries not to stop until it has nothing else that it can do, allowing it to uncover as many errors as possible and then compose them into a single message.
I have posted Blueprint to Hackage so that people can see what I have done and possibly play with it. I hope to eventually document it and add examples, but I figured it was better to release early and get it out there sooner rather than later so that people can see what I’ve done. Thus, at this point it should be considered a PREVIEW release, not even an alpha release. Having said that, within the domain of the functionality it implements it works well enough that I use it myself as the build system for a Physics simulation code that is a mixture of C, Haskell, and Fortran.
To see what Blueprint looks like in action, take a look at Setup.hs. For example, Setup can either build a library (“build” target) or it can build itself (“bootstrap” target); it is smart enough to use different flags and directories in the two cases so that there ends up being in essence two parallel builds. Setup also has a lot of targets: configure, reconfigure (delete cached configuration and then configure), build, rebuild (clean then build), clean, distclean, install, bootstrap (build itself rather than a library), haddock (documentation generation that does not work particularly well yet).
Anyway, take a look if any of this sounds interesting to you, and let me know if you have any questions!
- Greg
PS: You're best bet for browsing through the sources is to use Leo (leo.sourceforge.net), since this makes it easier for you to see how everything is organized.
More information about the Haskell-Cafe
mailing list