O'Reilly logo

Ant: The Definitive Guide, 2nd Edition by Steve Holzner

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 1. Getting Started

Build tools are one of the most boring items developers must have available in their development cycle. They aren’t sexy, they aren’t going to impress your friends, and you’ll hardly notice a build tool at all until it’s time to redeploy that 1,000-class Java application you’ve been working on. Then, all the interesting code, killer IDEs, and amazing design patterns aren’t worth nearly as much as typing ant and calmly watching your boring build tool handle complicated dependencies, deployment onto multiple servers via FTP and SSH, and log errors. It is here that build tools like Ant truly shine.

At its most basic, all a good build tool does is take source code, compile it, and create a working application. When you’re writing a single-class application, this isn’t a big deal; in fact, it can be annoying to manage a build system instead of typing javac. But it’s a different story when you start working with multiple source files, with multiple dependencies, need to check code out of a central repository automatically, test the code, and deploy it to some remote destination. You can end up with dozens of tasks to complete each time you want to build your application, which is the last thing you want to spend time on when you’re already brain-dead from an all-night debugging session. When new members join your team, you’ll have to walk through this whole process again, showing them the ropes and hoping they don’t break anything in the process. It’s for all of these reasons that developers—and especially Java programmers—turn to Ant.

Though there are still powerful alternatives to Ant like make, Jam, Cons, gnumake, and nmake, nothing is as integrated into the Java programming language. Ant is pure Java; you’ll find line after line of Java code and .java files if you obtain a source release of the tool. Further, some of the most popular projects in the Java universe are built using Ant; everything from Tomcat to JBoss to Turbine can go from source to binary by typing ant.

Ant’s Origins

Ant was originally the brainchild of James Duncan Davidson, and the word Ant stands for “Another Neat Tool,” a fact that relatively few developers realize. Ant 1.0 first appeared in March 2000. James’ original inspiration was to create a build tool that used a simple XML-based format for build files, as opposed to the shell commands and involved formatting that Makefiles used. Ant caught on rapidly, and newer versions followedAnt 1.1 (July 2000), 1.2 (October 2000), 1.3 (March 2001), 1.4 (September 2001), and 1.5 (July 2003). The version this book uses—version 1.6.1—appeared in February of 2004. Although James Davidson has moved on to work with other build tools, Ant continues to evolve on an almost daily basis.

Ant is an open source, Apache community project, and its home page is at http://ant.apache.org. Because it’s an open source project, it’s always developing. There are multiple authors, called committers, which can write to Ant’s source code repositories. However, officially sanctioned Ant versions don’t appear too rapidly, and when they do, they’re usually backward compatible enough to make sure your build files aren’t broken.

Tip

One notable exception to this practice is Ant 2.0, which may be out sometime in the next year or so. When it does come out, the Apache Ant team plans on releasing an automated migration tool that will translate 1.x build files to Ant 2.0.

Getting Ant

Ant comes in two editions: binary and source. The binary release is ready to use: just download, uncompress, and go. The source release allows you to see what makes Ant run and to make modifications of your own if you choose. To download either, go to http://ant.apache.org/ and click a link under the Download title (either Binary Distributions or Source Distributions).

Downloading a binary edition is easiest: Just click the Binary Distributions link and download the .tar.gz or .zip compressed file.

Tip

If you want bleeding-edge Ant, you can get the nightly builds from http://cvs.apache.org/builds/ant/nightly/.

Installing Ant

To install the binary distribution of Ant, expand it. Here’s the resulting directory layout (only the bin and lib directories are needed to run Ant):

  ant
   |___ bin  Ant launch scripts
   |
   |___ lib  Ant jars 
   |
   |___ docs Ant documentation
   |
   |___ etc  XSL for formatting Ant XML output

You need to perform the following steps to complete the setup process:

  1. Add the Ant bin directory to your path.

  2. Set the ANT_HOME environment variable to the directory where you installed Ant.

    Tip

    On some operating systems, the Ant scripts can guess ANT_HOMEspecifically in Unix and Windows NT/2000but it’s better not to rely on them doing so accurately.

  3. Set the JAVA_HOME environment variable to the directory where your JDK is installed.

If you’ve expanded Ant in c:\ant on Windows, you’ll end up with a new directory, c:\ant\apache-ant-1.6.1. If you’ve installed the JDK in c:\jdk1.4 (and the Java bin directory is C:\jdk1.4\bin), set the environment variables like this:

set ANT_HOME=C:\ant\apache-ant-1.6.1
set JAVA_HOME=C:\jdk1.4 
set PATH=%PATH%;%ANT_HOME%\bin

In Unix (bash), assume Ant is installed in /usr/local/ant. Here’s how you’d set up the environment:

export ANT_HOME=/usr/local/ant
export JAVA_HOME=/usr/local/jdk1.4
export PATH=${PATH}:${ANT_HOME}/bin

In Unix (csh), you’d do something like this:

setenv ANT_HOME /usr/local/ant
setenv JAVA_HOME /usr/local/jdk1.4
set path=( $path $ANT_HOME/bin )

Tip

There are great instructions on how to set environment variables on many different systems in the installation documentation for the Java JDK.

To compile Java code, you’ll need a working JDK on your machine. If you only have a Java Runtime Environment (JRE), Ant won’t be able to do many things you need it to do. Also note that the Microsoft JVM/JDK is not supported.

Warning

In Windows 95, Windows 98, and Windows ME, the batch file used to launch Ant will not work if ANT_HOME holds a long filename (a filename which is not in the 8.3 format). It’s best to install Ant in a short 8.3 path, such as c:\Ant. If you’re using one of these operating systems, you’ll need to configure more environment space. Update the following line in your config.sys file:

shell=c:\command.com c:\ /p /e:32768

Testing Ant

With Ant in your path, you should be able to run it at the command line. To test this, type ant -version, which should display the current Ant version:

