Sunday, 7 November 2010

How to write a generic java compile target in ant

The problem

We use ant for our builds and it generally works just fine. But we've been rationalising our many build scripts lately, identifying the common stuff and putting it into a common file. Obvious, really, and that is going well. In the process I came across an awkwardness, a kind of mismatch inside ant. We wanted a generic compile target that handles:
  1. running javac to compile the source files
  2. copying the non-java files (xml, xsd, xsl etc) across to the bin directory
We often have multiple source paths and javac lets you specify them like this:

javac srcdir="java/src:java/test:java/other"

So I have three directories with source files. But when I want to copy them I have to say:

<copy todir="${basedir}/bin" flatten="no" >
  <fileset dir="java/src" includes="**/*.properties,**/*.xml"/>>
  <fileset dir="java/test" includes="**/*.properties,**/*.xml"/>
  <fileset dir="java/other" includes="**/*.properties,**/*.xml"/>>
</copy>

Which would be okay but in different projects the list of source directories varies so I can't have a generic target that will compile anything. Well, actually I can...

The Solution

First I need to have ant-contrib in my classpath, then I define the taskdef for it like this:

<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>

Once that is done I can make my generic target ehich looks like this:

<target name="compile-source">
        <delete dir="${basedir}/bin" failonerror="false"/>
        <mkdir dir="${basedir}/bin"/>
        <javac destdir="${basedir}/bin"  srcdir="${srcpath}">
            <classpath>
                <path refid="libs"/>
            </classpath>
        </javac>
        <foreach delimiter=":"
             list="${srcpath}"
             param="d"
             target="copysource"/>
    </target>
   
    <target name="copysource">
        <copy verbose="true" todir="${basedir}/bin" flatten="no" >
            <fileset dir="${d}" includes="**/*.properties,**/*.xml"/>
        </copy>
    </target>

The key to this is the foreach tag in the compile-source target. That loops through the srcpath, splitting out the colon delimited fields and running the copy.

It took me a while to figure out how to use foreach, so hopefully this is a help.
Post a Comment