Using Ant for build scripts

Ant is an excellent tool for creating build scripts.

Ant has these characteristics:

Every Java programmer should at least be familiar with Ant.

Using Ant, a build file is made up of tasks, which perform operations commonly needed for builds. The list of tasks is extensive:

Example Build File

Here's an example of an Ant build file:
<project name="test-ant-builds" default='all' basedir="." >
     Demonstrate the use of the Ant build tool with a simple Java project.

    First define properties, datatypes, and default tasks; then define targets.
    Any Ant tasks placed outside of any target are always executed first.
  <!-- Override default property values with an external properties file, if present. -->
  <property file=''/>

  <!-- Default property values, if not overridden elsewhere: -->
  <property name='build' location='build' />
  <property name='app.version' value='1.0'/>
  <property name='' value='Example App'/>
  <property name='distro-name' value='example-app-${app.version}'/>
  <tstamp><format property='build.time' pattern='yyyy-MM-dd HH:mm:ss'/></tstamp>

  <path id='compile.classpath'>
    <fileset dir='lib'>
       <include name='*.jar'/>

  <!-- Simply extends the compile.classpath with your own compiled classes. -->
  <path id='run.classpath'>
    <path refid='compile.classpath'/>
    <path location='src'/>
  <fileset id='class.files' dir='src'>
     <include name='**/*.class'/>

  <fileset id='files.for.jar' dir='src'>
    <exclude name='**/*.java'/>
    <exclude name='**/doc-files/'/>
  <fileset id='test.classes' dir='src'>
    <include name='**/TEST*.java'/>

  <!-- Text files using Ant's '@' syntax are here called template files. -->
  <fileset id='template.files' dir='.'>
    <include name='**/*_template.*'/>

  <!-- Inspect the environment, to see if a deployment host is currently running. -->
  <condition property='deployment.server.running' value='true' else='false'> 
     <socket port='8081' server='' />
  <!-- A connection to this URL is used when building javadoc. -->
  <condition property='jdk.javadoc.visible' value='true' else='false'> 
    <http url='' />
    Application: ${} ${app.version}
    Build File : ${ant.file} 
    Run Date   : ${build.time}
    Run by     : ${}
    Build Dir  : ${build}
    Base Dir   : ${basedir}
    Java Home  : ${java.home}
    Deployment host running: ${deployment.server.running}
    Connected to the web   : ${jdk.javadoc.visible}
  <echo message='Create build directory, and its subdirectories.'/>
  <mkdir dir="${build}/javadoc"/>
  <mkdir dir="${build}/dist"/>
  <mkdir dir="${build}/templates"/>

  <!-- Now define the targets, which use the properties and datatypes defined above. -->

   <target name='clean' description="Delete all build artifacts." >
     <delete dir='${build}'/>
      <fileset refid='class.files'/>
     <mkdir dir="${build}/javadoc"/>
     <mkdir dir="${build}/dist"/>
     <mkdir dir="${build}/templates"/>
   <target name='compile' description='Compile source files and place beside source.'>
     <javac srcdir="src">   
       <classpath refid='compile.classpath'/>
     <!-- Here's a simple way of debugging a path, fileset, or patternset, using its refid: -->
     <echo>Classpath: ${toString:compile.classpath}</echo>
   <target name='test' description='Run all JUnit tests.' depends='compile'>
     <junit haltonfailure='false'> 
         <pathelement location="src"/>
         <fileset refid='test.classes'/>
       <formatter type='brief' usefile='no'/>

   <target name='launch' description='Build and run the program.' depends='compile, test'>
     <java classname='hirondelle.ante.Launcher' classpathref='run.classpath' failonerror='true'>
       <arg value="Solar System"/>
   <target name='jar' description='Create a jar file for distribution.' depends='compile'>
    <jar destfile='${build}/dist/${distro-name}.jar' manifest='MANIFEST.MF' duplicate='preserve'>
      <fileset refid='files.for.jar'/>
      <!-- The static file is merged with additional dynamic items, specified here : -->
        <attribute name='Specification-Version' value='${app.version}'/> 
        <attribute name='Specification-Title' value='${}' />
        <attribute name='Implementation-Version' value='${app.version}'/> 
        <attribute name='Implementation-Title' value='${}' />
  <target name='javadoc' description='Generate javadoc.' >
      use='true' author='true'  version='true'
      windowtitle='${} ${app.version}'
      <classpath refid='compile.classpath'/>
      <link href=''/>      
      <header><![CDATA[<h1>${} ${app.version}</h1>]]></header>
  <target name='text-templates' description='Process template files, and assign values to @ variables.'>
    <copy overwrite='true' todir='${build}/templates'>
      <fileset refid='template.files'/>       
      <!-- New files have 'template' removed from their name : -->      
      <globmapper from='*_template.txt' to='*.txt'/>
        <filter token='' value='${}'/>
        <filter token='app.version' value='${app.version}'/>
        <filter token='build.time' value='${build.time}'/>
  <target name='distro-binary' description='Create zip file with executable jar, docs.' depends='jar, javadoc, text-templates'>
    <zip destfile='${build}/dist/${distro-name}' duplicate='preserve'>
      <zipfileset dir='${build}/dist/' includes='${distro-name}.jar'/>
      <zipfileset dir='${build}/javadoc' prefix='javadoc' />
      <zipfileset dir='${build}/templates' includes='README.txt'/>
  <target name='distro-source' description='Create zip file with project source code.'>
    <zip destfile='${build}/dist/${distro-name}' duplicate='preserve' >
      <!-- exclude items specific to the author's IDE setup: -->
      <zipfileset dir='.' excludes='.classpath, .project'/>
  <!-- Add mail.jar and activation.jar to your ANT_HOME/lib! -->
  <!-- Please edit, using values appropriate to your environment. -->
  <target name='email' >
    <mail mailhost='' mailport='25' user=''  
       password='blah'  messageMimeType='text/html'
       tolist='' from=''  subject='Build completed.'
        <![CDATA[ Test email. <P><a href=''>link</a> ]]>
  <target name='all' description='Create all build artifacts.' 
             depends='clean, compile, test, jar, javadoc, distro-binary, distro-source'>
    <echo>Finished creating all build artifacts.</echo>
