BUY THIS BOOK

Safari Books Online

What is this?

Looking to Reprint this content?


Ant:  The Definitive Guide
Ant: The Definitive Guide By Jesse E. Tilly, Eric M. Burke
May 2002
Pages: 288

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Ant Jumpstart
It is likely that you have already downloaded and installed Ant and are ready to see an example of how it works. If so, then this chapter is for you. Here, we walk through a very basic buildfile example, followed by a full description of Ant's command-line options. If you prefer to walk through the step-by-step installation procedure first, you might want to skip ahead to Chapter 2 and then come back to this material.
We do not attempt to explain every detail of the buildfile in this chapter. For a more comprehensive example, see Chapter 3.
For our example, we start with the directory and file structure shown in Figure 1-1. The shaded boxes represent files, and the unshaded boxes represent directories.
Figure 1-1: Starting point for our example buildfile
You can download this example from this book's web page, located at http://www.oreilly.com/catalog/anttdg/.
The Ant buildfile, build.xml, exists in the project base directory. This is typical, although you are free to use other filenames or put the buildfile somewhere else. The src directory contains the Java source code organized into an ordinary package structure. For the most part, the content of the source files is not important. However, we want to point out that PersonTest.java is a unit test that will be excluded from the generated JAR file.
Our sample buildfile causes Ant to create the directory tree and files shown inside the shaded, dashed block in Figure 1-2. It also compiles the Java source code, creates oreilly.jar, and provides a "clean" target to remove all generated files and directories.
Figure 1-2: Directories and files created by our sample buildfile
Now let's look at the buildfile that makes this possible.
Ant buildfiles are written using XML. Example 1-1 shows the complete Ant buildfile for our example. This is simpler than most real-world buildfiles, but does illustrate several core concepts required by nearly every Java project.
Example 1-1. build.xml
<?xml version="1.0"?>

<!-- build.xml - a simple Ant buildfile -->
<project name="Simple Buildfile" default="compile" basedir=".">

  <!-- The directory containing source code -->
  <property name="src.dir" value="src"/>

  <!-- Temporary build directories -->
  <property name="build.dir" value="build"/>
  <property name="build.classes" value="${build.dir}/classes"/>
  <property name="build.lib" value="${build.dir}/lib"/>

  <!-- Target to create the build directories prior to the -->
  <!-- compile target. -->
  <target name="prepare">
    <mkdir dir="${build.dir}"/>
    <mkdir dir="${build.classes}"/>
    <mkdir dir="${build.lib}"/>
  </target>

  <target name="clean" description="Removes all generated files.">
    <delete dir="${build.dir}"/>
  </target>

  <target name="compile" depends="prepare"
          description="Compiles all source code.">
    <javac srcdir="${src.dir}" destdir="${build.classes}"/>
  </target>

  <target name="jar" depends="compile"
          description="Generates oreilly.jar in the 'dist' directory.">
    <!-- Exclude unit tests from the final JAR file -->
    <jar jarfile="${build.lib}/oreilly.jar" 
         basedir="${build.classes}"
         excludes="**/*Test.class"/>
  </target>

  <target name="all" depends="clean,jar"
          description="Cleans, compiles, then builds the JAR file."/>

</project>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Files and Directories
For our example, we start with the directory and file structure shown in Figure 1-1. The shaded boxes represent files, and the unshaded boxes represent directories.
Figure 1-1: Starting point for our example buildfile
You can download this example from this book's web page, located at http://www.oreilly.com/catalog/anttdg/.
The Ant buildfile, build.xml, exists in the project base directory. This is typical, although you are free to use other filenames or put the buildfile somewhere else. The src directory contains the Java source code organized into an ordinary package structure. For the most part, the content of the source files is not important. However, we want to point out that PersonTest.java is a unit test that will be excluded from the generated JAR file.
Our sample buildfile causes Ant to create the directory tree and files shown inside the shaded, dashed block in Figure 1-2. It also compiles the Java source code, creates oreilly.jar, and provides a "clean" target to remove all generated files and directories.
Figure 1-2: Directories and files created by our sample buildfile
Now let's look at the buildfile that makes this possible.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Ant Buildfile
Ant buildfiles are written using XML. Example 1-1 shows the complete Ant buildfile for our example. This is simpler than most real-world buildfiles, but does illustrate several core concepts required by nearly every Java project.
Example 1-1. build.xml
<?xml version="1.0"?>