%ant -version
Apache Ant version 1.6.1 compiled on February 12 2004

If Ant’s not working, you’ll see something along these lines:

-bash-2.05b$ ant
-bash: ant: command not found

Here’s the Windows version of the same error:

C:\>ant
'ant' is not recognized as an internal or external command,
operable program or batch file.

In that case, go back over the installation instructions, and look at the Ant documentation for troubleshooting issues.

Ant at Work

Rather than go on and on about what Ant can do for you, an example can illustrate how easy Ant makes the build process. Assume that you have a Java file called Project.java, as shown in Example 1-1.

Example 1-1. A simple Java class
public class Project 
{
    public static void main(String args[]) 
    {
        System.out.println("No worries.");    
    }
}

Assume you want to compile this code and store the results, Project.class, in a JAR file, Project.jar. With Ant and a build file, this is a piece of cake. By default, Ant looks for a build file named build.xml. That file is a valid XML document; Example 1-2 shows the build file for this example.

Example 1-2. A simple Ant build file
<?xml version="1.0" ?>
<project default="main">

    <target name="main" depends="compile, compress">
        <echo>
            Building the .jar file.
        </echo>
    </target>
  
    <target name="compile">
        <javac srcdir="."/>
    </target>
  
  <target name="compress">
        <jar jarfile="Project.jar" basedir="." includes="*.class" />
  </target>

</project>

To run this Ant build file, make sure it’s in the same directory as Project.java, and enter ant at the command-line prompt. Ant has been tested on many platforms, including Linux; Unix versions from Solaris to HP-UX; Windows 9x, NT, 2000, and XP; OS/2 Warp, Novell Netware 6, and MacOS X.

When you run Ant on this first build file, here’s what you’d see in Unix (using the bash shell):

-bash-2.05b$ ant
Buildfile: build.xml

compile:
    [javac] Compiling 1 source file

compress:
      [jar] Building jar: /home/httpd/vhosts/builder/Project.jar

main:
     [echo] 
     [echo]             Building the .jar file.
     [echo]         

BUILD SUCCESSFUL
Total time: 2 seconds

You’ll get the same results in any supported operating system. For example, here’s what you’d see in Windowsverything except the build time is identical:

C:\ant\ch01>ant
Buildfile: build.xml

compile:
    [javac] Compiling 1 source file

compress:
      [jar] Building jar: C:\ant\ch01\Project.jar

main:
     [echo]
     [echo]             Building the .jar file.
     [echo]

BUILD SUCCESSFUL
Total time: 4 seconds

For the most part, Ant builds are independent of operating system, and for that reason, % is used as a generic command prompt in this book. If anything is operating-system-dependent, it will be listed explicitly.

When Ant finishes executing the build file, you’ll have build.xml, Project.java, the compiled Project.class, and Project.jar, all in the same directory. Project.jar will contain a manifest file and Project.class. Fortunately, Ant handles 10, 20, or 100 source files in this same way, making your life easy at build time.

Anatomy of a Build File

Ant projects all revolve around one or more build files. By default, Ant looks for a build file named build.xml. Because Ant files are XML documents, they start with an XML declaration, as all valid XML documents must:

<?xml version="1.0" ?>
        .
        .
        .

Tip

For the complete XML 1.0 syntax, look at http://www.w3.org/TR/REC-xml/. XML 1.1 is out now as well, but Ant build files are based on XML 1.0, and the difference between these versions is small anyway, centering mostly on the manner in which certain Unicode characters are supported.

Projects

Every Ant build file contains exactly one project. You set up an Ant project in a build file with the project element, which is the document element—i.e., the element that contains all other elements:

<?xml version="1.0" ?>
<project>
        .
        .
        .
</project>

As Ant build files are just XML, you’ll need to know which attributes are allowed on the top-level project element.

Tip

You’ll also want to know about the elements that can be nested within project. Those are dealt with throughout the rest of this chapter and in Chapter 2.

The three allowed attributes for the project element are shown in Table 1-1.

Table 1-1. The project element’s supported attributes

Attribute

Description

Required

name

Defines the project name

No

default

The target to invoke if no target is explicitly specified

Yes

basedir

The base directory from which all relative paths are resolved

No

Note that the default attribute is required. This attribute points to the Ant target that you want run by default; in other words, this controls what happens when you type ant at the command prompt, without any other special instructions. In the following case, the default target is main:

<?xml version="1.0" ?>
<project default="main">
        .
        .
        .
</project>

Targets

An Ant target is a group of tasks that you want Ant to perform. These tasks are grouped together into one easily remembered unit, which is the target. For example, you might have a target deploy which opens an FTP connection to a remote server, uploads various files, and closes the connection. Though multiple tasks may be involved (opening the connection, performing an upload, closing the connection, and perhaps checking for error messages), it’s easiest to think of this as one unit of work. Considering this as a single target makes it reusable and easily accessed from various portions of your build file.

Another example might be a target named init that initializes a build by deleting output directories and recreating them so they’ll be empty, as well as copying over license files that should be a part of every build. You might use a target named compile to compile dozens of source files across various directories and store the results in various output directories. In all these cases, the target handles piecing together various individual tasks.

Ant build files are made up of targets like these. For example, to create the main target, you use the target element, along with the name attribute:

<?xml version="1.0" ?>
<project default="main">

    <target name="main">
        .
        .
        .
    </target>
  
</project>

You can see the possible attributes for the target element in Table 1-2.

Table 1-2. The target element’s attributes

Attribute

Description

Required

name

Defines the target name

Yes

depends

Comma-separated list of targets to execute before this target

No

if

Name of a property needed to run this task

No

unless

Name of a property that can not be set before running this task

No

description

Description of this target’s purpose

No

Tasks

You populate an Ant target with tasks; a task is an XML element that Ant can execute to make something happen. For example, the echo task echoes text messages to the console:

