Section 9.4. A Sample Ant Buildfile


9.4. A Sample Ant Buildfile

Let's go over the basics of creating an Ant buildfile. We'll start with an introduction to XML, and then move on to the specific tags Ant supports and how you might use them to automate a build.

9.4.1. XML for the Uninitiated

The buildfiles of ant, usually named build.xml, are written in Extensible Markup Language, or XML. Some of the reasons for this are:

  • XML is hierarchical.

  • XML is standardized.

  • XML is widely used and familiar to many programmers.

  • Java has many classes for reading, parsing, and using XML.

  • XML-based representations of hierarchical data structures are easy to read and parse for both humans and programs.

XML is a successor to SGML, Standard Generalized Markup Language, which is a language for defining markup languages. A markup document may be validated. A validated document is one that conforms to a structural specification of the markup tags in the document. Such a specification may be made using a Document Type Definition (DTD), which is a holdover from the way SGML markup languages were specified, or using one of the newer specification standards, such as W3C's XML Schema. In either case, the DTD or schema specify what tags may be used in the markup, where they may exist with respect to one another, what attributes tags may have, and how many times a given tag may appear in a given place. A document can thus be validatedthat is, checked against the corresponding DTD or schema. It's not necessary, however; in many situations, documents can also be used without validation so long as they are well-formedthat is, conform to the basic syntax of XML.

HTML, with which even nonprogrammers are familiar, is an instance of a markup language defined in terms of SGML (and XHTML is its reformulation in terms of XML). This book itself was written in Docbook, which is another SGML markup language.