<!-- build.xml - a simple Ant buildfile -->
<project name="Simple Buildfile" default="compile" basedir=".">

  <!-- The directory containing source code -->
  <property name="src.dir" value="src"/>

  <!-- Temporary build directories -->
  <property name="build.dir" value="build"/>
  <property name="build.classes" value="${build.dir}/classes"/>
  <property name="build.lib" value="${build.dir}/lib"/>

  <!-- Target to create the build directories prior to the -->
  <!-- compile target. -->
  <target name="prepare">
    <mkdir dir="${build.dir}"/>
    <mkdir dir="${build.classes}"/>
    <mkdir dir="${build.lib}"/>
  </target>

  <target name="clean" description="Removes all generated files.">
    <delete dir="${build.dir}"/>
  </target>

  <target name="compile" depends="prepare"
          description="Compiles all source code.">
    <javac srcdir="${src.dir}" destdir="${build.classes}"/>
  </target>

  <target name="jar" depends="compile"
          description="Generates oreilly.jar in the 'dist' directory.">
    <!-- Exclude unit tests from the final JAR file -->
    <jar jarfile="${build.lib}/oreilly.jar" 
         basedir="${build.classes}"
         excludes="**/*Test.class"/>
  </target>

  <target name="all" depends="clean,jar"
          description="Cleans, compiles, then builds the JAR file."/>

</project>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Running Ant
We are going to assume that Ant is installed properly. If you have any doubts on this point, now is the time to read Chapter 2 and get everything up and running.
To execute the tasks in the default target, compile, type the following command from the directory containing our sample build.xml file:
 ant
Ant will open the default buildfile, which is build.xml, and execute that buildfile's default target (which in our case is compile). You should see the following output, assuming your directory is called antbook:
Buildfile: build.xml

prepare:
    [mkdir] Created dir: C:\antbook\build
    [mkdir] Created dir: C:\antbook\build\classes
    [mkdir] Created dir: C:\antbook\build\lib

compile:
    [javac] Compiling 3 source files to C:\antbook\build\classes

BUILD SUCCESSFUL

Total time: 5 seconds
As Ant runs, it displays the name of each target executed. As our example output shows, Ant executes prepare followed by compile. This is because compile is the default target, which has a dependency on the prepare target. Ant prints the name of each task within brackets, along with other messages unique to each task.
In our sample output, [javac] is the name of the Ant task, not necessarily the name of the Java compiler. If you are using IBM's Jikes, for instance, [javac] is still displayed because that is the Ant task that is running Jikes behind the scenes.
When you invoke Ant without specifying a buildfile name, Ant searches for a file named build.xml in the current working directory. You aren't limited to this default; you can use any name you like for the buildfile. For example, if we call our buildfile proj.xml, we must type this command, instead:
ant -buildfile proj.xml
We can also explicitly specify one or more targets to run. We can type ant clean to remove all generated code, for instance. If our buildfile is called proj.xml, and we want to execute the clean target, we type ant -buildfile proj.xml clean. Our output would look something like this:
Buildfile: proj.xml

clean:
   [delete] Deleting directory C:\antbook\build

BUILD SUCCESSFUL

Total time: 2 seconds
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Ant Command-Line Reference
The syntax to use to invoke Ant from the command-line is as follows:
ant [option [option...]] [target [target...]]

option := {-help
          |-projecthelp
          |-version
          |-quiet
          |-verbose
          |-debug
          |-emacs
          |-logfile filename
          |-logger classname
          |-listener classname
          |-buildfile filename
          |-Dproperty=value
          |-find filename}
The syntax elements are as follows:
-help
Displays help information describing the Ant command and its options.
-projecthelp
Displays any user-written help documentation included in the buildfile. This is text from the description attribute of any <target>, along with any text contained within a <description> element. Targets with description attributes are listed as "Main targets," those without are listed as "Subtargets."
-version
Causes Ant to display its version information and exit.
-quiet
Suppresses most messages not originated by an echo task in the buildfile.
-verbose
Displays detailed messages for every operation during a build. This option is exclusive to -debug.
-debug
Displays messages that Ant and task developers have flagged as debugging messages. This option is exclusive to -verbose.
-emacs
Formats logging messages so that they're easily parsed by Emacs' shell-mode; i.e., prints the task events without preceding them with an indentation and a [ taskname ].
-logfile filename
Redirects logging output to the specified file.
-logger classname
Specifies a class to handle Ant logging. The class specified must implement the org.apache.tools.ant.BuildLogger interface.
-listener classname
Declares a listening class for Ant to add to its list of listeners. This option is useful when integrating Ant with IDEs or other Java programs. Read more about listeners in Chapter 6. The specified listening class must be written to handle Ant's build messaging.
-buildfile filename
Specifies the buildfile Ant should operate on. The default buildfile is
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Buildfile Outline
Shown next is a generic buildfile good for using as a template. A buildfile consists of the <project> element with its nested <target>, <property>, and <path> elements.
<project default="all">
  <property name="a.property" value="a value"/>
  <property name="b.property" value="b value"/>

  <path id="a.path">
    <pathelement location="${java.home}/jre/lib/rt.jar"/>
  </path>

  <target name="all">
    <javac srcdir=".">
      <classpath refid="a.path"/>
    </javac>
  </target>
</project>
Some notes about buildfiles to remember:
  • All buildfiles require the <project> element and at least one <target> element.
  • There is no default value for the <project> element's default attribute.
  • Buildfiles do not have to be named build.xml. However, build.xml is the default name for which Ant searches.
  • You can have only one <project> element per buildfile.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Learning More