<?xml version="1.0" ?>
<project default="main">

    <target name="main">
        <echo>
               Building the .jar file.
        </echo>
    </target>
  
</project>

To create an Ant target, you place Ant tasks like echo inside a target element; in this case, the main target only has one task, but you can include hundreds.

Built-in tasks

As you’d expect, Ant comes with a large number of built-in tasks, and you can see them all in Table 1-3 (many of these tasks may contain subelements).

Tip

In cases where a task is listed and followed by another task name in brackets (as in apply [execon]), the first task is the current name you should use; the second task is an older name that performs similar functionality but is now deprecated. Always use the task not in brackets to ensure your code is current.

Table 1-3. Core Ant tasks

Task name

Description

ant

Executes Ant

antcall

Executes a target from the current build file

antstructure

From a given build file, creates a DTD reflecting all of the tasks Ant currently knows about

apply [execon]

Invokes a native executable

available

Sets a Boolean value in a property according to the availability of desired resource

basename

Sets a property to the last element of a specified path in an effort to determine a file’s name without directory structure

buildnumber

Manages build numbers

bunzip2

Expands GZip or BZip2 archives

bzip2

Packs GZip or BZip2 archives

checksum

Creates checksums for one or more files

chmod

Modifies file permissions on Unix

concat

Concatenates multiple files

condition

Checks the result of a condition and sets the result to in a property

copy [copydir, copyfile]

Copies files

cvs

Interacts with a CVS repository

cvschangelog

Converts a series of CVS change logs into an XML report

cvspass

Adds entries to a .cvspass file

cvstagdiff

Creates an XML report highlighting the differences between tags

cvsversion

Finds the CVS software version

defaultexcludes

Modifies the list of default exclude patterns, affecting which files are automatically excluded from processing by file-related tasks

delete [deltree]

Delete files and folders

dependset

Deletes target files that are older than new source files

dirname

Assigns a file’s directory path to a property

ear

Extends the jar task to support handling files for an Enterprise Application archive (EAR)

echo

Echoes text to System.out or to a file

exec

Invokes a native executable

fail

Halts and exits a build by throwing a BuildException

filter

Sets a token filter that can be used by filter-related tasks such as copy

fixcrlf

Adds or remove tabs, carriage returns, linefeeds, and EOF characters from a set of files

genkey

Adds a new key to a given keystore

get

Retrieves files using FTP, HTTP, and more from a URL

gunzip

Unpacks a GZip file

gzip

Packs a GZip file

import

Allows the use of other Ant files

input

Displays a message and reads a line of input from the console, allowing for user input during the build process

jar

Creates a JAR archive similar to Java’s jar command

java

Executes the Java interpreter to run a class or application

javac

Compiles the specified source file(s)

javadoc [javadoc2]

Invokes the javadoc tool to create documentation

loadfile

Sets a property file to the entire contents of a text file

loadproperties

Loans an entire property file into Ant properties

macrodef

Defines a new task as a macro built-up upon other tasks

mail

Sends SMTP mail messages

manifest

Creates an archive’s manifest file

mkdir

Makes a new directory

move [rename]

Moves a file to another directory

parallel

Contains other Ant tasks that can be run simultaneously by multiple Java threads

patch

Uses the patch command (assuming it is on the path) to apply diff files to a source file (or files)

pathconvert

Converts paths between platforms

presetdef

Defines a new task based on an existing task with certain options preset as defaults

property

Sets one or more properties to new values

record

Runs a listener that records the logging output of the build process to a file

replace

Replaces a string with another in all files in a directory

rmic

Invokes the rmic compiler

sequential

A container task that can contain other Ant tasks and run them in sequence

signjar

Uses the JarSigner to securely sign ZIP and JAR archives

sleep

Suspends execution for a specified period of time

sql

Runs SQL statements against a database

subant

Runs Ant within all subdirectories of the project directory

sync

Synchronizes two directory trees

tar

Makes a new TAR archive

taskdef

Creates a new task definition and adds it to the current project

tempfile

Sets a temporary filename to an Ant property

tstamp

Sets time-based properties to the current time

typedef

Creates a new task or data type for use in the current project

unjar

Unpacks a JAR file

untar

Unpacks a TAR file

unwar

Unpacks a WAR file

unzip

Unpacks a ZIP file

uptodate

Sets a property value to true if a given target file is newer than a set of source files

waitfor

Halts a build and continues when specified conditions are met

war

Creates WAR archive files (an extension of the jar task)

whichresource

Locates a class or resource, either on the current class path or the system class path

xmlproperty

Loads Ant properties from an XML property file

xslt [style]

Transforms a set of documents via XSLT

zip

Creates and packs a new ZIP archive

Optional tasks

Besides these built-in tasks, called the core tasks, Ant supports many optional tasks, which you can see in Table 1-4. These tasks may require the support of additional JAR files, which you load into the Ant lib directory. For example, ftp uploads files to remote servers; you need to place the JAR files jakarta-oro.jar and commons-net.jar in your Ant lib directory to use the task. Another optional task is csc, which compiles Microsoft C# code:

<csc optimize="true" debug="false" 
    warnLevel="4"   
    unsafe="false" targetType="exe" incremental="false" 
    mainClass = "Main" destFile="app.exe" > 
    <src dir="src" includes="*.cs" /> 
    <reference file="${testCSC.dll}" /> 
    <define name="RELEASE" /> 
</csc>

Tip

To determine which additional JAR files an optional task needs, see http://ant.apache.org/docs/manual/index.html#librarydependencies, which lists the needed libraries for each optional taskand where to get them.

Table 1-4. Optional Ant tasks

Task name

Description

antlr

Runs the ANTLR Translator Generator Language Tool.

attrib

Changes the permissions and/or attributes of a file.

cab

