HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML

The Basics
Ant is very similar to the standard Unix tool "make" that just about every experienced C programmer is familiar with. It does its work based on a build file, typically called build.xml, that tells Ant how and what to build. The contents of the build file are marked up in XML, making it rather self-explanatory. Different actions are triggered by aptly named XML tags with attributes and subtags detailing the work to be done.

Listing 1 contains an extremely simple build file. First I'll show how to tell Ant to use this file from the command line and what the output will be, then I'll dissect the file, explaining the different parts. To get us moving ­ a "task" is a basic unit of work and a "target" is a grouping of tasks that does something useful. Your build file will consist of several targets, each containing one or more tasks. Targets, in turn, are contained in a single "project." I'll explain these concepts shortly, but now let's run this thing and see what happens! (The source code for this article can be downloaded from below.)

Running Ant
Running Ant is simply a matter of invoking the shell script or batch file that came with the Ant distribution. When you execute this file with no command-line arguments, Ant generally looks in the current directory for a file called build.xml. If it finds this file, it will execute the default target specified in it. Figure 1 shows what happens when we execute Ant.bat with no command-line parameters.

Figure 1
Figure 1

Notice that Ant tells you which targets are being executed (the left-aligned text followed by a colon) and which task within a target it's working on (the word inside the brackets). This gives you a "progress meter" of the build. Also notice that even though we didn't tell Ant which target to run, it executed our JAR target, which is specified as the default target inside the build file.

You can also tell Ant which targets you want it to execute and the order. Most build files will contain a target called clean that removes any artifacts from previous builds and "resets" the project. It's not uncommon to run this clean task just before rebuilding the project. For our example this can be accomplished by specifying the command line:

ant clean jar

Figure 2 shows the output from executing this command line. Pay special attention to the order of the targets that are executed.

Figure 2
Figure 2

Ant also supports a command-line switch that tells it where to find a build file to use. This switch has the intuitive name of ­buildfile and takes a pathname to the file that will serve as the build file. Using this switch, you're no longer required to name your build file build.xml, and it obviously doesn't have to be in the current directory. As you'll see, this is where the basedir attribute of the <project> tag comes in handy. If you set it to "." or didn't specify it, all the relative path information will be handled properly, since the dot means "relative to the build file." This is generally what you want.

If your build file is living in a directory that has a name similar to "build" and the source and compile directories are siblings of the "build" directory, then you would need to set basedir equal to the parent directory or "..".

