Developing projects using ant is pretty easy and straight forward. One convention I like to follow is to organize each component in the system to have its own local build file. These builds can be aggregated by higher level builds very simply. This gives great flexibility while developing since you can build only what you need while working on it and yet you (or continuous integration) can easily perform a full build/test. If you have lots of similar components, your ant scripts might begin to have lots of duplication in them unless you start refactoring the common pieces into includes. In the old days (prior to ant 1.6), there wasn’t an obvious way to include fragements. While reviewing some open source projects back in 1995 I stumbled across the xml include technique (below) that I’ve used a few times. I had forgotten about this until I was recently asked to make some recommendations on an older project’s build approach.

Assuming you have a bunch of web applications and a few common infra components. All of the web applications would have had the same (more or less) build file so you could refactor most of it into a common_build.xml. Since we were using ant 1.5X we used the little XML include trick to declare and use a new element. This lets the XML parser do the work of inserting the xml fragment into our build scripts.

For example, a web application’s build script would start like this.


<?xml version="1.0"?>
<!DOCTYPE project [
<!ENTITY common SYSTEM "file:../../common_build.xml">
]>
<project name="defects" default="build" basedir=".">
&common;
<!-- other ant properties and targets go here... -->
...

The common build script looks like this (it is only an xml fragment).


<property file="local_build.properties" />
<property file="../local_build.properties" />
<property file="../../local_build.properties" />
<property file="build.properties" />
<property file="../../common_build.properties" />


<property name="log.template.file" value="template_log4j.properties" />


<path id="master.classpath">
<pathelement location="${target}" />
<fileset dir="${lib}">
<include name="*.jar" />
</fileset>
<fileset dir="${target}">
<include name="*.jar" />
</fileset>
</path>
...

If this were setup in a directory structure like the following, you could apply this include trick in each of the webapps build scripts.

ant_nest_example

The common_build.xml is located in the root of the project. The webapps (for example, app1) have a build script that includes it. The build script in the webapps directory simply knows how to build each app. The core and common components probably don’t include the common_build.xml because they do something significantly different.

This approach works very well for situations where you need to build more than two very similar components. It isn’t a perfect solution tho as the syntax is somewhat confusing and not very intention revealing.

I should note, that I didn’t invent this but I can’t remember where I saw this used first. It was likely on an Apache open source project. It is now mentioned on the Ant FAQ.

Also, since Ant 1.6, there is a new <include> task which is even more flexible since it lets you use ant properties in the file name. This approach is much better than the xml trick.

Reusing build script fragments is a great way to DRY up your configuration and ensure more consistency.