Creates CAB files (Microsoft archives).

chgrp

Changes file groups on Unix.

chown

Changes file ownership.

depend

Determines which class files are out-of-date compared to their source.

echoproperties

Lists the project’s properties.

ftp

Supports a basic FTP client.

icontract

Generates a property file for iContract, an application for controlling assertions.

image

Performs bulk image manipulation.

jarlib-available

Checks for the presence of an extension.

jarlib-display

Displays the “Optional Package” and “Package Specification” information for JAR files.

jarlib-manifest

Generates a manifest with required dependencies.

jarlib-resolve

Searches for the location of a JAR file, setting the location to an ANT property.

javacc

Invokes the JavaCC compiler.

javah

Generates C header and source files for the Java Native Interface (JNI).

JPCoverage

Runs the JProbe coverage analyzer.

JcovMerge

Merges JProbe coverage snapshots.

JcovReport

Takes a JProbe coverage snapshot and creates a report.

jdepend

Uses the JDepend parser to generate code quality metrics.

jjdoc

Invokes the JJDoc documentation generator (used with JavaCC).

jjtree

Inserts parse tree building actions into source code using the JJTree preprocessor for the JavaCC compiler.

jlink

Deprecated. Merges archive contents. Use the zip and jar tasks with the zipfileset and zipgroupfileset attributes instead.

jprobe

Runs various tools from the JProbe suite.

jspc

Deprecated. Compiles JSP pages to Java source code. Use Tomcat’s jspc task instead.

junit

Runs unit tests using JUnit.

junitreport

Merges separate XML files generated by the JUnit task into a single XML file.

maudit

Highlights stylistic and potential execution problems using the Metamata Metrics/WebGain Quality Analyzer.

mimemail

Deprecated. You can still send mail using the mail task.

mmetrics

Generates metrics using the WebGain’s Metameta Metrics Quality Analyzer.

mparse

Takes a grammar file, and compiles it with MetaMata’s MParse compiler.

native2ascii

Takes a native encoded file and converts it to ASCII.

netrexxc

Compiles all NetRexx source files.

propertyfile

Creates or modifies property files.

pvcs

Gets latest source code from a PVCS repository.

renameextensions

Deprecated. You can achieve the same results by using the move task and using a glob mapper.

replaceregexp

Replaces matched text with new text.

rexec

Controls a rexec session from Ant.

rpm

Builds Linux RPM installation files.

scp

Moves files to and from a remote SSH server.

script

Executes an Apache BSF script.

Scripdef

Defines Ant tasks from scripts.

serverdeploy

Runs a hot-deployment tool for a J2EE server.

setproxy

Configures web proxy properties.

sound

After a build, plays a sound file letting you know whether the build succeeded or failed.

splash

Displays a splash screen.

sshexec

Executes a command on a remote server using SSH.

stylebook

Uses Apache Stylebook to generate book documentation.

symlink

Makes, deletes, or edits Unix symbolic links.

telnet

Controls a Telnet session from ANT.

test

Executes a JUnit test.

translate

Translates keywords in files using values in resource bundles.

vajload

Loads files for Visual Age for Java source control.

vajexport

Exports packages for Visual Age for Java source control.

vajimport

Imports files for Visual age for Java source control.

wljspc

Compiles JSP pages using Weblogic’s JSP compiler.

xmlvalidate

Validates XML files and reports any errors.

In addition to these tasks, specific Ant tasks for .NET are shown in Table 1-5.

Table 1-5. .NET Ant tasks

Task name

Description

Csc

Invokes the C# compiler.

vbc

Invokes the VB.NET compiler.

jsharpc

Invokes the J# compiler.

ildasm

Disassembles from .NET intermediate language back to source code.

ilasm

Assembles code into .NET intermediate language.

WsdlToDotNet

Given a WSDL file, this task will generate C# or VB code.

ImportTypelib

COM library importer.

Specific tasks for the Clearcase version control system are listed in Table 1-6.

Table 1-6. Clearcase Ant tasks

Task name

Description

CCCheckin

Checks in files.

CCCheckout

Checks out files.

CCUnCheckout

Un-checks out files.

CCUpdate

Executes cleartool update.

CCMklbType

Executes cleartool mklbtyle.

CCMklabel

Executes cleartool mklabel.

CCRmtype

Executes cleartool rmtype.

CCLock

Executes cleartool lock.

CCUnluck

Executes cleartool unlock.

CCMkbl

Executes cleartool mkbl.

CCMkattr

Executes cleartool mkattr.

CCMkdir

Executes cleartool mkdir.

CCMkelem

Executes cleartool mkelem.

Many EJB specific tasks are shown in Table 1-7.

Table 1-7. EJB-related Ant tasks

Task name

Description

blgenclient

Generates a client JAR for Borland application servers.

ddcreator

Creates EJB deployment descriptors, given a group of WebLogic deployment descriptors.

ejbc

Invokes WebLogic’s ejbc tool.

Iplanet-ejbc

Invokes iPlanet’s ejbc tool.

ejbjar

Invokes the ejbjar tool (used for many application servers).

wlrun

Starts a WebLogic server.

Wlstop

Stops a WebLogic server.

The Perforce source control tasks are shown in Table 1-8.

Table 1-8. Perforce Ant tasks

Task name

Description

P4Sync

Synchronizes files with the Perforce server.

P4Change

Gets a list of current changes from the Perforce server.

P4Edit

Checks out files for editing.

P4Submit

Checks in files.

P4Have

Lists all client-viewable files.

P4Label

Makes a label based on the files in the current workspace.

P4Labelsync

Syncs with a label.

P4Counter

Gets or sets a counter value. (Counters can be used to keep track of build events, such as the number of builds that have been executed.)

P4Reopen

Reopens a checked-out file.

P4Revert

Reverts file(s) that have been changed to their original content.

P4Add