So, if SGML is such a wonder, why is XML all the rage? Well, SGML is one of those standards that attempt to "subsume the world." SGML has very complex and flexible syntax, with many different ways to represent a simple markup construct. Thus, to completely implement an SGML parser is difficult. Recognizing that 90% of the complexity of SGML is needed in only about 1% of cases, the designers of XML realized that they could make a markup specification language only 10% as complicated that would cover 99% of cases (of course, like 85% of statistics, we're making these numbers up, but you get the point).

Implementing an XML parser, while not exactly trivial, is much easier than implementing an SGML parser.

SGML/DSSSL and XML/XSLT are efforts to make the transformation and presentation of hierarchical data easier and more standardized. If what you have read here is all that you know about XML (or SGML), you should certainly consider getting yourself a book on these important standards.

For now, we can say that XML consists of tags which are set off from data content by the familiar less-than and greater-than brackets we are used to seeing in HTML:

 <samplexmltag> 

Just as in HTML, the tags may have start tag and end tag forms:

 <samplexmltag>Sample XML tagged data</samplexmltag> 

The entire construct, including the pair of matching tags and everything inside them, is called an element. The start tags may also, like in HTML, carry data inside them in the form of attributes:

 <samplexmltag color="blue">Sample XML tagged data</samplexmltag> 

If you have an empty element, one that that either does not or cannot have data between its start tag and end tag, you may "combine" the start and end tag by putting the slash at the end of the tag:

 <samplexmltag color="blue"/> 

Obviously, there is more to it than this, but it is enough to begin with.

XML's uses range from publishing to networked interprocess communications. Our interest here is in using it to represent a model of a piece of software and the various ways that software might be built and deployed. So from here on, we will be discussing not XML in general, but the ant document type. Actually, ant's markup language uses unvalidated XML. In other words, there isn't officially a schema for ant. Thus, the only formal definition for an ant XML file is what ant accepts and understands. This is more common than it should be. Any XML markup vocabulary really should have a schema, but often XML use starts with "Oh, this is just a quick thing. No one will ever read or write this markup. Just these two programs of mine." These famous last words will one day be right up there with "I only changed one line of code!" As strongly as we feel about this, ant really can never have a DTD, at least not a complete one. The custom task feature makes this impossible.

9.4.2. The Buildfile Tags

The buildfile (usually named build.xml) begins with a header announcing that this is an XML document and specifying what version of XML is being used in it:

 <?xml version="1.0"?> 

The <? and ?> delimiters mark up an XML statement (as opposed to an XML tag).[6] In this case, we are declaring that this is an XML document and that it is using XML version 1.0.

[6] Note that these are the terms we are using to describe XML to a new user. They are not the formal terms for these document elements. For the proper names, consult an XML reference.

9.4.2.1 The project Tag

Every buildfile must begin with a project tag. A buildfile must contain exactly one project tag.

The project tag contains three attributes:

name

The name of the project.

default

The default target (see next section).

basedir

The base directory of the project. Usually this is "." meaning the directory the buildfile is in.

The project name is just a name. It is not of particular importance to ant, although many IDEs that integrate ant will make use of the name attribute of the project.

The default attribute names a target tag that will be built by default if a build target is not passed to ant (see Section 9.4.2.2).

9.4.2.2 The target Tag

Every time you run ant, you are building a target. If you do not specify a target, ant will run the target named in the default attribute of the project tag.

A project may contain any number of targets. The target tag has five attributes:

depends

The name or names of other targets that must be built before this target may be built.

description

A descriptive name for the target. Displayed when ant -projecthelp is run.

if

Specifies a property name (see Section 4.4). The target is only built if the named property is set.

name

The name of the target. This is the name entered as an argument to ant. This is also the name that may be used in the default attribute of the project tag.

unless

This is the reverse of the if attribute. The target is built unless the property is set.

9.4.2.3 Properties

There is more than one way to set what we might call variables in ant. The only one we will concern ourselves with here is properties. Properties are like a simple hash, or associative array. They associate value, which is stored as a String, with a name, which is also a String. They behave very much like the Properties class introduced earlier in this book.[7] You can use buildfile properties to associate a single name with a single value that you use in multiple places throughout the buildfile to make configuration changes easier and less error-prone. Some tasks also expect certain properties to be set, as we shall soon see.

[7] In fact, an examination of the ant source code reveals that ant properties are stored in a HashTable.

You set a property with the property tag (Example 9.2).

Example 9.2. A useless build.xml example to demonstrate properties
 <?xml version="1.0"?> <project name="pointless" default="useless" basedir=".">   <target name="useless">     <property name="example.utility" value="nil"/>       <echo>This example's usefulness:       ${example.utility}. OK?</echo>   </target> </project> 

Running ant with Example 9.2 gives this output:

 $ ant Buildfile: build.xml useless:      [echo] This example's usefulness: nil. OK? BUILD SUCCESSFUL Total time: 1 second 

9.4.2.4 Tasks

A task is something that must be done to build the target. There is no single "task" tag; instead, each kind of task has its own tag[8] so there are many tags referred to collectively as task tags.

[8] In fact, task tag names correspond to the names of the Java classes that implement them. This will matter to you only if you wish to write your own ant tasks. We will not take you that far in this book.

There are dozens of standard task tags, but only a few of them are "everyday." We'll introduce a few of them here, and then talk about the tags that don't fall into the project/target/task hierarchy.

Standard task attributes

All ant task tags have at least the three attributes:

id

A unique ID for the task (not required).

taskname

A name for the task, used in logging (not required).

description

A description of the task, used for comments.

The javac task

The javac task, not surprisingly, runs the Java compiler. Note that since the Java compiler is written in Java and so is ant, there is no VM launch overhead to running the compiler. This can make ant many times faster than make simply for normal compiles.

The javac tag is one of the most complex in ant.

The javactask tag has a very large number of attributes, and may contain quite a number of other tags within it. First off, it is sensitive to a property, build.compiler, which may be used to specify that a particular Java compiler version must be used. The use of this will come up later when we build part of our application using the GNU Compiler for Java, but for now, and in general, you will not set this property,[9] compiling with the default compiler for the JDK version you are using. This is ant's default behavior.

[9] The one place you are likely to need to set this is when you are using a recent JDK to compile applets that you wish to work in Netscape 4.0 and IE 4.0 and older browsers. But this book doesn't teach you Java applets. We swear.

srcdir

Location of the Java source files.

destdir

Location to store the class files.

includes

Comma- or space-separated list of files (optionally using wildcards) that must be included; all .java files are included when this attribute is not specified.

excludes

Comma- or space-separated list of files (optionally using wildcards) that must be excluded; no files (except default excludes) are excluded when omitted.

classpath

The classpath to use.

sourcepath

The sourcepath to use; defaults to the value of the srcdir attribute or to nested src elements. To suppress the sourcepath switch, use sourcepath="".

classpathref

The classpath to use, given as a reference to a path defined elsewhere.

extdirs

Location of installed extensions.

nowarn

Indicates whether the -nowarn switch should be passed to the compiler; defaults to off (i.e., warnings are shown).

debug

Indicates whether the source should be compiled with debug information; defaults to off. If set to off, -g:none will be passed on the command line to compilers that support it (for other compilers, no command-line argument will be used). If set to true, the value of the debuglevel attribute determines the command-line argument.

debuglevel

Keyword list to be appended to the -g command-line switch. This will be ignored by all implementations except modern and classic (version 1.2 and more recent). Legal values are none or a comma-separated list of the following keywords: lines, vars, and source. If debuglevel is not specified (by default) nothing will be appended to -g. If debug is not turned on, this attribute will be ignored.

optimize

Indicates whether compilation should include optimization; defaults to off.

deprecation

Indicates whether source should be compiled with deprecation information; defaults to off.

verbose

Asks the compiler for verbose output; defaults to no.

depend

Enables dependency tracking for compilers that support this (Jikes and classic).

The jar task

The jar task makes a JAR file.

The javadoc task

One of the greatest benefits of developing in Java is the nearly automatic generation of thorough and correct documentation. Javadoc is the tool that does the job, and the javadoc task is the way to automate document production in ant. This tag has a number of attributes that specify where the source to be documented is located, how the documentation is to be produced, and where the documentation is to be placed.

The copy and mkdir tasks

These tasks are used to copy files and make directories.

The rmic task

Remote Method Invocation is a distributed computing technology (Section 5.8). RMI requires the generation of server and stub classes that provide the networking support for an RMI-enabled class. This is normally done by the rmic compiler, and this is one of the common reasons the Java programmers turn to build automation tools. The rmic tag allows ant to build RMI classes.

9.4.2.5 Other Tags

So far we have ignored a major component of ant. In order to introduce it, we need to give you a (painfully) high-level view of how ant works "under the hood."

Task tags actually map directly to Java classes that implement the tasks. Each task class is an instance of the Task class (in other words, it is a Java class that either directly or indirectly extends the Task class). This is how you can write your own tasksdownload the ant source code and write your classes that extend the Task class.

Tasks are not, however, the only tags that map to Java classes. There is another category of tags that do so. They are called datatypes. These are classes that directly or indirectly extend the ant DataType class.

Generally speaking, a task may require zero to many datatypes to specify the data with which the task works. Some such tags include the manifest tag used in our sample build.xml file discussed later in this chapter.

We'll mention a couple of the most frequently used datatype tags here and leave looking up the details as an exercise for you.

The PatternSet, Include, and Exclude datatypes

As you may have noticed, the most common tags we have covered allow you to specify the files to be processed using the tag's attributes. Usually, you nominate a base directory and let the task tag process everything in that directory.

There are times, however, when you need finer grained control than that. For example, you might wish to exclude all Java classes whose names end in "Test" (Example 9.3).

Other datatypes

There are many other datatypes used for various purposes. One of them, FilterSet, is able to modify files before they are copied or moved. This can be useful, for example, to put build information into a source file for an About dialog.

Example 9.3. Using the PatternSet datatype
 <patternset >   <include name="**/*.java">   <exclude name="**/*Test.java"> <patternset> <target name="build">   <javac destdir="build">     <src path="src"/>     <patternset ref/>   </javac> </target> 

In general, datatypes give you more sophisticated control than do the attributes of a task. Take a look at the Ant User's Manual[10] for full details on ant.

[10] http://ant.apache.org/manual/

9.4.3. A Real, Live Buildfile

Let's take it to the next level and examine a real working buildfile.

9.4.3.1 Project Organization

All but the simplest of projects will require multiple classes. Some will require libraries, multiple programs, binary deployment, Web deployment, enterprise deployment, and so on. A project will be most successful if you plan out what goes where in advance. We're going to present a series of suggestions for how to organize the files involved in developing, building, and deploying a Java project with ant. By no means is this the only way it might be done, but it has worked well for us.

9.4.3.2 The build.xml File for Payback

Example 9.4 is the actual Ant buildfile for the Payback program in our source code examples. These examples are available on the book's Web site.[11]

[11] http://www.javalinuxbook.com/

Example 9.4. The build.xml file for the Payback application
 <?xml version="1.0"?> <!--   $Id: 070_antIntro.sgml,v 1.51 2004/04/13 05:10:45 mschwarz Exp $   Buildfile for the Payback program. Payback will calculate   the length of time and real amount of money it takes to make a   purchase using various savings or credit accounts. --> <project name="Payback" default="all" basedir="."> <!-- The "init" target sets up properties used throughout   the buildfile. --> <target name="init" description="Sets build properties">   <echo>Running INIT</echo>   <property name="src" value="${basedir}/src"/>   <property name="build" value="${basedir}/build"/>   <property name="doc" value="${basedir}/doc"/> </target> <!-- The "all" target does nothing but tie together the "jar" and   "doc" targets. --> <target name="all" depends="jar,doc"         description="Pseudo-target that builds JAR and Javadoc">   <echo>Building ALL</echo> </target> <!-- The "build" target compiles the code in the project. --> <target name="build" depends="init"         description="Compiles the classes">   <echo>Running BUILD</echo>   <mkdir dir="${build}"/>   <javac destdir="${build}" srcdir="${src}" debug="true"          deprecation="true"/> </target> <!-- The "doc" target generates Javadoc documentation of the   project. The "author", "version", and "use" attributes set to   true cause those Javadoc tags to be used in the final document.   The "private" attribute set to true causes private methods and   attributes to be included in the documentation. We tend to use   this for projects to provide complete reference documentation.   You would probably not want to do this for an app or lib   distributed as a JAR file only. --> <target name="doc" depends="init"         description="Generates Javadoc documentation">   <echo>Running DOC</echo>   <mkdir dir="${doc}/api"/>   <javadoc packagenames="net.multitool.Payback.*"            sourcepath="${src}" destdir="${doc}/api"            author="true"       version="true"            use="true"          private="true"/> </target> <!-- The "jar" target depends on the "build" target. It places   all of the class files in the project into a JAR file, and   builds a manifest using the "manifest" tag. --> <target name="jar" depends="build"         description="Builds an application JAR file">   <echo>Running JAR</echo>   <jar basedir="${build}" jarfile="${basedir}/Payback.jar">     <manifest>       <attribute name="Version" value="1.0"/>       <attribute name="Main-Class"                  value="net.multitool.Payback.Payback"/>     </manifest>   </jar> </target> <!-- The "run" target depends on the "jar" target. It executes   the class named as the "Main-Class" in the JAR's manifest. --> <target name="run" depends="jar" description="Runs the program">   <echo>Running RUN</echo>   <java jar="${basedir}/Payback.jar" fork="true">     <arg value="${basedir}/accounts.properties"/>   </java> </target> <!-- The "clean" target erases all files and directories that other   Ant targets might have generated. It returns a copy of the   project tree to a "pristine" (some might say "clean") state. --> <target name="clean" depends="init"         description="Erase all generated files and dirs">    <echo>Running CLEAN</echo>    <delete dir="${build}" verbose="true"/>    <delete dir="${doc}/api" verbose="true"/>    <delete file="Payback.jar" verbose="true"/> </target> </project> 



    Java Application Development with Linux
    Java Application Development on Linux
    ISBN: 013143697X
    EAN: 2147483647
    Year: 2004
    Pages: 292

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net