Most programmers, and I was one of them, are skeptical when they are first introduced to Ant. They think, "Why do I need a build tool? My IDE handles all my build dependencies for me." In fact, one of the first things that attracted me to Java and IDEs was that I no longer had to deal with creating makefiles and figuring out whether or not I had put those pesky tabs in the right places.
However, relying on your IDE to handle builds isn't always a good idea. For one thing, although IDEs automate simple builds and some even do a pretty good job of bundling up J2EE applications, they are often very limited for anything more complicated. For example, if you wanted to pull all your source code from the version control system, build a jar file, sign it, deploy it to a server, and generate your Java doc, you would probably have to go through several rather tedious steps. Another problem is that developers sometimes forget to check into version control the files that the IDE uses to deploy a system. Also, with some IDEs, the files are in a proprietary or binary format, which prevents them from being manually edited or examined, making it difficult to track down errors, especially if multiple developers can make changes to your build configuration. Furthermore, most IDEs don't allow you to reuse or switch between configurations easily, which can be a problem if you have many similar build configurations, as you would if you needed to be able to deploy against several different databases or application servers. Another problem that I ran into recently was that, when my IDE was upgraded from one version to the next, the deployment method had changed so much that I had to throw out my entire deployment configuration and start over.
So Ant takes a very simple approach that solves most, if not all, of these problems. As I mentioned, Ant is written in Java. Thus, it is inherently cross-platform. In addition, it is an open-source project, so in the unlikely event that you need to fix a bug or extend the functionality, you can. Also, most IDEs now have at least a basic level of integration with Ant. This is especially rewarding if you work on multiple IDEs. The syntax for Ant build scripts is in XML, which solves all the problems related to proprietary or non-human-readable formats and provides a nice file or set of files to check into version control.
Projects, Targets, and Task
Ant build files have three key components:
- Projects
- Targets
- Tasks
A project is the ultimate goal of a single Ant build file; therefore, each Ant build file contains exactly one project. Each Ant project consists of multiple targets. A target is a logical step in the build process, like creating a jar file or generating a Java doc. Targets can have dependencies on other targets. The target to create a jar file would probably depend on a target that compiles source code into class files. All the targets on which a target depends are executed before the current target is executed. Targets consist of zero or more tasks. Tasks are the smallest unit of work in an Ant file. For example, the target to clean the build system might consist of multiple tasks that delete all the generated files and directories.
Installation and Configuration
Ant runs on many platforms, including most flavors of Unix, Linux, and Windows as well as Mac OS X and Novell Netware 6. Besides the installer, all that is required is a Java Virtual Machine (JVM). Apache recommends JVM 1.2 or higher for the full compatibility. You can download the current binary version of Ant from here. Or since Ant is a typical Apache open-source project, you can also get all of the source code from here, in case you want to add your own extensions or bug fixes or just take a look under the hood. If you download the binary distribution, which is what I recommend for getting started, simply unzip it and set up your environment variables as described in the installation instructions for your particular platform. If you download the binary distribution, you will need to build the source code as well as set up your environment variables. The installation instructions are excellent and will guide you through the process.
Running Ant
To show you what Ant can do, I've provided a handful of examples.
Example 1
I'll start you out with the easiest example possible. You will create a one-class, Hello World-style application and make a build script to build it for you. Here is the source for the application:
public class HelloAnt
{
public static void main(String[] argv)
{
System.out.println("Hello Ant");
}
}
To build this mini application, use the following build.xml file:
To keep this example as small as possible, I have stripped out all but the essential commands. In this example, you are declaring that you have a project called the HelloAntProject. The project has only one target, "compile", which consists of one task that invokes the Java compiler to compile all the Java source files in the current directory and then output their .class files to this same directory. You direct Ant to do this simply by invoking it from the command prompt in the directory that contains your build.xml file. Doing so in this example yields the following output:
Compile:
BUILD SUCCESSFUL
Total time: 0 seconds
Here, Ant is echoing back the name of the build file used. Then, it lists the targets that were executed in the order in which they were executed. In this case, you just invoked the "compile" target, which is then followed by a success message and elapsed time. This seems pretty easy, but you also could have done it simply by typing javac HelloAnt.java at the command prompt.
Example 2
Now, take a look at a slightly more complicated example. For this example, suppose you have an application consisting of several Java source files all in a directory called src. You want the compiled class files to be stored in a directory called build. So the class structure would look like this:
|
+-- src - *.java files
|
+-- build - *.class files
The build.xml for this example looks like this:
This example shows how you can build more complicated projects by using dependencies. Here, you have three targets: "init", "compile", and "clean". From the command line, you can specify which target Ant should build as a command line argument. Note that, in this example, you have specified a default target of "compile" so that if no command line argument is included, Ant will still build the "compile" target. The "compile" target has a dependency on the "init" target, so the "init" target is built first. In this case, the "init" target just creates the directory for "compile" to store its class files. Once the dependency is satisfied, "compile" compiles all the Java source files in the src directory, generates the class files, and stores them in the build directory. It is important to note here that you declared the src and build properties for the whole project so that they are available within all of the project's targets. This example also includes a third target called "clean" that can only be called by adding it as a command line argument to Ant. The "clean" target simply removes the build directory that contains all the class files, thus forcing the "compile" target to recompile all the source files on its next invocation.
Example 3
In this example, you will add functionality to build all of your source files into a jar file for testing or distribution. To do this, you will add a lib directory to store your jar file. Your new directory structure will look like this:
|
+-- src - *.java files
|
+-- build - *.class files
|
+-- lib - *.jar file
Then, make a few minor changes to your build.xml file so that it looks like this:
Here, you have added a couple of new properties for the lib directory and the jarfile name to the project as well as an extra delete to the "clean" target to remove the jar files directory. Then, you have a new jar target that makes sure you do a "clean" and a "compile" before wrapping up all the classes into a jar file and storing the jar file in the newly created lib directory. Don't forget that the default target is still "compile", so to create the jar file, you will need to specify it by adding it as a command line parameter to the Ant command.
Example 4
A common task that comes up when building Java systems is the need for a person other than a developer to be able to build the system and prepare it for QA testing or final deployment. You can use Ant to automate the whole process. In this example, you will add targets to sign the jar that you have created as well as generate the javadoc for the system. In order to do this, your new directory structure will look like this:
|
+-- src - *.java files
|
+-- build - *.class files
|
+-- lib – unsigned *.jar file
|
+-- doc - *.html generated javadoc files
|
+-- dist – signed *.jar file
The new build.xml file for signing and generating javadoc looks like this:
location="${dist}/HelloAntProject.jar" />
alias="myAlias"
storepass="myPassword"
signedjar="${signedjarfile}"/>
Above, you have added properties and directories for both the dist directory, where you will store your signed jar file, and the doc dir, where you will store all of your generated HTML javadoc. To do this, you also created three new targets. The first is "sign", which signs the jarfile and moves it to the dis directory. The second is "doc", which generates all the javadoc. The third is "dist", which depends on both "sign" and "doc" but does no work of its own. As with your other changes, "compile" is still the default target, so to use "dist", you will need to pass it as a command line argument. Also note that, by putting "sign" and "doc" into their own separate targets, you can specify either of them by using a command line argument. This way, if you only want to generate the javadoc, you don't have to do the unrelated task of signing the jar file.
With this example, you are getting pretty close to something that you would use with a real application. However, a full production version of this build script should contain some explanatory comments.
Some Hints
Like most languages, Ant contains literals. Some guides recommend that, if you use a literal in Ant more than once, you should define it in an initialization target. I disagree, but only slightly. I believe you should treat most literals in Ant the same way you would treat a constant in a programming language. In other words, define them in one place. That way, whenever you want to define a new literal, you don't have to search all over the place to see if it has already been defined.
The best place to define literals is, as I have done in my examples, as properties of the project itself. Also, Ant files can be used to call other Ant files, so a good general structure is to break down your total build so that you have one Ant project for each jar file that you generate and one master Ant file that pulls everything together. Ant is a powerful tool, like a chainsaw, so you have to wear safety goggles. You can create an Ant script so that your QA team can do a one-command build that pulls all of the source from version control and then builds, jars, and tests the system automatically. But be sure that you use a separate Ant file from the one that your developers use to build--otherwise, sooner or later, they will wind up pulling all the source code from version control right on top of what they have been working on.
Other Cool Ant Features
Ant can be easily extended. Each Ant target is object-based; in other words, there is an instance of a Java class that handles each target. So you can create your own targets fairly easily. Probably one of the most powerful features of Ant is that it can be used along with JUnit to fully automate your unit testing. Ant also provides a filtering mechanism that you can use to do string replacement in your source files. This can be very useful at build time for configuring which database server an application will connect to or the password for the server itself. Ant also has a built-in timestamp mechanism that can be handy when you need to create uniquely named files.
Synopsis
Ant is a cross-platform build tool that is essential to Java development. It overcomes many of the problems associated with using the automated build systems within IDEs by being simple, XML-based, and open-source. The three key concepts to an Ant build file are projects, targets, and tasks. Complicated application builds can be accomplished through a divide-and-conquer technique whereby each jar file in an application has its own build file, and then a master Ant build file ties them all together. Because Ant is powerful, it can also be dangerous. Take care when implementing targets that are destructive. Ant also has a lot of other cool features such as integration with JUnit for automated unit testing as well as filtering and timestamps.
Want More Information?
For more information about Ant, I recommend Java Tools for Extreme Programming: Mastering Open Source Tools Including Ant, JUnit, and Cactus, by Richard Hightower and Nicholas Lesiecki, or Java Development with Ant, by Eric Hatcher and Steve Loughran
Final Thought
So I've left you with one nagging detail about Ant. Where did the name come from? Well, according to Ant's original author, James Duncan Davidson, Ant is an acronym for Another Neat Tool, and I'm sure you will agree that it is.
Michael J. Floyd is an Extreme Programmer and the Software Engineering Technical Lead for DivXNetworks. He is also a consultant for San Diego State University and can be reached at
LATEST COMMENTS
MC Press Online