Ant brings pure Java portability, flexibility to key build tool options

Using a cumbersome build tool can be as frustrating as writing the code. The Jakarta project's Java-based Ant build tool offers an alternative to UNIX-oriented tools, such as Make.

In any substantial software engineering project, the build tool is one of the most important parts of the developer’s toolkit. Without a solid build tool, the process of compiling, packaging, and distributing can overshadow actual programming in both complexity and time requirements.

Build tool options for Java developers have been limited mostly to older UNIX-based tools, such as Make. Make and its open source derivatives can get the job done, but using them often relies on calling UNIX or Windows commands to do the heavy lifting. That means that even though the Java code is cross-platform and write-once-run-anywhere, the build system generally is tied to one platform.

Java developers looked at this problem and realized that by leveraging the Java platform, they could create a much more powerful build tool, one specifically designed for Java programmers and not bound to any specific platform. The result is Ant, a project managed by the Apache Foundation’s Jakarta project.

Ant configuration files are written as XML documents, so Java programmers should already be familiar with the file syntax, in contrast with the notoriously unfriendly Make syntax. More importantly, all the build system’s actions to build your project, known as tasks, are written in Java; the same build file will run anywhere a Java compiler is available. Everything is self-contained within Ant.

In this article, we’ll look at how to setup and install Ant, create a configuration file to build your project, and use available built-in system and conditional tasks.

Setting up and installing Ant
To get started, we’ll need to head over to the Ant homepage, which contains the most recent release, online manual, and FAQ. Before downloading and installing Ant, you’ll need the Java Development Kit installed (version 1.2 or higher), your JAVA_HOME environment variable set, and the javac compiler in your executable path.

You can download ANT precompiled from the Jakarta site. You'll also want to pick the optional Java Archive (JAR) file, which includes tasks that help integrate with other development tools. Ant is also open source software, so if you want to change any of the internals to help fit your build environment, you could. All you need is to download the source. However, keep in mind that Ant is extremely flexible, and as we'll see in the next article, adding functionality to Ant is easy and doesn't require changing the Ant source code.

Once you’ve downloaded the binary package, you simply need to uncompress the file where you wish to install Ant. For Windows systems, uncompress to c:\ant\; on UNIX systems, you may want to install into /usr/local/ant/ or /opt/ant/.

Next, you’ll need to set your environment variables, specifically ANT_HOME. On Windows, assuming we installed in c:\ant, the commands shown in Figure A will properly set your environment variables.

Figure A
Set Windows environment variables.

On UNIX, assuming we installed in /usr/local/ant, the commands shown in Figure B will properly set your environment variables.

Figure B
Set UNIX environment variables.

To install the optional tasks on either Windows or UNIX systems, you need to copy the optional jar file into the $ANT_HOME/lib/directory. The ant or ant.bat script will automatically append the jar files into the class path for you.

Now, let’s test to make sure Ant installed properly. On the command line, type ant. You should see a message, shown in Figure C, saying that Ant could not locate a Build.xml file. That’s expected, since we have to configure and create project files.

Figure C
Build file error message

Now that Ant is ready to read project files, let’s see what a project file looks like.

Creating projects
To make life easier for developers, Ant’s configuration files are written as XML documents. Developers don’t have to worry about problems with white space (like with Makefiles), and many developers are already adept at writing valid XML.

At launch, Ant will automatically try to load the project configuration file named Build.xml. If you want to name the project configuration something different, you can run ant with the –buildfile flag, like so:
ant -buildfile Project_configuration.xml

In the SimpleBuild.xml example configuration file, shown in Listing A, you’ll see a project tag with three attributes: name, default, and basedir. Each tag in Ant configuration files is documented in great detail within the Ant manual. You’ll want to use the Ant manual as a reference to see which are required tags, which are optional, and which have default values.

Within the project tag, you’ll see property and target tags. The property tags create variables that can be accessed by tasks and variable expansion. As we’ll see later, some variables, like the date and time, can be set from within tasks, so not all variables will be explicitly defined.