Adds file(s) to the list to be submitted to the server.

P4Delete

Deletes file(s).

P4Integrate

Integrates file(s). You must specify the source file(s) and the target file(s).

P4resolve

Resolves file(s) in case others have made changes to the file(s) when you were working on it.

P4Fstat

Views differences with the server.

Many tasks for Microsoft Visual Source Safe are detailed in Table 1-9.

Table 1-9. Visual Source Safe tasks

Task name

Description

vssget

Gets a copy of a particular VSS file.

Vsslabel

Makes a new label for the current version of a file.

Vsshistory

Displays a file’s history in the project.

Vsscheckin

Checks in files to VSS.

Vsscheckout

Checks out files from VSS.

Vssadd

Adds a new file to VSS.

Vsscp

Changes the project considered the current project by VSS.

Vsscreate

Makes a new project.

Continuing with source control repository tasks, Table 1-10 shows tasks for working with Starteam source control.

Table 1-10. Starteam Ant tasks

Task name

Description

STCheckout

Checks out files from StarTeam projects

STCheckin

Checks in files to StarTeam projects

STLabel

Creates a new label for this project

STList

Displays a list of files in the project

Table 1-11 shows tasks for the Continuous source control server.

Table 1-11. Continuous/Synergy Ant tasks

Task name

Description

CCMCheckin

Checks in files to the source manager

CCMCheckout

Checks out files from the source manager

CCMCheckinTask

Checks in all files in the current task

CCMReconfigure

Reconfigures an existing command

CCMCreateTask

Creates a task

Finally, Table 1-12 lists optional tasks for supporting SourceGear’s SourceOffSite Visual Source Safe plug-in.

Table 1-12. SourceOffSite Ant tasks

Task name

Description

Sosget

Gets a read-only copy of a file

Soslabel

Creates a label for the current project

Soscheckin

Checks in files to the source manager

Soscheckout

Checks out files from the source manager

In addition to the built-in and the optional tasks, Ant supports third-party and custom tasks (yes, that’s a large number of tasks you can use!). As you’d expect, third-party tasks add functionality to Ant; as an example, take a look at the third-party tasks available for free at http://ant-contrib.sf.net/, which includes a set of tasks for use with Ant and C++. Creating Ant tasks is easier than you might think, and you’re going to create your own in Chapter 11.

Dependent Tasks

Typically, you create an Ant build file with a default target named something like main; this target then acts as a master target, handling program flow for the entire build process. It tells Ant to run other targets and specifies their ordering. This is accomplished through the target element’s depends attribute.

For example, you might want to add a target named compile to compile your code and add another target called compress to put the compiled code into a JAR file:

<?xml version="1.0" ?>
<project default="main">

    <target name="main">
        <echo>
            Building the .jar file.
        </echo>
    </target>
  
    <target name="compile">
               <javac srcdir="."/>
               </target>
  
               <target name="compress">
               <jar jarfile="Project.jar" basedir="." includes="*.class" />
               </target>

</project>

Ensure that the compile and compress targets runin that orderby assigning the string “compile, compress” to the default target’s depends attribute:

<?xml version="1.0" ?>
<project default="main">

    <target name="main" depends="compile, compress">
        <echo>
            Building the .jar file.
        </echo>
    </target>
  
    <target name="compile">
        <javac srcdir="."/>
    </target>
  
    <target name="compress">
        <jar jarfile="Project.jar" basedir="." includes="*.class" />
    </target>

</project>

When you run Ant, it’ll look for build.xml and execute the default target, which the project element indicates is main. The main target’s depends attribute tells Ant to run the compile target and then run the compress target before running the body of the main target.

Warning

Though you use this attribute to indicate the order targets should run in, targets can still fail, which means you’re not guaranteed that they will all behave as expected. Generally, a failed target will stop the Ant build process, but that’s not always the case.

Bear in mind that dependencies can be nested inadvertently. For example, take a look at this build file fragment:

<target name="find"/>
<target name="inspect" depends="find"/>
<target name="test" depends="inspect"/>
<target name="purchase" depends="test, inspect, find"/>

If target purchase was the default target, you might think that targets test, inspect, find, and purchase were executed in that order. However, target test depends on target inspect, which depends on find, and so on. An Ant target gets executed once even when multiple targets depend on it. Because the dependencies of a task are executed before the task, the actual order of execution here is find, inspect, test, and then purchase.

Properties

In addition to targets and tasks, the third pillar of an Ant build file is its properties. Properties are name-value pairs that act much like constants in Java code. You set the value of a property with the property element and can refer to that property by name throughout your build file. You can insert the value of a property in task attributes by dereferencing the property name with ${ property-name }.

For example, if you had a property named bin corresponding to the output directory of your build and wanted to refer to that directory, you could refer to it as ${bin} when you assign it to task attributes in your build file. If you wanted to refer to the archives subdirectory in that output directory, you could refer to it as ${bin}/archives. The advantages to this approach should be obvious to anyone who’s had to change a directory name in 300 different places throughout an application.

Tip

A forward slash will work as a directory delimiter even on Windows systems; Ant is smart enough to know what you mean.

Property attributes

Properties are used the same way as constants are in Java: they let you collect definitions in one centralized place rather than having them dispersed throughout a build file. When you want to change property values, you can make changes in one location and know that they will propagate throughout the build file. You can see the attributes of the property element in Table 1-13.

Table 1-13. The property element’s attributes

Attribute

Description

Required

classpath

The classpath to use when looking for a resource.

No

classpathref

The classpath to use when looking for a resource, which can then be given as a reference to a path element later in the build file.

No

environment

The prefix to use when retrieving environment variables. For example, if you specify environment="env“, you will be able to access operating-system-specific environment variables as property names like ${env.PATH}.

A resource, file, url, or environment attribute is required when not using the name attribute.

file

The name of a property file to load values from.