Example of running the above build script:
C:\\johanley\\Projects\\ant-test>ant -file build.xml all
Buildfile: build.xml
     [echo]     Application: Example Appl  1.1
     [echo]     Build File : C:\\johanley\\Projects\\ant-test\\build.xml
     [echo]     Run Date   : 2010-07-21 19:14:11
     [echo]     Run by     : John
     [echo]     Build Dir  : C:\\@build
     [echo]     Base Dir   : C:\\johanley\\Projects\\ant-test
     [echo]     Java Home  : C:\\jdk1.5.0\\jre
     [echo]     Deployment host running: true
     [echo]     Connected to the web   : true
     [echo] Create build directory, and its subdirectories.
    [mkdir] Created dir: C:\\@build\\javadoc
    [mkdir] Created dir: C:\\@build\\dist
    [mkdir] Created dir: C:\\@build\\templates

   [delete] Deleting directory C:\\@build
   [delete] Deleting 3 files from C:\\johanley\\Projects\\ant-test\\src
    [mkdir] Created dir: C:\\@build\\javadoc
    [mkdir] Created dir: C:\\@build\\dist
    [mkdir] Created dir: C:\\@build\\templates

    [javac] Compiling 5 source files
     [echo] Classpath: C:\\johanley\\Projects\\ant-test\\lib\\junit.jar

    [junit] Testsuite: hirondelle.ante.TESTLauncher
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec

      [jar] Building jar: C:\\@build\\dist\\example-app-1.1.jar

  [javadoc] Generating Javadoc
  [javadoc] Javadoc execution
  [javadoc] Loading source files for package hirondelle.ante...
  [javadoc] Loading source files for package hirondelle.ante.deluvian...
  [javadoc] Constructing Javadoc information...
  [javadoc] Standard Doclet version 1.5.0_07
  [javadoc] Building tree for all the packages and classes...
  [javadoc] Generating C:\\@build\\javadoc\\hirondelle/ante/\\package-summary.html...
  [javadoc] Copying file C:\\johanley\\Projects\\ant-test\\src\\hirondelle\\ante\\doc-files\\VersionHistory.html 
            to directory C:\\@build\\javadoc\\hirondelle\\ante\\doc-files...
  [javadoc] Building index for all the packages and classes...
  [javadoc] Building index for all classes...

     [copy] Copying 1 file to C:\\@build\\templates

      [zip] Building zip: C:\\@build\\dist\\

      [zip] Building zip: C:\\@build\\dist\\

     [echo] Finished creating all build artifacts.

Total time: 6 seconds

For those already familiar with Ant, here are some reminders regarding its use.






Patternsets use 4 special char's:

Other datatypes


Properties are immutable once set.

Sources of Properties

Built-in Properties

Properties Files

# example properties file
app.version = 1.0

# This style also works, and it's not sensitive to order 
# of appearance in this file
# Thus, the contents of this file is manipulated somewhat 
# after being loaded.
# This does NOT work when using 'ant -propertyfile' = My Wonderful App ${app.version}

# you need to escape backslashes
build.dir = C:\\\\@build

Reminders and Practices

See Also :
Use a testing framework (JUnit)