We have only scratched the surface in this chapter, but this does give you an idea of what Ant buildfiles look like and how to run the command-line ant script. As mentioned earlier, Chapter 3 presents a much more sophisticated example with a great deal more explanation of what is going on in each step.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Installation and Configuration
This chapter describes where to get Ant, explains the differences between the various distributions, and covers the most common installation scenarios. As a portable Java application, Ant works very consistently on many different platforms. This should not be a surprise, given that Ant was written as an alternative to platform-specific make utilities. Most differences manifest themselves in the Ant startup scripts, which are understandably different on Windows and Unix systems. Once Ant is installed and configured, it does a remarkable job of insulating you from differences between platforms.
Ant is open source software from the Apache Software Foundation, available in binary and source forms. It is available from the Ant home page located at http://jakarta.apache.org/ant/; you can choose either a release build or a nightly build. To ease installation, different distributions are provided for Unix and Windows systems.
The direct link to the list of nightly builds is http://jakarta.apache.org/builds/jakarta-ant/nightly/. The nightly builds include the latest bug fixes and features, and are a constantly changing target. The vast majority of software development teams should opt instead for a release version of Ant, available at the following URLs:
http://jakarta.apache.org/builds/jakarta-ant/release/v1.4.1/bin/
The binary distribution.
http://jakarta.apache.org/builds/jakarta-ant/release/v1.4.1/src/
The source distribution corresponding to the current binary distribution.
For earlier releases of Ant, merely substitute 1.1, 1.2, or 1.3 for the version number in these URLs.
Each directory contains .tar.gz files for Unix users, .zip files for Windows users, .asc files, and a .jar file. The .asc files contain PGP signatures, useful for determining the authenticity of the distributions. Usually, you can safely ignore these files. The jakarta-ant-1.4.1-optional.jar file contains Ant's optional tasks, and is described later in this chapter. We recommend that you download this file.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Distribution
Ant is open source software from the Apache Software Foundation, available in binary and source forms. It is available from the Ant home page located at http://jakarta.apache.org/ant/; you can choose either a release build or a nightly build. To ease installation, different distributions are provided for Unix and Windows systems.
The direct link to the list of nightly builds is http://jakarta.apache.org/builds/jakarta-ant/nightly/. The nightly builds include the latest bug fixes and features, and are a constantly changing target. The vast majority of software development teams should opt instead for a release version of Ant, available at the following URLs:
http://jakarta.apache.org/builds/jakarta-ant/release/v1.4.1/bin/
The binary distribution.
http://jakarta.apache.org/builds/jakarta-ant/release/v1.4.1/src/
The source distribution corresponding to the current binary distribution.
For earlier releases of Ant, merely substitute 1.1, 1.2, or 1.3 for the version number in these URLs.
Each directory contains .tar.gz files for Unix users, .zip files for Windows users, .asc files, and a .jar file. The .asc files contain PGP signatures, useful for determining the authenticity of the distributions. Usually, you can safely ignore these files. The jakarta-ant-1.4.1-optional.jar file contains Ant's optional tasks, and is described later in this chapter. We recommend that you download this file.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Installation
Regardless of platform, downloading Ant is the first step to installing the software. The files can be downloaded to a temporary directory and then uncompressed to any desired directory. After the download step, the process differs depending on whether you've downloaded the binary distribution or the source distribution.
Windows users should avoid directories with spaces such as "Program Files," as this can cause problems with the provided batch files.
The Ant documentation warns against installing Ant's JAR files in Java's lib/ext directory. If you do, you are likely to encounter class-loading problems with some Ant tasks. Instead, you should leave Ant's JAR files in the Ant distribution directory.
Ant does not provide an installation program; it runs from wherever you choose to copy the files and directories. Table 2-1 lists the directories that ultimately get created under your main Ant directory.
Table 2-1: Directories provided with Ant
Directory
Description
bin
Batch files, Perl scripts, and shell scripts for running Ant.
docs
Ant documentation.
lib
Libraries required by Ant to run.
src
Source code for Ant. Provided only in the source distribution.
We will cover the binary installation first, which should suffice for most users. The term "binary" just means that everything is compiled and packaged into JAR files for easy execution — you don't need to compile Ant from source. The source distribution, covered later in this chapter, must be compiled before it is usable.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Configuration
Once Ant is installed properly, it requires very little additional configuration. Provided the ant.bat batch file (or ant shell script) is installed in a directory that is included in your system path, you should be able to run Ant from any command prompt.
You do not technically have to use the provided ant or ant.bat script to run Ant. You can run Ant manually, as long as the following items are configured:
  • The system CLASSPATH includes ant.jar and any JAXP-compliant XML parser.
  • For JDK 1.1, classes.zip must be added to the CLASSPATH. For Java 2, tools.jar must be added. This is necessary for tasks like javac.
  • Many tasks require that the ant.home Java system property be set to the Ant installation directory. This is accomplished by launching the JVM with the -D flag, as shown shortly.
  • JAR files for optional tasks must be added to the CLASSPATH.