A resource, file, url, or environment attribute is required when not using the name attribute.

location

Sets the property to the absolute filename of the given file. If an absolute path is supplied, it’s left unchanged (with / and \ characters converted for the current platforms). Otherwise, the supplied filename is taken as a path relative to the project’s base directory and then expanded.

A value, location, or refid element is required when using the name attribute.

name

The name of the property to set.

No

prefix

The prefix to add to properties loaded from a file or a resource. A . is appended to the prefix if none is specified.

No

refid

A reference to a (previously) defined object.

A value, location, or refid element is required when using the name attribute.

resource

The resource name of the property file, used for searching the classpath.

A resource, file, url, or environment attribute is required when not using the name attribute.

url

The URL from which to read properties.

A resource, file, url, or environment attribute is required when not using the name attribute.

value

The value of this property.

A value, location, or refid element is required when using the name attribute.

As an example, you can store a message that displays “Building the .jar file.” in a property named message:

<?xml version="1.0" ?>
<project default="main">

    <property name="message" value="Building the .jar file." />
        .
        .
        .
</project>

Tip

You declare properties outside your targets. As of Ant 1.6, all tasks can be declared outside of targets (earlier versions only allowed property, typedef and taskdef to be used outside of a target element). When you define tasks external to a specific target, those tasks are evaluated before any targets are executed.

You can echo the message to the console like this:

<?xml version="1.0" ?>
<project default="main">

    <property name="message" value="Building the .jar file." />
        .
        .
        .
    <target name="main" depends="compile, compress">
        <echo>
                  ${message}
                  </echo>
    </target>
  
</project>

Properties are frequently used to hold pathnames, and the property element’s location attribute is useful in this context. Suppose you’re storing your source code in a subdirectory of the current directory named source and want to deploy the .jar file created by this build file to a directory named bin. You can create properties corresponding to these directories:

<?xml version="1.0" ?>
<project default="main">

    <property name="message" value="Building the .jar file." />
    <property name="src" location="source" />
                  <property name="output" location="bin" />

    <target name="main" depends="init, compile, compress">
        <echo>
            ${message}
        </echo>
    </target>
        .
        .
        .
</project>

The default target in this build file, main, depends on an init target where the mkdir task (detailed in Chapter 3) is used to create the output directory:

<?xml version="1.0" ?>
<project default="main">

    <property name="message" value="Building the .jar file." />
    <property name="src" location="source" />
    <property name="output" location="bin" />

    <target name="main" depends="init, compile, compress">
        <echo>
            ${message}
        </echo>
    </target>
  
    <target name="init">
        <mkdir dir="${output}" />
    </target>
        .
        .
        .
</project>

Now you can compile the Java source code from the ${src} directory, placing the created .class file in the ${output} directory, and create the Project.jar file in the ${output} directory, all using properties:

<?xml version="1.0" ?>
<project default="main">

    <property name="message" value="Building the .jar file." />
    <property name="src" location="source" />
    <property name="output" location="bin" />

    <target name="main" depends="init, compile, compress">
        <echo>
            ${message}
        </echo>
    </target>
  
    <target name="init">
        <mkdir dir="${output}" />
    </target>
  
   
                      <target name="compile">
                  <javac srcdir="${src}" destdir="${output}" />
                  </target>
  
                  <target name="compress">
                  <jar destfile="${output}/Project.jar" basedir="${output}" 
             includes="*.class" />
                  </target>
</project>

The relative paths used will be expanded in a platform-specific way, something like this in Unix:

-bash-2.05b$ ant -f properties.xml
Buildfile: properties.xml

init:
    [mkdir] Created dir: /home/steve/bin

compile:
    [javac] Compiling 1 source file to /home/steve/bin

compress:
      [jar] Building jar: /home/steve/bin/Project.jar

main:
     [echo] 
     [echo]             Building the .jar file.
     [echo]         

BUILD SUCCESSFUL
Total time: 2 seconds

Here’s the Windows version:

C:\ant\ch01>ant -f properties.xml
Buildfile: properties.xml

init:
    [mkdir] Created dir: C:\ant\ch01\bin

compile:
    [javac] Compiling 1 source file to C:\ant\ch01\bin

compress:
      [jar] Building jar: C:\ant\ch01\bin\Project.jar

main:
     [echo]
     [echo]             Building the .jar file.
     [echo]

BUILD SUCCESSFUL
Total time: 4 seconds

Built-in properties

Ant gives you access to the same system properties you’d have access to in Java code, as if they were Ant properties. For example, if you want to determine the name of the operating system, you can refer to ${os.name} in your build file.

Tip

For a list of system properties, see the Java documentation of the System.getProperties( ) method.

Ant has some additional Ant-specific properties:

ant.file

Contains the absolute path of the build file

ant.java.version

Contains the JVM version Ant is using (can hold only 1.1, 1.2, 1.3, 1.4 and [as of Ant 1.6] 1.5)

ant.project.name

Holds the name of the project that is executing (set with the name attribute of project)

ant.version

Contains the version of Ant running

basedir

Holds the absolute path of the project’s base directory (set with the basedir attribute of project)

Running Ant

Running Ant from the command-line is simple:

%ant [options] [target [target2 [target3] ...]]

Command-Line Options

options are one or more of the command-line options that begin with a hyphen, listed in Table 1-14; target, target2, etc., are the specific targets you want to run in the event you don’t want to defer to the project element’s default target.

Tip

Entering ant -help on the command line generates a list of command-line options.

Table 1-14. Ant command-line options

Name

Description

-buildfile file, or -f file, or -file file

Runs the build file specified by file.

-Dproperty=value

Sets a property called property with a value of value, and passes it to Ant.

-debug, -d

Prints debugging information.

-diagnostics

Prints diagnostics about Ant.

-emacs, -e

Creates plain, emacs-friendly logging information.