The Build File
The Ant build file is an XML document that tells Ant how to do the work to build a project. The first line in Listing 1 is the standard XML processing instruction that tells the XML parser which version of XML this document complies with (since there's currently only one version of XML, this line will always be set to version 1.0).

The <project> Tag
Line 3 is where the interesting content begins. The <project> tag is the only top-level tag that is allowed in a build file. In this example the <project> tag defines a logical name for this project (the name attribute) and specifies a default target (the default attribute) and a base directory for relative path specifications (the basedir attribute).

The name is not really used anywhere with an out-of-the-box Ant installation, but integrated development environments that understand and integrate with Ant will use the name to differentiate between different projects. Examples of Ant-aware IDEs include Eclipse, jEdit, and IntelliJ IDEA (URLs are provided at the end of the article).

The default attribute tells Ant which target to execute if you don't specify one on the command line. In general, the default target should be set to the one that's most useful or the one you execute the most; this will save some typing later on. In our case we want everything to execute, so we'll set the JAR target as the default.

The basedir attribute is used when building up relative pathnames. There are many properties set in a typical build file that specify directories or files. It's much easier and portable to specify these in a relative rather than absolute fashion. In other words, using the basedir attribute will allow you to pick up and move your entire build directory structure to a different disk or machine, without radically changing your build file. This is a big win, especially in a multideveloper scenario where different developers may not have the project directory in the same place on their machines.

Setting Properties
Just as with make, it's useful and indeed encouraged to set constants for often-used information to avoid retyping and copying. This is accomplished with the <property> tag that can appear either by itself directly inside the <project> tag or inside a <target> tag. The <property> tag has several options but we'll consider only one here: file. Supplying a file name (which will be found relative to the basedir attribute if no path is given) will create properties for each line in the file. The following is the properties file that we're using for this project.

  1. projectname=example1
  2. src.dir=src
  3. jar.name=${projectname}.jar
  4. build.dir=build
This is standard Java properties syntax. We are defining four properties, one of which is based on one other; the jar.name property on line 3 is based on the projectname property on line 1. The ${} syntax is Ant's way of dereferencing a property, substituting the property's value. You'll notice that on lines 9, 13, 14, 18, 19, 24, and 25 of the build file we use this same syntax ­ the same dereferencing syntax that works in the properties file works in the build file.

Note that we could have specified each of these properties directly in the build file, but it is much cleaner to move them out to a properties file. This makes the build file less cluttered and the properties a little easier to read.

Defining Targets
The <target> tag is the real workhorse of an Ant build file. Define a target for each major area of functionality that you need; this generally consists of some common setup, a compilation setup, a step to create a JAR file, and perhaps steps to create a WAR or EAR file.

In our example, we have five targets defined: init, prepare, compile, jar, and clean. The init target in our example merely loads up the properties file, as explained in the previous section. There's nothing stopping you from performing other tasks in this target; one common task that you will find in init is a call to <timestamp>, which sets properties containing the current time and date. You'll see an init target in most build files that you examine.

The prepare target is another common target that provides functionality that can be shared by multiple targets. Here the prepare target is simply creating a directory using the built-in task <mkdir> that we can compile our Java source code in. Notice that the directory we ask it to create is the result of using a property. The <prepare> target could do quite a bit more, such as create entire directory hierarchies, but for our purposes, simply creating this one directory is sufficient.

Notice that at the end of line 8 there's an attribute that says depends="init". This attribute sets up a dependency between the current target and the target(s) specified. When Ant gets ready to run our prepare target, it will see that we have a dependency and will then go off to run the depended-upon target(s) and then come back and run ours. This is a powerful mechanism for avoiding redundancy. As build files get larger, you'll end up with many targets that need some common functionality; moving this commonality into a single target and then setting up a dependency allows this to happen. Here we specify that prepare depends on init, which makes sense because prepare uses a property that's set inside init. If init were not called, we'd end up with a directory called ${build.name} being created. (Yes, we could have put the <mkdir> task directly into the compile target or inside init, but then you wouldn't have seen the dependency mechanism in action.)

Next, our compile target does what you might expect: it compiles our code! As you can see from Listing 1, there's a built-in task called <javac>, a wrapper for the standard javac compiler. It has many attributes, most of which are optional. Here we tell it where to find the source code to compile, srcdir="${src.dir}", and where to put the compiled class files, destdir="${build.dir}". Using the task this way will compile all Java source files that it finds in the ${src.dir} directory (and all of its subdirectories) and put the binary class files in the directory specified by the ${build.dir} attribute. If the source files declared a package, then the package structure will be represented in the destination directory.

Notice that the compile target depends on prepare. Since we need the build directory to be created before we try to write class files to it, we need to call prepare. But we also need the properties that get created inside init. Because compile depends on prepare and prepare depends on init, everything will be executed in the proper order and compile will work just fine.

Moving on, our jar target will take the output of our compile step and build a Java archive out of it. This example is almost overkill because of the simplicity of the project, but I wanted to show you a few of the interesting built-in tasks that Ant provides. You can see here that the jar task will build the archive specified by destfile and will include in it any class files (and directory structure) that are returned by the enclosed <fileset>. In this case, it will return only a single class file, but if there were others located anywhere under ${build.dir}, it would also return those. And notice again that it has dependencies. It wouldn't be terribly useful to create a JAR file without first compiling our source files. Thus setting depends="compile" will cause everything to be compiled (and prepared and inited) before trying to create a JAR. Usually if a target fails, the build aborts. There are a few exceptions, but generally this is the rule.

Finally we have a target called clean. This target can be executed to remove all artifacts of previous builds to ensure a clean build. Here we're deleting the compilation directory and the JAR file created from a previous run. Both these deletes will fail silently if the specified file/directory doesn't exist, which is fine. You'll almost certainly want a clean target in most of your build files, but care must be exercised when using the delete task, the same care you exercise any time you're deleting files and directories. It's quite painful if you delete the current directory and its contents instead of a subdirectory. Notice that our clean target depends on init. The reason for this is that if init is not run, then the two properties that are used by the <delete>s would never be defined and nothing would get deleted.

That's About It
That wraps up our discussion of the simple build file (the Hello, World of the Ant world, if you will). You should now have an understanding of what a build file looks like, how the different pieces relate to each other, how to declare that a task is dependent on another, and what a couple of the built-in tasks are.

When Things Go Awry...
Inevitably you're going to write a build file that you think is perfect, but when you try to run it your screen will fill up with stack traces and other error messages. One of the most common errors in a build file is not properly formatting the XML code. Remember that XML, unlike HTML, requires all attributes to be quoted and all tags must be closed! The build file in Listing 2 will not parse correctly because there are missing quotes all over the place and at least one target isn't closed. Even leaving off one quote will cause your file not to parse properly. An editor that does color syntax highlighting or checks for well-formed XML will help you spot these errors.

Figure 3 shows the output from running Ant with the bad.xml file in Listing 2 .

Figure 3
Figure 3

The parser encounters the first error and indicates it as being on line 5 (the number after the colon next to the file name). Actually it's on line 4, which is where we forgot to add the closing quote to the name attribute of the init target. Since Ant couldn't complete parsing the file, it will abort the run after the first error. Once you add the missing quote and run again, you'll see the next error, an unclosed <property> tag.

Remember that the error messages may not always explicitly help you and, in fact, may be caused by something other than your build file, such as a failed execution of an external program. Get comfortable with Ant's error messages; this is certainly not the last time you'll see one.

Summary
In this article I provided a quick introduction to an extremely useful tool. You should be able to take what you've learned here and immediately start applying it to your current business problem. There are a number of books on Ant available (one of which I coauthored) that would be helpful. Don't forget that the entire Ant manual is included with the Ant distribution and is located in ANT_HOME/docs/manual. It's also available on the Ant home page.

Links

  • Jakarta Web site: http://jakarta.apache.org
  • Ant pages: http://jakarta.apache.org/ant
  • Ant Manual: http://jakarta.apache.org/ant/manual
  • Eclipse: www.eclipse.org
  • jEdit: www.jedit.org
  • IntelliJ IDEA: www.intellij.com/idea
  • BravePoint: www.bravepoint.com

    Author Bio
    Joey Gibson is a senior consultant and instructor for BravePoint, a consulting company in Atlanta, GA. He is the coauthor of Ant Developers Handbook published by SAMS. [email protected]

    	
    
    
    
    Listing 1: build.xml
    
    1  <?xml version="1.0"?>
    2 
    3  <project name="Example1" default="jar" basedir=".">
    4    <target name="init">
    5      <property file="build.properties"/>
    6    </target>
    7         
    8    <target name="prepare" depends="init">
    9      <mkdir dir="${build.dir}"/>
    10   </target>
    11
    12   <target name="compile" depends="prepare">
    13      <javac srcdir="${src.dir}"
    14             destdir="${build.dir}"/>
    15   </target>
    
    
    17   <target name="jar" depends="compile">
    18     <jar destfile="${jar.name}">
    19       <fileset dir="${build.dir}"
                      includes="**/*.class"/>
    20     </jar>
    21   </target>
    22
    23   <target name="clean" depends="init">
    24     <delete dir="${build.dir}"/>
    25     <delete file="${jar.name}"/>
    26   </target>
    27 </project>
    
    Listing 2: bad.xml, A Build File with Problems
     
    1  <?xml version="1.0"?>
    2
    3  <project name="Example1" default="jar" basedir="." >
    4    <target name="init>
    5      <property file="build.properties">
    6    </target>
    7
    8    <target name="prepare" depends="init">
    9      <mkdir dir="${build.dir}"/>
    10   </target>
    11
    12   <target name="compile" depends=prepare>
    13     <javac srcdir="${src.dir}"
    14            destdir="${build.dir}>
    15 </project>
    
     
    

    Additional Code For This Article (~ 1.97 KB ~zip format )

    All Rights Reserved
    Copyright ©  2004 SYS-CON Media, Inc.
      E-mail: [email protected]

    Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.