ANN: Capon 0.1 - a software build framework

Anders J. Munch andersjm at dancontrol.dk
Thu Apr 10 06:01:03 EDT 2003


"Aahz" <aahz at pythoncraft.com> wrote:
> 
> So how does Capon differ from SCons?

SCons has lots of features.  The main thrust of Capon is on providing
the means to add features.  Capon is a language by itself, and Capon
scripts are not Python scripts.  That sounds complex but isn't, the
language is just Python in disguise.

It's not inconceivable that I could find a straightforward way to
bridge Capon and SCons, providing "Caponic" style access to SCons
features.  It's not inconceivable that someone else could, either,
given the extensible nature of Capon.

I'm not going to attempt a comparison with SCons, I don't know SCons
well enough for that, and besides I'm taking Bjarne Stroustrup's
advice on comparing languages.  Instead let me illustrate what it is
that sets Capon apart.

Take a look at this implementation of 'clean', a function to delete
intermediary files.

| import os  # import a Python module
| .clean():  # lazy notation; think of this as "def clean(self):"
|     # dependency_tree() is a generator that lists dependencies recursively
|     for dep in .dependency_tree():
|         dep.clean_this() 
| 
| .clean_this():
|     pass
|
| .file.gen/clean_this():
|     if .exists():
|         if .verbose:
|             print "clean() deleting %s" % (.filename,) 
|         os.unlink(.filename)

'clean' is a simple function that walks a generator and calls
'clean_this' on each node.  The nodes typically represent files but
don't have to.  Except for implicit self argument lists and function
bodies are straight Python.

'clean_this' comes in two incarnations: The simple ".clean_this()"
that doesn't do anything, and ".file.gen/clean_this()" which deletes a
file.  It's what I call a category qualified function.  This means
that clean_this will do different things for nodes in different
categories.  For example, if you call clean_this on a node in category
"file.gen.obj.c", which would be a typical category for an object file
which is compiled from a C file, then the second version will be
called, and the file will be deleted.  

Calling clean_this on a source file in category "file.source.c" will
call the first version and do nothing.

This is the clean and clean_this functions as I have written them.
They happen to be a part of the distribution, but you could just as
well have written them in your own scripts.  Either way, you can
override their behaviour for specific nodes, and in more than one way.
By specialising a category:

| .file.gen.map/clean_this():
|        pass # never delete map files

Or by overriding for a single node or group of nodes:

| Gen('systemfile.lib'):  # a node representing the systemfile.lib file
|       .clean_this():    # overrides inherited versions
|               send_email(to="BOFH", subj="Delete systemfile.lib, please?")

All top-level function are automatically available from the command
line.  So you can write:

  cap .clean()

to run the 'clean' function on the default node.

More interesting than 'clean' is the 'compile' function, which serves
the same purpose as build commands in a makefile; but you can read all
about that in the tutorial.  I hope I've peaked your curiosity and
you'll give it a try.

caponically-y'rs, Anders






More information about the Python-list mailing list