-find file, or -s file

Searches for the build file (named file) along the directory structure towards the root.

-help, -h

Prints help information.

-inputhandler class

Specifies the class that will handle user text input.

-keep-going, -k

Continues to execute targets even if prior targets fail. Only targets that do not depend on failed targets are attempted.

-l file, or -l file

Uses file to log to.

-lib path

Specifies the classpath on which to search for JARs and library classes.

-listener classname

Adds an instance of classname as a listener, which is alerted when build events occur (e.g., starting and stopping of the build process).

-logger classname

Specifies the class to handle logging of Ant’s output.

-noinput

Turns off interactive input.

-projecthelp, -p

Prints the project’s help information (if there is any).

-propertyfile file

Loads properties from the specified file.

-quiet, -q

Reduces Ant messages to the minimum possible.

-verbose, -v

Specifies verbose output.

-version

Prints the version of Ant being used.

Executing Ant

If you want to use a build file named build.xml and want to run the default target, enter ant in the directory containing the build file:

%ant

For example, if you ran the build file from Example 1-2, that command gives this result:

-bash-2.05b$ ant
Buildfile: build.xml

compile:
    [javac] Compiling 1 source file

compress:
      [jar] Building jar: /home/httpd/vhosts/builder/Project.jar

main:
     [echo] 
     [echo]             Building the .jar file.
     [echo]         

BUILD SUCCESSFUL
Total time: 2 seconds

Each build file requires a default target, but you can specify the target(s) you want Ant to run via the command line. For example, add a target named clean to the build file (using Example 1-2 as a starting point):

<project default="main">
    <target name="main" depends="compile, compress">
        <echo>
            Building the .jar file.
        </echo>
    </target>
  
    <target name="compile">
        <javac srcdir="."/>
    </target>
  
  <target name="compress">
        <jar jarfile="Project.jar" basedir="." includes="*.class" />
  </target>

    <target name="clean">
               <delete file="*.class"/>
               <delete file="*.jar"/>
               </target>
</project>

You can then specify the clean target from the command line:

%ant clean

If you want to run multiple targets, you can list them (in the order they should be run):

%ant clean compile compress

Tip

If you don’t want to allow a target to be run from the command line, you can start the target name with a hyphen (e.g., -clean). This will make Ant think the target is a command-line option, and since -clean isn’t a valid command-line option, Ant will refuse to run that target directly.

By default, the build file that Ant looks for is build.xml, but you can name the file as you want.

Tip

The downloadable example code for Ant has multiple build filenames to make the separation of examples clearer.

For example, if you have a build file named project.xml that you want to use, you can specify that Ant should use that build file with -f (or -file or -buildfile):

%ant -f project.xml

Tip

If you use the -find file option, Ant will search for a build file first in the current directory, then in the parent directory, and so on, until a build file with the supplied name is found or the root of the filesystem is reached.

Customizable Environment Variables

Ant scripts, which start Ant, use some customizable environment variables:

JAVACMD

Holds the full path of the Java executable. Use this to launch a different JVM than JAVA_HOME /bin/java(.exe).

ANT_OPTS

Command-line arguments that should be passed to the JVM unchanged.

ANT_ARGS

Ant command-line arguments. These may be used, for example, to point to a different logger, a new listener, or to include the -find flag in all invocations of Ant.

Tip

The Ant wrapper script for Unix will read the file ~/.antrc before it starts running. On Windows, the Ant wrapper batchfile ant.bat invokes %HOME% \antrc_pre.bat at the start of the Ant process and %HOME% \antrc_post.bat at the end of that process. You can use these files to set or unset environment variables that should only be used during the execution of Ant.

Failed Builds

Every Ant developer has builds that fail for one reason or another. Ant does its best to pinpoint the problem. For example, say you misspelled the name of the javac task:

<?xml version="1.0" ?>
<project default="main">
    <target name="main" depends="compile, compress">
        <echo>
            Building the .jar file.
        </echo>
    </target>
  
    <target name="compile">
        <jjavac srcdir="."/>
    </target>
        .
        .
        .

Ant will diagnose this problem when it runs and give you some feedback:

%ant 
build.xml:10: Could not create task or type of type: jjavac.

Ant could not find the task or a class this task relies upon.

This is common and has a number of causes; the usual
solutions are to read the manual pages then download and
install needed JAR files, or fix the build file:
 - You have misspelt 'jjavac'.
   Fix: check your spelling.
 - The task needs an external JAR file to execute
   and this is not found at the right place in the classpath.
   Fix: check the documentation for dependencies.
   Fix: declare the task.
 - The task is an Ant optional task and optional.jar is absent
   Fix: look for optional.jar in ANT_HOME/lib, download if needed
 - The task was not built into optional.jar as dependent
   libraries were not found at build time.
   Fix: look in the JAR to verify, then rebuild with the needed
   libraries, or download a release version from apache.org
 - The build file was written for a later version of Ant
   Fix: upgrade to at least the latest release version of Ant
 - The task is not an Ant core or optional task
   and needs to be declared using <taskdef>.

Remember that for JAR files to be visible to Ant tasks implemented
in ANT_HOME/lib, the files must be in the same directory or on the
classpath

Please neither file bug reports on this problem, nor email the
Ant mailing lists, until all of these causes have been explored,
as this is not an Ant bug.

Total time: 0 seconds

Sometimes errors won’t stop a build, and you may want to change that behavior so the build will terminate when there’s been any kind of problem. Most tasks have a failonerror attribute, which is set to false by default. Setting this attribute’s value to true makes the build fail if the task encounters an error, allowing you to stop a build if a specific task generates errors .

Keep in mind that this won’t affect your build in the case where you’ve previously executed the build and your output files are up to date. By default, Ant tasks check to see if the output files they’re supposed to create are current (i.e., the output file is more recent than the files used to create it); if they are, Ant tasks won’t recreate them because Ant considers the target executed. For example, here’s what you’d see when you run the example build file a second timeAnt displays the names of the various targets but, because they’re up to date, it doesn’t execute them:

