Skip to main content

The Sum of Ant

Posted by arnold on May 30, 2004 at 7:52 PM PDT

In a previous blog on href="http://weblogs.java.net/pub/wlg/197">today.java.net I
said some fairly strong things about ant, and I think I ought to
say something more, both good and bad. This seems like the place
to do it.

First, let us give ant its due. href="http://ant.apache.org/">Ant is designed to be a portable
way to replace make. Ant was to be platform independent, so the
obvious implementation choice was Java, which is fine, mostly.
And the obvious data format for the project description -- saying
what needs to be built -- was XML, which is not fine, as
we shall see.

Ant performs this task with some power, if little aplomb. On
can build ant files that will compile Java, C, and many other
languages; perform CVS and FTP tasks; build jar files and EJB
deployments, and so forth. Ant can run the same configuration
without modification, no matter the platform. This is no mean
feat. There is a reason why it has been winning many awards.

But when I say it is "with little aplomb", I mean it. Nobody
can accuse XML of being an easy read, of course, but if that were
ant's worst problem, well, ant is hardly alone in this sin. XML
abuse is rampant, and ant is far, far from the worst
offender. Given the limitations of XML syntax, ant does pretty
well. To see it really suck, try reading href="http://www.venge.net/graydon/markup-abuse.html"> Graydon
Hoare's essay on XML abuse. (Ignore the odd section headings
and stick to the content.)

The real problem is the one I talked about in my brief href="http://weblogs.java.net/pub/wlg/197">java.net blog:

Ant is nothing more than the sum of its parts

By this I mean that ant has not learned the basic power of composition,
building things out smaller parts. This was the great insight that
our Unix forbearers bequeathed us toolsmiths, and it's pretty sad
to see it forgotten. In Unix this is done with pipes -- the output
of one program can become the input of another. Along with
conventions about program output, this allows you to build up
something that is more than the sum of its parts. A utility that
finds file in the file system can generate a list of files for
any purpose: removal, editing, rebuilding, copying,
printing, ...

Ant has many
kinds of tasks
. These are portable because they are written
in Java, and these task implementations can rely upon operating
system abstractions in the underlying ant platform.

But they almost never work together. There are some common
tools for building up lists of files, but if you want a list of
files from any other source, good luck. This is why there are two
different tasks (one optional) that calculate list of Java class
dependencies, and they are incompatible. And if you want a list
of Java class dependencies for a task that one of these two tasks
can't handle, good luck.

A common quote in our biz is the observation that a good software
tool will do things the author never expected1. I doubt that writers
of ant tasks are very often surprised.

In fact, I will assume that the value of composable tools is
so obvious, I will not belabor it further. Unless you ask...

My experience is that the primary legibility problem with
Makefiles are strings and variables. The string operations are
primitive, ugly, and limited. So to do anything at all interesting
requires cryptic and hobbled work. After that, the next worst problem
is the lack of flow control. Loops are put into the shell commands
because make doesn't have loops, or (shudder) people use recursion
as a replacement. Ugh.

The primary portability problem is obvious: Different system
have different commands, and make just executes commands.

So where would one go to leverage existing tools that already
know how to do these things well? Scripting languages, of course.
Perl, python/jython, tcl, and so on live, breath, eat, and excrete
strings for a living, and they are programming languages with real
logic. They are ported to every platform that matters (more than
Java runs on).

All they are missing are tools to express dependencies and how
to apply them to building things. One of the response to my post
pointed me at scons,
which does this in Python. It seems just the right direction,
although I haven't had a chance to do more than play with scons.
I don't claim it is the right answer, but it sure is moving
down the right path.

Johnathan Simon's href="http://today.java.net/pub/a/today/2003/06/10/jython.html">
blog entry about how to use ant tasks from jython points
towards some hope that we can reuse all the work these folks put
into ant tasks. This has often been non-trivial effort, and it
would be good to keep this work viable.

One could pick any language, of course, and choosing a winner
here would antagonize folks who would just prove they could do it
better in the "right" language. I have my preferred scripting
languages, but compared to scripting in XML itself (which is where
the ant folks seem to be going), no major possibility is worse.

I intend to poke harder at scons, and if it looks good, dive
in fully to find out. You'll be seeing a blog here about scons
and the lessons to learn from it.


[1] Google has failed me. Can the death of
the internet be far behind? I cannot find an attribution for this
quote, despite the obvious set of words and the fact that it's a
computer quote that I've heard a billion times.

Related Topics >>