This article will describe some of the development tools that are available from the Java Open Source community and explore how they can help you create high-quality software in a predictable and reproducible fashion, saving you precious time and money. It is taken from chapter three of the book Enterprise Java Development on a Budget, written by Brian Sam-Bodden and Christopher M. Judd (Apress, 2004; ISBN: 1590591259).
Development and Build System with ANT - More on Targets (Page 5 of 11 )
Targets are meant to represent a discrete step in the build process. Targets use tasks, datatypes, and property declarations to accomplish their work. Targets are required to have a name attribute and an optional comma-separated list of dependent targets.
Use action verbs to name your targets, such as “build,” “test,” or “deploy.”
A typical buildfile is composed of several main targets: those that are meant to be called directly by the user and subtargets, which are targets that provide functionality to a main target.
Add a description attribute to a build’s main targets. Targets containing a description are shown in the automatic project help, which is displayed when Ant is invoked with the -projecthelp command-line option. For subtargets, prefix the name with a hyphen to make it easy to differentiate them from main targets.
Targets can be conditionally executed, for this purpose Ant supports the if and unless attributes. Targets using either or both of these are said to be conditional targets. Both if and unless take the name of a property as value, which is tested for existence. You can see an example of this if you modify Target A from the sample buildfile and add an if attribute with a value of do_a as shown here:
The target should only be executed if the Ant property by the name do_a exists in the context of the build. Executing the buildfile produces the following result:
Buildfile: build.xml Target A: Target B: [echo] Performing Step B [echo] Echo is one of many Core Tasks Target C: [echo] Performing Step C BUILD SUCCESSFUL Total time: 1 second
Notice that the output shows the banner for Target A but the echo tasks contained within were never executed. You can run the buildfile again using the -D option to pass the property do_a to the build as shown:
The output now shows that Target A is being executed. You add the double quotes around the name-value pairs for the command-line argument parser so you can recognize the end of the argument. Any value could have been passed and the results would have been the same. Remember with if and unless, the value of the property is irrelevant; what matters is whether the property has been defined or not.
From the simple buildfile shown previously you can see that targets can depend on other targets. This example shows a very simple and linear dependency chain in which Target C depends on Target B, which in turn depends on Target A.
Ant will resolve any circular dependencies and will consequently fail the build. For example, you can modify the sample script to add Target C as a dependency of Target A as shown in the following buildfile target:
The resulting execution of the script will produce output similar to the following:
Buildfile: build.xml BUILD FAILED Circular dependency: Target C <- Target A <- Target B <- Target C Total time: 1 second
Dependencies are resolved recursively using a topological sorting algorithm. The resulting build sequence ensures that a target in the dependency chain will only get executed once. You can see a great example of this in the Ant online manual, which shows a build with dependencies as shown in Figure 3-2.
Figure 3-2.Script dependencies
A buildfile for the build in Figure 3-2 would look like the following:
Understanding how dependencies work is very important as your build process grows in complexity. Figure 3-3 shows a depiction of the dependency resolution process.
Figure 3-3.Dependency resolution in Ant
To test the dependencies example, save the buildfile as dependencies.xml and run it using Ant’s -f parameter in order to indicate the buildfile as follows:
ant -f dependencies.xml -v
The output should look like this:
... Buildfile: dependencies.xml ... Build sequence for target `D' is [A, B, C, D] Complete build sequence is [A, B, C, D] A: B: C: D: BUILD SUCCESSFUL Total time: 1 second
Whenever possible keep a build’s dependencies as simple and linear as possible.
Tasks are used within a target to achieve certain functionality. Think of a task element as a way to invoke a Java class’s functionality. Ant provides a plethora of tasks that are divided in the following two categories:
Core: Core tasks include basic foundational facilities needed in the build process like file manipulation, file dependencies, directory operations, source-code compilation, API document generation, archiving and packaging, XML file manipulation, SQL execution, and others.
Optional: This includes tasks for some commercial products (like EJB/J2EE servers and third-party Version Control Systems) as well as nonbuild-specific tasks like unit testing, XML validation, and others.