%ant
Buildfile: build.xml

compile:

compress:

main:
     [echo]
     [echo]             Building the .jar file.
     [echo]

BUILD SUCCESSFUL
Total time: 3 seconds

Tip

Ant doesn’t come with a built-in debugger, which can make it tough to troubleshoot build files. However, one of the items under development in the Java Eclipse IDE is an Ant build file debugger. Chapter 11 has more on integrating Ant into Eclipse.

Verbose Output

You can control the amount of output Ant gives you when it runs with the -verbose, -quiet, and -debug command-line options. If you ask Ant to be quiet, it won’t display anything except for build failure or success, total build time, and any text you specifically output via the echo task. Here’s an example of a quiet build:

%ant -quiet
     [echo]
     [echo]             Building the .jar file.
     [echo]

BUILD SUCCESSFUL
Total time: 2 seconds

On the other side of the coin, the -verbose option gives you a lot more information than normal, including whether Ant is skipping up-to-date output files, what OS or JDK you’re using, and a lot more. Here’s what you might see from a verbose build on Unix:

-bash-2.05b$ ant -verbose
Apache Ant version 1.6.1 compiled on February 12 2004
Buildfile: build.xml
Detected Java version: 1.4 in: /opt/j2sdk1.4.2_02/jre
Detected OS: Linux
parsing buildfile /home/build.xml
Project base dir set to: /home
Build sequence for target `main' is [compile, compress, main]
Complete build sequence is [compile, compress, main, clean, ]

compile:
    [javac] Project.class skipped - don't know how to handle it
    [javac] Project.jar skipped - don't know how to handle it
    [javac] Project.java omitted as Project.class is up to date.
    [javac] build.xml skipped - don't know how to handle it

compress:
      [jar] Project.class omitted as Project.class is up to date.

main:
     [echo] 
     [echo]             Building the .jar file.
     [echo]         

BUILD SUCCESSFUL
Total time: 1 second

This output shows that Ant is skipping up-to-date output targets. Here’s similar output in Windows:

%ant -verbose
Apache Ant version 1.6.1 compiled on February 12 2004
Buildfile: build.xml
Detected Java version: 1.4 in: C:\jdk1.4
Detected OS: Windows 2000
parsing buildfile C:\ant\ch01\build.xml with URI = file:///C:/ant/ch01/build.xml

Project base dir set to: C:\ant\ch01
Build sequence for target `main' is [compile, compress, main]
Complete build sequence is [compile, compress, main, clean, ]

compile:
    [javac] Project.class skipped - don't know how to handle it
    [javac] Project.jar skipped - don't know how to handle it
    [javac] Project.java omitted as Project.class is up to date.
    [javac] build.xml skipped - don't know how to handle it

compress:
      [jar] Project.class omitted as Project.class is up to date.

main:
     [echo]
     [echo]             Building the .jar file.
     [echo]

BUILD SUCCESSFUL
Total time: 2 seconds

The -debug options prints out even more information—often pages of it—which isn’t reproduced here. Included in a debugging build is information about classes as they’re loaded, classes that Ant looked for but couldn’t find, the locations where Ant is picking up library files, and almost everything else you could think of.

Another useful command-line option for displaying information is the -projecthelp option, which prints out a list of the build file’s targets. Targets that include a description attribute are listed as Main targets; those without a description are listed as “Subtargets”, and then the “Default” target is listed.

Here’s the example build file, with the addition of a description attribute for each target element:

<?xml version="1.0" ?>
<project default="main">
    <target name="main" depends="compile, compress" description="Main target">
        <echo>
            Building the .jar file.
        </echo>
    </target>
  
    <target name="compile" description="Compilation target">
        <javac srcdir="."/>
    </target>
  
  <target name="compress" description="Compression target">
        <jar jarfile="Project.jar" basedir="." includes="*.class" />
  </target>
</project>

Here’s what you’d see when running Ant with the -projecthelp option:

%ant -projecthelp
Buildfile: build.xml

Main targets:

 compile   Compilation target
 compress  Compression target
 main      Main target
Default target: main

Logging and Libraries

You can log the output of running Ant using the -logfile option. For example, here’s how you’d sent output to a file named file.log:

%ant -logfile file.log

You can log part of a build file’s results with the record task; for example, if you were using the javac task to compile code and wanted to log the output of this task to a file named log.txt, you could start and stop that logging this way:

<record name="log.txt" action="start"/>
    <javac ... />
<record name="log.txt" action="stop"/>

Another handy option is the -lib option, which adds additional directories to be searched for .jar or .class files. Here’s an example, which adds /home/ant/morejars to the library search path:

%ant -lib /home/ant/morejars

The -lib option is useful when you’re working on a system where you don’t have access to the Ant lib directory as is often the case when dealing with Internet Service Providers (ISPs). Using this option, you can make sure Ant has access to JAR files needed for Ant’s optional tasks without having to load them into directories you don’t have permission to access.

Tip

Before Ant 1.6, all JARS in the ANT_HOME /lib would be added to the CLASSPATH used to run Ant. Since Ant 1.6, two directories are scanned—ANT_HOME /lib and .ant/lib—in the Java user home directory. You can place additional library files in this directory if you don’t have access to ANT_HOME /lib. The location of the Java user home directory depends on your JVM settings. In Unix, it’s usually your home directory (so you’d store additional Ant libraries in, for example, /home/ username /.ant/lib). In Windows, it’s usually C:\Documents and Settings\ username (so you’d store additional Ant libraries in C:\Documents and Settings\ username \.ant\lib). To determine where your Java user home is, use this element in a build file:

<echo>${user.home}</echo>

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required