Ant Fu

We’ve had some discussions recently about best practices when creating Ant scripts, so I thought I’d write up a few of my favourites.

Managing Ant target dependencies

“depends” are great, until your build file gets bigger than a couple of screenfuls. You can end up with a crazy spaghetti monster of dependencies very quickly. On a few builds I’ve worked on we’ve had a basic rule:

Targets can either have depends or a body, but not both.

So you end up having two types of targets:

  • functional targets” that actually do the work, carrying out small individual tasks
  • flow targets” that tie the functional targets together

<target name=”the.lot” depends=”compile,test,jar,report” />
<target name=”compile”>

</target>
<target name=”test”>

</target>

Public vs Private targets

I’ve built build files using the public and private target idea (affix a “-” to private targets so they can’t be called externally).

It can work in some situations and makes it reasonably clear what’s going on. It can also work in conjunction with the “functional and flow” targets described above. (Functional targets are private; flow targets are public).

My main issue with this approach is that as a build engineer you often want to call internal / private targets to run just a small step in the build (particularly while developing new features) – you can’t do this if the targets are private. so you end up creating a second, public, target that calls the private target … and you end up doubling the size of your build files.

I prefer just to have the main entry point targets (your flow targets) at the top of the build file so it’s obvious to anyone who opens the build file what they can use.

You can also differentiate your public (API) targets by only allowing them to have description attributes. These will be the only targets listed when your run “ant -p”.

Macrodefs with closures

Macrodefs are great and should be used to reduce duplication wherever possible.

An extra-powerful feature of macrodefs, which I only came to understand recently, is the ability to pass arbitrary ant elements into macrodefs – think closures / ruby blocks.

We now have expressive parts of our build scripts looking a bit like the following:

<for-each-module>
<compile module=”@{module}” />
</for-each-module>

<for-each-module>
<test module=”@{module}” />
</for-each-module>

<macrodef name=”for-each-module”>
<element name=”action” />
<sequential>
…. do some stuff …
<action />
…. do some more stuff …
</sequential>
</macrodef>

I’d be interested to hear if anyone has other suggestions for keeping Ant from spiraling out of control.

One Reply to “Ant Fu”

  1. In response to the public/private thing, one trick that can be tried is the inclusion of a description. When you do ant -p, only targets with descriptions will show up. This is one way of hiding public targets that you may not want people to know about.

    Personally, in the flow targets, I like to use antcall instead of depends. I find this to make the target more readable and communicates the intent of the target better then using depends. For me, a target that depends on other targets, but doesn’t do anything doesn’t make sense. Whereas a target with a series of antcalls shows me the intent of that target.

Comments are closed.