How-To Guides
Getting Started
Policy Strategies
Format Strings
Extending Antlion
First Tutorial: Simple
Ant Tasks
inner processors
inner repositories
Optional Tasks
About optional tasks
Prev   Next  

Large Ant projects generally run into the issue of breaking up a monolithic build process into smaller, more manageable pieces. In the process, the smaller pieces lose the nice dependency graph that Ant provides with the depends. In its place, custom Ant script codifies this dependency graph. Ant 1.6 supplied the <subant> task to ease the burden of a master build file, but does nothing for inter-project dependency analysis.

Antlion provides the <subprojects> Ant task to allow for a cleaner solution. It provides a single place in a build file where all the external build dependencies get defined, and allows for the target dependency graph to still be defined in the targets.

Master Builds

Let's first look at how the <subprojects> task fills the role of the master build file calling other builds. In this example, we'll have the master build file, master.xml, call out to other Ant files in the same directory, a.xml, b.xml, and c.xml. If a.xml and b.xml each have public targets "all", "main", and "clean", while c.xml has only "main", then master.xml will look something like:

<project name="master" default="main">
  <subprojects prefix="SUB">
    <project name="a" antfile="a.xml"
                       targets="all, main, clean" />
    <project name="b" antfile="b.xml"
                       targets="all, main, clean" />
    <project name="c" antfile="c.xml"
                       targets="main" />

  <target name="main"
      depends="SUB::a::main, SUB::b::main, SUB::c::main" />

  <target name="clean"
      depends="SUB::a::clean, SUB::b::clean" />

  <target name="all"
      depends="SUB::a::all, SUB::b::all, SUB::c::main" />

The <subprojects> task will create an artificial Ant target for each listed target of the projects. Then, those targets can be added wherever they are needed, to let Ant discover the correct build order.

Inter-related Projects

Let's say our build is two separate projects, a.xml and b.xml. They can be built independently, but b.xml requires a jar file from a.xml in order to compile correctly.

We can alter the above example to include the conditional property to check for the jar file's existence. Thus, b.xml could look like:

<project name="b" default="main">
    <subprojects prefix="SUB">
        <project name="a" antfile="../a/a.xml" targets="jar"
            unless="a.jar-exists" />

    <target name="compile" depends="-compile:init, SUB::a::jar">

    <target name="-compile:init">
        <available property="a.jar-exists"
            file="../a/dist/a.jar" type="file" />

In this example, the artificial target "SUB::a::jar" gets created as though the above build file added:

    <target name="SUB::a::jar" unless="a.jar-exists">
        <ant antfile="../a/a.xml" target="jar" />

Working With Artifacts

The above example isn't ideal. It doesn't take into account the possibility that the jar file could be out-of-date with its source.

If, however, the "a" project provided an artifact file (see the discussion about artifacts) located at ../a/artifact.xml (relative to b.xml), like so:

<project name="a-artifact">
  <artifact antfile="a.xml" name="a" id="a-artifact.a.jar"
      artifact="dist/a.jar" target="jar">
    <src dir="src/java">
      <include name="**/*.java" />
      <include name="META-INF/**" />

then we could rewrite the above example of b.xml as:

<project name="b" default="main">
    <import file="../a/artifact.xml" />
    <subprojects prefix="SUB">
        <artifact refid="a-artifact.a.jar" />

    <target name="compile" depends="SUB::a::jar">

This will automatically do an out-of-date check on ../a/dist/a.jar against its source.

Prev   Next  
Document version $Revision: 1.7 $ $Date: 2005/10/27 19:54:00 $

SourceForge Logo
Copyright © 2004-2006, The Antlion Project