After the property tags, you’ll see the target tag. You can define multiple targets, each with a different name. You’ll notice that the name of the target tag is compile, which happens to correspond to the default value in the project tag. That means that when we execute Ant, it will automatically start the compile target.

Within the target are a number of tasks, which Ant executes sequentially. You’ll find that almost everything you want to do in the process of building, packaging, and distributing can be handled with the tasks that ship with Ant.

In our simple build, we use the tstamp task to set the current date and time into environment variables. Next, we’ll use the mkdir task to create a directory called ${build}. (Assuming it doesn’t already exist. This is the first example of shell expansion in our script. Ant will automatically expand “${build}” to the value set by the property build, in this case the string build.)

Last, we’ll use the javac task to compile the source code from the directory src and save the output into build.

When we run Ant, we’ll get output showing the status of each target executed, as shown in Figure D.

Figure D
Ant output

A more in-depth example
Now let’s look at a slightly more complex configuration that uses multiple targets to build.

In the example Medium.xml, shown in Listing B, the configuration is broken up into many more targets than in our SimpleBuild.xml example. Breaking the build process into different targets means that Ant can enter the build process at any point. In SimpleBuild.xml, we simply compiled the Java source code. However, in this example, we initialize the environment (init), compile the code (compile), package the code into a jar (package), and copy the result to our production location (dist). We also have a task to clean the environment by reverting to before any code was compiled.

By default, we’ll sequentially run init, compile, package, and then dist. You can see that each target has a defined dependency; Ant completes dependencies before targets that rely on them. The default target is dist, so running ant on the command line would do all of the tasks.

However, we can execute just a portion of the steps by specifying the desired target on the command line. For example, we can only package the code, not distribute it. Breaking up larger projects into multiple targets will help in the debugging and quality assurance process by allowing developers to quickly make builds of subsections, rather than wait for a complete build.

Built-in tasks
Now that you’ve seen how to create a project file, let’s look at some of the built-in tasks. You’ll want to look at the documentation for Ant to get specifics on the tasks, since there’s a lot more info than we can cover here.

File System Tasks
You’ll probably use Ant most frequently for system tasks: moving, modifying, copying, and deleting files. You’ll need to move files around when you do distribution and when you clean up temporary files. That’s why having a good understanding of the file system tools is essential.

Our example Fs.xml, shown in Listing C, echoes a message to the filesystem. The “@…@” designation is how Ant does text substitution. You must designate tokens to be replaced by putting the “@” symbols around the text to be replaced. After the message is copied onto the disk, we create two directories, copy the files around, do a token substitution of the file on disk when we copy it, and delete one of the copied files. Figure E shows the output of running Ant on the Fs.xml build file.

Figure E
Output of the filesystem example

Using conditionals
Building conditionals in Ant isn’t easy. Because of the way Ant builds tasks and targets, you’ll have to carefully construct your statements. Conditionals work by executing targets only if a property is set to true. You can use and, or, and not statements to construct your conditionals. When a conditional is found to be true, you can use the antcall task to execute another target. Let’s look at a simple example that determines if the optional sound task is available and if it is available on UNIX or Windows.

In the SoundConditional example, shown in Listing D, you’ll see that the condition task will call the two conditional statements, condWinSound and condUnixSound, but neither will execute unless the conditional properties are set. The conditional targets check to see if the package is available (it's part of the optional jar file) and on which platform it is available.

Wrapping it up
By now, you should be ready to start moving your own software projects into the Ant build tool. Ant is being used more and more by developers to support large Java projects—and for good reason. The tools are Java-oriented, cross-platform, and generally easier to use than UNIX-oriented tools. Hopefully, this article gave you a look into the power of Ant and can help increase productivity in your organization. In future installments, we’ll look at how you can extend Ant by creating your own tasks.

Editor's Picks