Provided that these items are all set properly, you can use the following command to invoke Ant:
java -Dant.home=pathToAnt org.apache.tools.ant.Main
Understanding how to set up and run Ant manually might be useful if you are making customizations to Ant and wish to run it using your IDE's debugger.
Early versions of Ant (prior to Version 1.4) include Sun's Java API for XML Parsing (JAXP) Version 1.0. Ant Versions 1.4 and later ship with JAXP 1.1, as described in the next paragraph. JAXP is an API allowing Java programs to use XML parsers from different vendors in a portable way. The JAXP JAR files, jaxp.jar and parser.jar, are found in ANT_HOME /lib. These, along with any other JAR files found in this directory, are automatically added (by ant or ant.bat) to the CLASSPATH used by Ant. jaxp.jar contains the JAXP API, while parser.jar is an XML parser implementation from Sun.
If you require DOM Level 2 or SAX 2.0 XML support, then JAXP 1.0 is insufficient. For this level of XML, you should upgrade Ant to support JAXP 1.1, available at http://java.sun.com/xml/. This won't affect you if you are using Ant 1.4 or later, since it ships with JAXP 1.1. Since JAXP 1.1 is backwards compatible with JAXP 1.0, you can safely replace the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: The Buildfile
Building projects with Ant requires you to focus on two things: project organization and the Ant buildfile. Rather than distinct focal points, these subjects are two sides of the same coin; they are closely related and any decision made in the design of one affects the design and implementation of the other. In this chapter, we show how to design a project using Ant to manage the build process, and how to write a buildfile for that project. As we go through the sample project, we explain how we arrive at particular design decisions for the layout of the project, as well as for the various parts of the buildfile. Not every project can fit the model we present, but many can; we hope this exercise will prepare you for writing buildfiles in other development projects.
Before we begin, however, you should understand the features of the buildfile itself. The buildfile is the most important aspect of Ant, and many details need explaining. Your understanding of the buildfile's use of XML is essential. With this, you will be better equipped to examine the major parts of a buildfile. To that end, we'll begin our discussion in this chapter with a look at the reasons behind Ant's use of XML. Then we'll take the sample project and its corresponding layout and define our build requirements. These elements come together and create our example buildfile.
With the buildfile written, we can examine how Ant reads the buildfile and executes the steps defined within it. You can see how the flexibility of Ant results in a complex process. We explain the process so you can use this knowledge in not only writing buildfiles, but also when extending Ant — for example, with a user-written task. Last, we cover some of Ant's oddities, talk about what's missing, and discuss how to work around some of the resulting issues. So, let's get on with it!
Rather than being defined in terms of dependencies, a model other build tools use, Java projects are best described in terms of packages and components, thus closely following the package and object model of the Java language. No current build tool did this when Ant was first developed, and the idea comes from the need for something better for Java than the existing build tools of the time. Because Sun provides a Java library for its tools, which gives users programmatic access to the Java compiler, the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Why XML?
Rather than being defined in terms of dependencies, a model other build tools use, Java projects are best described in terms of packages and components, thus closely following the package and object model of the Java language. No current build tool did this when Ant was first developed, and the idea comes from the need for something better for Java than the existing build tools of the time. Because Sun provides a Java library for its tools, which gives users programmatic access to the Java compiler, the jar tool, and so on, the best language choice for a new Java project build engine is Java. With a plan and a language, the only thing left for Ant's designer, James Duncan Davidson, to do was to choose the buildfile descriptor syntax.
James had several requirements in mind for the buildfile syntax. First, the syntax should be simple so new users could easily pick it up. Next, it should have available (read: free) Java libraries so the new Java-based build engine would be easy to implement and maintain. Of utmost importance was the concept that writing a new engine shouldn't require writing a new syntax parser — an existing library was crucial. Another design goal was the ability to express a build structure that was a hierarchical tree. And the syntax should be capable of simultaneously describing builds in terms of components and packages and as operations. Let's look at why XML satisfies these requirements.
Developers understand XML since they use it in many areas of Java development, such as Enterprise Java Beans (EJB), Java Server Pages (JSP's), and with data transports such as Simple Object Access Protocol (SOAP). Outside of the Java world, XML finds equally great acceptance, giving Ant a wide potential user base. XML's parser and model libraries are freely available as Java libraries. Documentation is not a problem; there are hundreds of books, magazines, and web sites dedicated to XML technology. As a general-purpose description language, XML fits the complex use-case requirements set forth earlier. It can describe operations, data types, data values, and project layout. These attributes of XML map closely to Ant's design requirements. XML is the best choice for Ant.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Ant Building Blocks
With XML elements and tags, we can look at the primary components of an Ant buildfile as components or building blocks. We build the buildfile using these blocks. Some pieces have very specialized uses, while others are more common and used more frequently. Let's look at the primary components of the Ant buildfile.
We call the set of tags and elements in an XML file from the root element — in this case <project> — to the lowest-nested tag, the document object model (or DOM). The first or root element of any buildfile is always the <project> tag. No buildfile can be without one, nor can it have more than one. The DOM lays elements out in a tree-like hierarchy, making the buildfile more of an object model than simply a plain process-description document. The following example shows a valid project tag:
<project name="MyProject" default="all" basedir=".">
...
</project>
The <project> tag has three attributes: name, default, and basedir. The name attribute gives the project a name. A project name is valuable for purposes of identifying log output (to know what project you're building). For systems that manage buildfiles, such as an IDE that can read buildfiles, the project name acts like an identifier for the buildfile. The default attribute refers to a target name within the buildfile. If you run Ant without specifying a target on the command line, Ant executes the default target. If the default target doesn't exist, Ant returns an error. While we do not recommend it, the value of default does not have to be a valid target name (i.e., a name corresponding to an actual target name in the buildfile). We suggest either making the default target compile everything or display help for using the buildfile. The basedir attribute defines the root directory of a project. Typically, it is ".", the directory in which the buildfile resides, regardless of the directory you're in when you run Ant. However, basedir can also define different points of reference. For example, a buildfile that is part of a hierarchical project structure needs a different reference point, referring to the project's root directory. You can use the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
An Example Project and Buildfile
To provide an example buildfile for this book, we need an example project. We use a project that already exists as a GNU Make-based project called irssibot, an IRC bot written by Matti Dahlbom (the original can be found at http://dreamland.tky.hut.fi/IrssiBot). This project requires all the features of a typical build: compiling source code, packaging classes, cleaning directories, and deploying the application. As an exercise, we took this project and converted it to use Ant.
Let's begin by looking at how we configure the directories for the irssibot project. Java project organization methods vary — sometimes considerably so — depending on the project (e.g., web applications have very different project structures from GUI tools). Many times, the tools dictate a project's structure. Some IDE's, for example VisualAge versions prior to 3.5, require that all source code is in one file. EJB and CORBA compilers require naming conventions for source files and directories. For all cases, the project model should fit the requirements of your revision control system (you use a revision control system, right?). Because of such varied requirements and dependencies, a perfect project organizational pattern does not exist and we do not propose to suggest one here. The layout and organization we describe, however, is simple enough to work with many projects, and it works especially well with Ant.
Designing and implementing a project structure is not a trivial task, so do not assign and dedicate less than an hour of work to it and think you will do a good job. It's not just hard, it's tedious. Most Java programs have cross-platform capabilities, and you may be thinking of how to organize projects with this goal in mind. Traditionally, this thinking applies to working across operating systems and/or hardware configurations. However, in development teams, a different platform also means changes as small as toolset differences between heterogeneous workstations. Clean separation of functionality, the ability to be self-contained, and the lack of outside requirements should all be goals for Java projects. The benefits of working out such a structure for your project will not be immediately apparent, but as more developers use your build system, and as functionality is added to your project, you'll be glad you thought ahead. It is much easier to change the buildfile than it is to change an established project with 45 directories and 1,000 classes.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Buildfile Execution Process
We have the buildfile, but what happens when Ant runs? Understanding how Ant parses the buildfile and executes the targets is key to writing good, solid buildfiles.
Ant interprets the buildfile's XML, meaning that it processes the elements as it parses them. The XML library that Ant uses represents a hierarchal tree structure; Ant follows this tree's path during processing. At the project level, the level of XML just inside the <project> element, Ant does a breadth-first traversal of the XML elements. This means that it loads and processes all of the elements just below the level of the <project> element first, and then moves on to the first target. Inside a target, Ant does a depth-first traversal. This means that, starting with a target's first element, Ant processes each element as deep as it can before it moves on to the next element.
Understanding this design is most important when trying to understand how Ant processes its own errors (as opposed to errors from bad compilation or failed file copies). At the project level, Ant does a kind of syntax check before it actually processes any elements. In general, when speaking of Ant processing an element, we mean that Ant goes through the full processing life cycle on that element. Assuming a syntactically correct element declaration, the processing appears to be atomic from the outside; you cannot insert any operations between the time Ant parses the element and when Ant performs the operations that form the basis of the element's definition. Errors, however, occur within two distinct phases during the processing of an element, and understanding these phases alleviates some frustration.

Section 3.4.1.1: Project-level errors

At the project level, Ant loads all of the elements in the buildfile. It processes every element type except targets. This means any project-level tasks or DataTypes are processed. Processing a target means running the tasks and DataTypes within that target. You do not want Ant to execute all targets when it loads the buildfile. Instead, think of Ant as making a list of targets for future use. The list consists only of target names and attributes, and any invalid values in these particular items cause Ant to fail.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
AINASL: Ant Is Not a Scripting Language
After looking at the example project and buildfile, you may begin to look at Ant as a sort of scripting language for builds. With this bit of insight, you may charge forward writing buildfiles with this concept in mind...until the wheels fall off and you're stuck wondering why Ant can't do something you'd expect of any scripting language. Here's why they fell off: XML does not make for a good scripting language.
In a way, you're excused for seeing Ant as a sort of XML scripting language and accompanying parser. The difference is that, viewed as a scripting language, Ant is not very good. In fact, it's horrible. This little oddity of perception can cause a lot of confusion and frustration. Viewing the build as a design and not as a series of steps helps alleviate this confusion. We champion this authoring technique. So where does Ant's XML syntax fail as a scripting language?
A more concrete example of an oddity in Ant's syntax is its management of data. Here, the closest analogy to a language variable is the <property> tag. This, of course, completely ignores the rich data capabilities of XML, and Ant's developers know this. In addition to the property, there is the concept of an Ant data element — for example, the path DataType. The limitation is you cannot create DataTypes "in-language," as you can with a scripting language. Instead, you must write a class (or a set of classes) to represent a new data type in Ant; this is probably more effort than you are willing to put in for simply encapsulating groups of data values. If you're looking at Ant as an XML-based build scripting language and want to create your own data elements, you'll run into this dead-end fairly quickly.
So, how to avoid it? You can, of course, fix some of these shortcomings programmatically, but only if you're willing to make the effort of writing extensions and tasks for Ant. Alternatively, if you're not willing or not able to extend Ant programmatically, there's not much else you can do. Consider following the Ant mailing lists and reading the archives to find out more about the efforts Ant's developers are making to refactor this design limitation. The odds are good that refactoring will happen sooner rather than later. For instance, Ant developers introduced the concept of the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Buildfile Authoring Issues
The example buildfile we present in this chapter is simple compared to the capabilities Ant presents. Our goal is to show how to take a project, organize the files, and write a buildfile that makes life easier for the developers and project managers. The project and the steps we take are exaggerated and expanded to better demonstrate how we came to the decisions we make concerning the design of the project's organization and buildfile.
Beyond these first steps, your best path towards writing better buildfiles is experience. This includes both working with buildfiles and writing new ones. Most major open source Java applications now use Ant, giving you a virtual repository of best (and worst) practices. As an exercise, you may wish to take one of those buildfiles and, using this book as a reference, comment them, making note of what you think is happening and why.
The following issues have not yet been mentioned because they're more workarounds for Ant's shortcomings than buildfile design guidelines. Ideally, Ant's developers will refactor the design to eliminate the need for these workarounds.
Magic properties
Some properties are set but never explicitly used in any target or task. Ant's object model allows any build component to see all of a build's properties. The lack of an in-buildfile reference for these properties has led to their labeling as magic properties. A good example of a magic property is the build.compiler property for the javac task. No attribute exists for specifying the type of compiler the javac task uses. Instead, it relies upon the buildfile defining build.compiler. If a task uses a magic property, we specify this in the task definition provided in Appendix B.
When writing your own tasks, try to avoid using magic properties, as it makes the buildfile unreadable and hard to maintain.
When failure is success
Consider the following buildfile snippet:
<copy todir="newdir">
    <fileset dir="foo">
        <include name="**/*.xml"/>
    </fileset>
</copy>
This copy task element copies any XML files from foo to newdir
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Ant DataTypes
In the previous chapter's buildfile example, you saw the fileset DataType being used to identify groups of files to copy in order to deploy the irssibot application. DataTypes are important when using Ant, and fileset is just one of the many available to you:
argument
Passes command-line arguments to programs that you invoke from an Ant buildfile.
environment
Specifies environment variables to pass to an external command or program that you execute from an Ant buildfile.
filelist
Defines a named list of files that do not necessarily need to actually exist.
fileset
Defines a named list of files that must actually exist.
patternset
Groups a set of patterns together.
filterset
Groups a set of filters together.
path
Specifies paths (such as a classpath) in a way that is portable between operating systems.
mapper
Defines a complex relationship between a set of input files and a set of output files.
Let's dig in and learn more about these fundamental Ant DataTypes. They are building blocks used by tasks and are essential to using Ant effectively. In this chapter, we'll talk about each DataType in detail. Before doing that, however, we discuss briefly how DataTypes fit into Ant's overall design, and explain the notation used in this chapter to describe the attributes for the different DataTypes.
Ant DataTypes are found in the org.apache.tools.ant.types package, usually extending from the org.apache.tools.ant.types.DataType base class. EnumeratedAttribute, Commandline, Environment, and Reference are also treated as DataTypes, although they do not extend from DataType. Figure 4-1 contains a basic UML class diagram illustrating this aspect of Ant's design.
Figure 4-1: Ant DataTypes
The base class, org.apache.tools.ant.ProjectComponent, provides logging functionality as well as access to the Project object. Not shown here, ProjectComponent is also the base class for every Ant task. These tasks are detailed in Chapter 7 and Chapter 8.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
DataTypes Defined
Ant DataTypes are found in the org.apache.tools.ant.types package, usually extending from the org.apache.tools.ant.types.DataType base class. EnumeratedAttribute, Commandline, Environment, and Reference are also treated as DataTypes, although they do not extend from DataType. Figure 4-1 contains a basic UML class diagram illustrating this aspect of Ant's design.
Figure 4-1: Ant DataTypes
The base class, org.apache.tools.ant.ProjectComponent, provides logging functionality as well as access to the Project object. Not shown here, ProjectComponent is also the base class for every Ant task. These tasks are detailed in Chapter 7 and Chapter 8.
While the class diagram helps to explain what DataTypes are, understanding the internal structure of Ant is rarely necessary. In most cases you simply want to write buildfiles and use Ant. For this reason, the remainder of this chapter focuses on how these types are used, rather than how their internal implementation works.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
XML Attribute Conventions
DataTypes, like tasks, are defined using attributes. As we discuss each DataType in this chapter, we also list all the available attributes for it. These listings describe each attribute, specify which versions of Ant support it, and indicate whether it is required. The attribute listings take on the following form:
attribute_name (version, type, required_flag)
Is a description of an attribute and its function.
In which:
attribute_name
Is the name of the attribute. Use this to refer to the attribute when you specify it for a task.
version
Indicates the version of Ant supporting this attribute. "all" means Ant Versions 1.2 and later.
type
Indicates the type of data that an attribute can hold. For example, String indicates that an attribute holds textual data. See Table 4-1.
required_flag
Indicates whether a given attribute is required when using the task. If this flag is a asterisk (*), then see the notes immediately following the list.
Description of attribute
Is a description of the attribute and its function.
Table 4-1 summarizes the attribute types frequently referenced throughout this chapter. In all cases, text from XML attributes is converted into one of the basic types listed here. The "Description" column describes how each conversion happens. The "Implemented by" column lists the Java class that Ant uses to represent each of these attribute types.
Table 4-1: XML attribute type summary
Type name
Implemented by
Description
boolean
N/A
Performs a case-insensitive string comparison, converting on, true, and yes to true. All other values are false.
Enum
org.apache.tools.ant.types.EnumeratedAttribute
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Argument DataType
The apply, exec, and java tasks accept nested <arg> elements, specifying command-line arguments for their respective process calls. The org.apache.tools.ant.types.Commandline.Argument class implements this DataType. If several <arg> elements are specified, each is treated as a separate argument to the process call. Following is a list of all <arg> attributes:
file (all, File,*)
A filename as a single argument. In the buildfile, this filename is relative to the current working directory. The "current working directory" varies depending on the context this type is used in. The name is converted to an absolute path when passed as an argument.
line (all, String,*)
A space-delimited list of multiple arguments.
path (all, Path, *)
A path, as explained later in the section "Path DataType."
value (all, String, *)
A single command-line argument. Use this if your argument has spaces, but you still want to treat it as a single value.
Exactly one of these attributes is required.
Let's look at a complete buildfile to put things into perspective. In Example 4-1, we use the java task to invoke Apache's Xalan XSLT processor, transforming an XML file into HTML using XSLT. As you might expect, the java task invokes any Java class with a main( ) method. Use <arg> elements to pass arguments to the java task.
Example 4-1. <arg> usage
<?xml version="1.0"?>
<project name="arg demo" default="xslt" basedir=".">

  <property name="xalan.home" value="C:/java/xalan-j_2_1_0"/>
  <property name="xalan.jar" value="${xalan.home}/bin/xalan.jar"/>
  <property name="xerces.jar" value="${xalan.home}/bin/xerces.jar"/>

  <property name="xmldata" value="familyTree.xml"/>
  <property name="stylesheet" value="familyTree.xslt"/>
  <property name="result" value="Family Tree.html"/>

  <path id="project.class.path">
    <pathelement location="${xalan.jar}"/>
    <pathelement location="${xerces.jar}"/>
  </path>

  <target name="clean">
    <delete file="${result}"/>
  </target>

  <target name="xslt">
    <echo message="Transforming '${xmldata}' using '${stylesheet}'"/>

    <java fork="true" classname="org.apache.xalan.xslt.Process"
          failonerror="true">
      
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Environment DataType
The apply and exec tasks, which execute system commands, accept zero or more nested <env> elements. These elements specify which environment variables are passed to the system command being executed, and they are implemented by the org.apache.tools.ant.types.Environment.Variable class. The <env> element accepts the following attributes:
file (all, File,*)
A filename as the value of the environment variable. The name is converted to an absolute path.
key (all, String,Y)
The environment variable name.
path (all, Path, *)
A path as the value of the environment variable. Ant converts this to local conventions, as explained in "Path DataType." For instance, foo.txt is converted into C:\path\to\file\foo.txt on Windows platforms.
value (all, String, *)
A literal value for the environment variable.
Exactly one of file, path, or value is required.
The following example calls a batch file named deploy.bat. Within the batch file, the TOMCAT_HOME environment variable is available because of the <env> element:
<property name="tomcat.home" value="/path/to/tomcat"/>

<target name="deploy">
    <!-- Call a deployment script, setting up the TOMCAT_HOME -->
    <!-- environment variable.                                -->
    <exec executable="deploy.bat">
      <env key="TOMCAT_HOME" value="${tomcat.home}"/>
    </exec>
  </target>
The preceding example shows how you can pass environment variables to system commands using exec and env. Ant also allows you to use environment variables within your own buildfiles. This is an excellent way to avoid hardcoding, although it can limit portability. Because it deals with environment variables, using environment variables in buildfiles is closely related to the environment DataType. However, the environment DataType is not used to access environment variables from within Ant. Instead, this use of environment variables is implemented as a special feature of the property task, which is described in Chapter 7.
JDK 1.1.x applications can access environment variables using the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
FileList DataType
A filelist is a DataType supporting a named list of files, implemented by org.apache.tools.ant.types.FileList. The files do not have to exist in order to be included in a filelist. Following are the allowable attributes:
dir (1.4, File, *)
The directory used to compute absolute filenames.
files (1.4, String, *)
A comma-separated list of filenames.
refid (1.4, Reference, N)
A reference to a <filelist> defined elsewhere. The <filelist> being referred to defines a list of files. This is useful if you wish to define a list of files once, and then refer to it from several places in your buildfile.
Both dir and files are required, unless refid is specified, in which case neither dir nor files is allowed.
The filelist DataType was introduced in Ant 1.4, along with the dependset task. (Since filelist is only used with dependset, we must talk about the dependset task to explain the filelist DataType). The dependset task compares one or more input files to one or more output files. If any of the input files are newer, then all of the output files are erased. Additionally, if any of the input files are missing, all of the output files are erased. Comparing output files to a set of input files that may not yet exist is why the filelist DataType is necessary.
Let's illustrate why the combination of the filelist DataType and the dependset task is valuable. In this example, we are comparing a list of XML and XSLT files to a single HTML file. The HTML file, employeeDirectory.html, should be erased if any input file is missing or newer than it.
<?xml version="1.0"?>
<project name="filelist demo" default="xslt" basedir=".">

  <filelist id="stylesheets" dir="." files="header.xslt,footer.xslt,body.xslt"/>
               
  <filelist id="xmlfiles" dir="." files="employees.xml"/>

  <target name="xslt">
    <!-- erase employeeDirectory.html if any of the XML files or
         XSLT stylesheets are newer -->
    <dependset>
               
      <srcfilelist refid="stylesheets"/>
               
      <srcfilelist refid="xmlfiles"/>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
FileSet DataType
The fileset DataType defines a group of files and is commonly represented by the <fileset> element. However, many Ant tasks form implicit filesets, which means they support all fileset attributes and nested elements. Unlike the filelist type, files represented by fileset must exist. Filesets may also be specified as target-level buildfile elements (i.e., children of <project>) and referenced by their ids. Following is a list of fileset attributes:
dir (all, Path, Y)
The base directory for the fileset.
casesensitive (1.4.1, boolean N)
If set to false, the fileset is not case-sensitive when matching filenames. Defaults to true. Ant versions prior to 1.4.1 use case-sensitive matching.
defaultexcludes (all, boolean, N)
Determines whether to use default excludes. Defaults to true. Default excludes consists of: **/*~, **/#*#, **/.#*, **/%*%, **/CVS, **/CVS/**, **/.cvsignore, **/SCCS, **/SCCS/**, and **/vssver.scc.
excludes (all, String, N)
A comma-separated list of file patterns to exclude. These are in addition to the default excludes.
excludesfile (all, File, N)
The name of a file containing one exclude pattern per line. These are in addition to the default excludes.
includes (all, String, N)
A comma-separated list of file patterns to include.
includesfile (all, File, N)
The name of a file containing one include pattern per line.
In addition to the attributes listed, a fileset may also contain the following:
0..n nested patternset elements: <exclude>, <include>, <patternset> (all); <excludesfile>, <includesfile>. (1.4)
These define which files are included and/or excluded from the fileset. All are described shortly in Section 4.7. Other than <patternset>, these nested elements are used in place of their corresponding attributes.
The following examples produce identical results. Since fileset depends heavily on patternset, you should continue on and read the "Patternset DataType" section after studying these examples. The first example uses
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
PatternSet DataType
While filesets group files together, patternsets group patterns. These are closely related concepts, because filesets rely on patterns to select files. The <patternset> element may appear as a target-level buildfile element (i.e., as a child of <project>), and later be referenced by its id. As shown in the previous examples, it may also appear as a nested element of <fileset>. Tasks that are implicit filesets also