Task Dependencies: ant

Steven J Zeil

Last modified: Mar 19, 2014

Contents:
1. The ant Command
2. Build Files
2.1 Targets
2.2 Properties
2.3 File Sets and Lists
2.4 Path Sets
2.5 Filters
2.6 Tasks
3. Case Studies
3.1 Code Annotation
3.2 Projects with Multiple Sub-Projects
3.3 Extend or Exec?
4. Eclipse/Ant Integration

ant is a build manager based upon a task dependency graph expressed in an XML file


What’s Wrong with make?

ant is actually an acronym for Another Neat Tool.

But why do we need “another” tool for build management?


Other Criticisms

1. The ant Command


ant Options

Some useful options:

-k, -keep-going
“Keep going.” Don’t stop the build at the first failue, but continue building any required targets that do not depend on the one whose construction has failed.
-f filename
Use filename instead of the default build.xml. Also -file or -buildfile
-Dproperty=value
Sets a property (similar to make’s variables)

2. Build Files

The ant build file is an XML file.

<project name="382Website" default="deploy">
     <description>
        Extract Metadata Extractor - top level
    </description>
  ⋮
</project>

2.1 Targets

At its heart, a build file is a collection of targets.

ant targets correspond, roughly, to make’s “artificial targets”.


Example of Targets

simplebuild.xml.listing
<project name="JavaBuild" default="deploy"> ➊
  <description>
    Example of a simple project build
  </description>

  <target name="compile" description="Compile src/.../*.java into bin/"> ➋
    <mkdir dir="bin" />                    ➌
    <javac srcdir="src" destdir="bin"
       debug="true" includeantruntime="false"/>
    <echo>compiled </echo>
  </target>

  <target name="unittest" depends="compile" unless="test.skip"> ➍
    <mkdir dir="test-reports" />
    <junit printsummary="on" haltonfailure="true" 
       fork="true" forkmode="perTest">
      <formatter type="plain" />
      <batchtest todir="test-reports">
    <fileset dir="bin">
      <include name="**/Test*.class" />
      <exclude name="**/Test*$*.class" />
    </fileset>
      </batchtest>
    </junit>
  </target>

  <target name="deploy" depends="unittest" description="Create project's Jar file">
    <jar destfile="myProject.jar">
      <fileset dir="bin"/>
    </jar>
  </target>
</project>

The project has a name and default target
A basic target. It is named “compile” and has a description (which may be picked up by some IDEs)
This target has 3 tasks. It creates a directory, compiles Java source code, and prints a message when completed.

This target illustrates both a dependency and a condition.


Task versus File Dependencies

ant targets correspond, roughly, to make’s “artificial targets”.

So this build file

simplebuild.xml.listing
<project name="JavaBuild" default="deploy"> ➊
  <description>
    Example of a simple project build
  </description>

  <target name="compile" description="Compile src/.../*.java into bin/"> ➋
    <mkdir dir="bin" />                    ➌
    <javac srcdir="src" destdir="bin"
       debug="true" includeantruntime="false"/>
    <echo>compiled </echo>
  </target>

  <target name="unittest" depends="compile" unless="test.skip"> ➍
    <mkdir dir="test-reports" />
    <junit printsummary="on" haltonfailure="true" 
       fork="true" forkmode="perTest">
      <formatter type="plain" />
      <batchtest todir="test-reports">
    <fileset dir="bin">
      <include name="**/Test*.class" />
      <exclude name="**/Test*$*.class" />
    </fileset>
      </batchtest>
    </junit>
  </target>

  <target name="deploy" depends="unittest" description="Create project's Jar file">
    <jar destfile="myProject.jar">
      <fileset dir="bin"/>
    </jar>
  </target>
</project>

is roughly equivalent to this makefile

simplemake.listing
JAVAFILESsrc=$(shell find src/ -name '*.java')
JAVAFILES=$(JAVAFILESsrc:src/%=%)
CLASSFILES=$(JAVAFILES:%.java=%.class)
TESTFILES=$(shell find src/ -name 'Test*.java')
TESTS=$(TESTFILES:src/%.java=%)

deploy: unittest
    cd bin; jar cvf myProject.jar `find . -name '*.class'`

unittest: build
    cd bin; for test in $(TESTS); do \
       java $$test; \
    done
build:
    cd src; javac -d ../bin -g $(JAVAFILES)

though a “real” makefile author would probably write this:

simplemake2.listing
JAVAFILESsrc=$(shell find src/ -name '*.java')
JAVAFILES=$(JAVAFILESsrc:src/%=%)
CLASSFILES=$(JAVAFILES:%.java=%.class)
TESTFILES=$(shell find src/ -name 'Test*.java')
TESTS=$(TESTFILES:src/%.java=%)

deploy: myProject.jar
unittest: testReport.txt
build: $(CLASSFILES)

myProject.jar: testReport.txt $(CLASSFILES)
    cd bin; jar cvf myProject.jar `find . -name '*.class'`

testReport.txt: $(CLASSFILES)
    -rm testReport.txt
    cd bin; for test in $(TESTS); do \
       java $$test >> testReport.txt; \
    done


bin/%.class: src/%.java
    cd src; javac -d ../bin -g $*.java


Make Efficiency

If we do

make
make

The second command does not actually perform any steps.


Ant Efficiency

What happens if we do

ant
ant -Dskip.test=1

2.2 Properties

Properties are named string values.


The <property Task

Two basic modes:


Additional <property Variants

2.3 File Sets and Lists

File Sets

<fileset file="src/main.cpp"/>
<fileset dir="src" 
    includes="main.cpp utility.h utility.cpp"/>
<fileset dir="src" includes="*.cpp,*.h"/>

File Lists

<filelist dir="src" 
    files="main.cpp utilities.h utilities.cpp"/>

Mappers

would map a compiled unit test file project/package/TestADT.class to project.package.TestADT


Selectors

Selectors provide more options for selecting file than simple include/exclude based on the names.

<fileset id="unitTestSrc" dir="src">
   <include name="**/Test*.java"/>
   <contains text="@Test" casesensitive="no"/>
</fileset>

(Our previous examples assumed that unit tests woule be identified by file name. Here we look instead for the JUnit4 @Test annotation.)

2.4 Path Sets

Used to specify a sequence of paths, usually to be searched.

<classpath>
    <pathelement path="${env.CLASSPATH}"/>
    <fileset dir="target/classes">
       <include name="**/*.class"/>
    </fileset>
    <filelist refid="third-party_jars"/>
</classpath>

Referencing Path Sets

2.5 Filters

Filters are used to modify the outputs of some commands by performing various substitutions:

<copy file="../../templates/@{format}.tex" 
      tofile="${doc}-@{format}.ltx">
  <filterset>
    <filter token="doc" value="${doc}"/>
    <filter token="relPath" value="${relPath}"/>
    <filter token="format" value="@{format}"/>
  </filterset>
</copy>

A filter set replaces tokens like @doc@ by a string, in this case the value of the property ${doc}


Filter Chains

Filter chains offer a variety of more powerful options, e.g.,

<loadfile property="doctitle" srcfile="${doc}.info.tex">
  <filterchain>
    <linecontains>
      <contains value="\title{"/>
    </linecontains>
    <tokenfilter>
      <replaceregex pattern=" *\\title[{]([^}]*)[}]"
                    replace="\1"/>
    </tokenfilter>
  </filterchain>
</loadfile>

2.6 Tasks

The Ant Manual has a good breakdown on these.


Extending Ant

<project name="code2html" default="build">

  <taskdef classpath="JFlex.jar" 
           classname="JFlex.anttask.JFlexTask" 
           name="jflex" />
     ⋮

  <target name="generateSource">
    <mkdir dir="src/main/java"/>
    <jflex file="src/main/jflex/code2html.flex"
       destdir="src/main/java"/>
    <jflex file="src/main/jflex/code2tex.flex"
           destdir="src/main/java"/>
       ⋮

Finding Extensions

3. Case Studies

3.1 Code Annotation

The steps involved in building this tool are:

1.Run the program jflex on each file in src/main/jflex, generating a pair of .java files that get placed in src/main/java

  1. Compile the Java files in src/main/java, placing the results in target/classes

  2. Compile the Java files in src/test/java (using the target/classes compilation results, placing the results in target/test-classes.

  3. Run the JUnit tests in target/test-classes.

  4. If all tests pass, package the compiled classes in target/classes into a .jar file.


The Code Annotation Tool Build

codeAnnotation.build.listing
<project name="code2html" default="build">

  <record name="ant.log" action="start" append="false" />   ➊

  <taskdef classpath="JFlex.jar" classname="JFlex.anttask.JFlexTask" 
       name="jflex" />                                      ➋
    
  <echo>loading build-${os.name}.paths</echo>
  <include file="build-${os.name}.paths"/>                  ➌
    

  <target name="generateSource">                           ➍
    <mkdir dir="src/main/java"/>
    <jflex file="src/main/jflex/code2html.flex"
       destdir="src/main/java"/>
    <jflex file="src/main/jflex/code2tex.flex"
       destdir="src/main/java"/>
    <jflex file="src/main/jflex/list2html.flex"
       destdir="src/main/java"/>
     <jflex file="src/main/jflex/list2tex.flex"
       destdir="src/main/java"/>
  </target>
  

  <target name="compile" depends="generateSource">      ➎
    <mkdir dir="target/classes"/>
    <javac srcdir="src/main/java" destdir="target/classes"
       source="1.6" includeantruntime="false"/>
  </target>

  <target name="compile-tests" depends="compile">       ➏
    <mkdir dir="target/test-classes"/>
    <javac srcdir="src/test/java" destdir="target/test-classes"
       source="1.6" includeantruntime="false">
      <classpath refid="testCompilationPath"/>
    </javac>
  </target>

  <target name="test" depends="compile-tests">         ➐
    <mkdir dir="target/test-results/details"/>
    <junit printsummary="yes" 
       haltonfailure="yes"
       >
      <formatter type="xml"/>
      <batchtest todir="target/test-results/details">
         <fileset dir="target/test-classes">
            <include name="**/*Test*.class"/>
         </fileset>
      </batchtest>
      <classpath refid="testExecutionPath"/>
    </junit>
    <junitreport todir="target/test-results">
      <fileset dir="target/test-results/details">
        <include name="TEST-*.xml"/>
      </fileset>
    </junitreport>
  </target>

  <target name="build"  depends="test">               ➑
    <jar destfile="codeAnnotation.jar" basedir="target/classes">
        <manifest>
        <attribute name="Main-Class"
                   value="edu.odu.cs.code2html.Code2HTML"/>
            </manifest>
    </jar>
  </target>

  <target name="clean">                             ➒
    <delete dir="target"/>
  </target>
  
</project>

This is a fairly “stock” build for a Java project.

Nonetheless, there are multiple steps that would not be handled by typical IDE build managers.

build-Linux.paths.listing
<project>
    <path id="testCompilationPath">
      <pathelement location="/usr/share/java/junit4.jar"/>
      <pathelement location="/usr/share/java/hamcrest-library.jar"/>
      <pathelement path="target/classes"/>
    </path>

    <path id="testExecutionPath">
      <pathelement location="/usr/share/java/junit4.jar"/>
      <pathelement location="/usr/share/java/hamcrest-library.jar"/>
      <pathelement path="target/classes"/>
      <pathelement path="target/test-classes"/>
    </path>
</project>

build-Windows7.paths.listing
<project>
    <path id="testCompilationPath">
      <pathelement location="./junit4.jar"/>
      <pathelement location="hamcrest-library.jar"/>
      <pathelement path="target/classes"/>
    </path>

    <path id="testExecutionPath">
      <pathelement location="./junit4.jar"/>
      <pathelement location="hamcrest-library.jar"/>
      <pathelement path="target/classes"/>
      <pathelement path="target/test-classes"/>
    </path>
</project>

3.2 Projects with Multiple Sub-Projects


Managing Subprojects with ant

Typical key ideas:


A Top-Level Build

topProject-build.listing
<project name="course" default="build">

  <record name="ant.log" action="start" append="false" />

  <!-- Invoke this build file as
     ant
       - to build the desired documents
     ant clean
       - to clean out all generated files

  -->

  <property file="course.properties"/>

  <macrodef name="iterate">              ➊
    <attribute name="target"/>
    <sequential>
      <subant target="@{target}">
    <fileset dir=".">
      <include name="*/**/build.xml"/>
      <exclude name="templates/**"/>
    </fileset>
      </subant>
    </sequential>
  </macrodef>

  <dependset>                           ➋
    <srcfileset file="course.properties"/>
    <targetfileset file="course.info.tex"/>
  </dependset>    
  <available property="course.info.tex.exists" ➌
          file="course.info.tex"/>


  <target name="courseSetup" unless="course.info.tex.exists">    ➍
    <copy file="templates/course.info.tex" toFile="course.info.tex">
      <filterset>
    <filtersfile file="course.properties"/>
      </filterset>
    </copy>
    <replace file="course.info.tex" token="~" value="\%7E"/>
    <echo file="course.info.tex" append="true">
      % This file is generated automatically from course.properties
    </echo>
    <echo file="course.info.tex" append="true">
      % Do not edit. Any changes are likely to be overwritten.
    </echo>
  </target>

  <target name="emailSetup">
    <copy todir=".">
      <fileset dir='.' file="templates/sendEmail.html"/>
      <filterset>
    <filtersfile file="course.properties"/>
      </filterset>
    </copy>
  </target>

  <target name="setup" depends="courseSetup,emailSetup"     ➎
        description="Prepare all source files prior to running LaTeX"
        >
    <iterate target="setup"/>
  </target>

  <target name="build"  depends="courseSetup,emailSetup"
      description="Generate all documents">            ➏
    <iterate target="build"/>
  </target>

  <target name="zip" depends="build"                      ➐
      description="Generate all documents and prepare a zip file that can be uploaded to and unpacked on a webserver"
      >
    <tstamp>
      <format property="today" pattern="yyyy-MM-dd_hh-mm"/>
    </tstamp>
    <zip destfile="${courseName}_${today}.zip" level="9">
      <fileset dir=".">
    <exclude name="**/*~"/>
    <exclude name="**/*.aux"/>
    <exclude name="**/*.fdb_latexmk"/>
    <exclude name="**/*.fls"/>
    <exclude name="**/*.log"/>
    <exclude name="**/*.out"/>
    <exclude name="**/*.toc"/>
    <exclude name="**/*.nav"/>
    <exclude name="**/*.snm"/>
    <exclude name="**/*.vrb"/>
    <exclude name="**/*.tex"/>
    <exclude name="**/*.ltx"/>
      </fileset>
    </zip>
  </target>

  <target name="deploy" depends="build"           ➑
      description="Generate all documents and sync with the deployment directory (usually a website)"
      >
    <sync todir="${deploymentDestination}" 
      includeEmptyDirs="true" granularity="2000">
      <fileset dir=".">
    <exclude name="**/*~"/>
    <exclude name="**/*.aux"/>
    <exclude name="**/*.fdb_latexmk"/>
    <exclude name="**/*.fls"/>
    <exclude name="**/*.log"/>
    <exclude name="**/*.out"/>
    <exclude name="**/*.toc"/>
    <exclude name="**/*.nav"/>
    <exclude name="**/*.snm"/>
    <exclude name="**/*.vrb"/>
    <exclude name="**/*.tex"/>
    <exclude name="**/*.ltx"/>
      </fileset>
      <preserveintarget>
    <include name="**/.ht*"/>
      </preserveintarget>
    </sync>
  </target>


  <target name="clean">
    <iterate target="clean"/>
  </target>

  <target name="cleaner">
    <iterate target="cleaner"/>
  </target>

  <target name="cleanest">
    <iterate target="cleanest"/>
  </target>

  
</project>

3.3 Extend or Exec?

As we move further from common Java project structures, the problem arises of how to issue commands for which we have no readily available ant task.


Mitigating Factors

Although the community has contributed numerous extension tasks,

This can drive a project to use exec/apply even if tasks purportedly exist


Generating Course Website PDFs

Each document is a subproject with a build file like this:


<project name="docs" default="build">

  <import file="../../commonBuild.xml"/>

  <target name="makeSources" depends="properties">
    <docformat format="slides"/>
    <docformat format="web"/>
    <docformat format="printable"/>
    <docformat format="10-4x3"/>
    <docformat format="10-16x10"/>
    <docformat format="7-4x3"/>
    <docformat format="7-16x10"/>
  </target>


</project>


The “good stuff” is in the included commonBuild.xml

commonBuild.listing
  <project>

    <condition property="windowsos">
      <os family="windows" />
    </condition>

    <target name="logging" unless="windowsos">
      <record name="ant.log" action="start" append="false" />
    </target>

    <property environment="env"/>

    <basename property="doc" file="${basedir}"/>
    <property name="baseParent" location=".."/>
    <basename property="relPath" file="${baseParent}"/>

    <property file="../../course.properties"/>
    
    <macrodef name="docformat">
      <attribute name="format"/>
      <sequential>
    <copy file="../../templates/@{format}.tex" 
          tofile="${doc}-@{format}.ltx">
      <filterset>
        <filter token="doc" value="${doc}"/>
        <filter token="relPath" value="${relPath}"/>
        <filter token="format" value="@{format}"/>
      </filterset>
    </copy>
    <replaceregexp file="index.html" 
               match ="[.]vis@{format} [{]display:none" replace=".vis@{format} {table-row"/> 
    <copy file="${doc}-@{format}.ltx" tofile="${doc}-@{format}.main.tex"/>
      </sequential>
    </macrodef>

    <available property="dblatex-is-installed" 
           file="dblatex" filepath="${env.PATH}"/>

    <target name="checkDB" depends="logging" if="dblatex-is-installed">
      <dependset>
    <srcfileset file="${doc}.dbk"/>
    <targetfileset file="${doc}.content.tex"/>
      </dependset>
    </target>

    <target name="checkForContent" depends="checkDB">
      <available property="content.exists" file="${doc}.content.tex"/>
    </target>

    <target name="convertDB" depends="checkForContent" unless="content.exists">
      <apply executable="dblatex" parallel="false">
    <arg value="--style=simple"/>
    <arg value="--type=tex"/>
    <arg value="--xsl-user=../../templates/dblatex-sjz.xsl"/>
    <fileset file="${doc}.dbk"/>
      </apply>
      <replace file="${doc}.dbk.tex" token="language=cpp" value="language=C++"/>
      <replace file="${doc}.dbk.tex" token="\cyrchar\cyrie{}" value="$\epsilon$"/>
      <apply executable="csplit" parallel="false" addsourcefile="false">
    <arg value="${doc}.dbk.tex"/>
    <arg value="/title/"/>
    <arg value="/^%/"/>
    <arg value="/mainmatter/+1"/>
    <arg value="/end{document}/"/>
    <fileset file="${doc}.dbk.tex"/>
      </apply>
      <move file="xx01" tofile="${doc}.info.tex"/>
      <move file="xx03" tofile="${doc}.content.tex"/>
      <delete>
    <fileset dir="." includes="xx0*"/>
    <fileset file="${doc}.dbk.tex"/>
      </delete>
    </target>


    <target name="makeGraphics" depends="logging,epsGraphics,gifGraphics"/>

    <available property="epstopdf-is-installed" 
           file="epstopdf" filepath="${env.PATH}"/>

    <target name="epsGraphics" depends="logging,diaGraphics,figGraphics" 
        if="epstopdf-is-installed">
      <apply executable="epstopdf" parallel="false">
    <fileset dir="." includes="*.eps"/>
    <globmapper from="*.eps" to="*.pdf"/>
      </apply>
      <dependset>
    <srcfileset dir="." includes="*.eps"/>
    <targetfileset dir="." includes="${doc}-*.pdf"/>
      </dependset>
    </target>

    <available property="dia-is-installed" 
           file="dia" filepath="${env.PATH}"/>

    <target name="diaGraphics" depends="logging" if="dia-is-installed">
      <apply executable="dia" parallel="false">
    <arg value="-t"/>
    <arg value="eps-builtin"/>
    <fileset dir="." includes="*.dia"/>
    <globmapper from="*.dia" to="*.eps"/>
      </apply>
    </target>


    <available property="fig2dev-is-installed" 
           file="fig2dev" filepath="${env.PATH}"/>

    <target name="figGraphics" depends="logging" if="fig2dev-is-installed">
      <apply executable="fig2dev" parallel="false">
    <arg value="-L"/>
    <arg value="eps"/>
    <srcfile/>
    <targetfile/>
    <fileset dir="." includes="*.fig"/>
    <globmapper from="*.fig" to="*.eps"/>
      </apply>
    </target>

    <available property="convert-is-installed" 
           file="convert" filepath="${env.PATH}"/>

    <uptodate property="gifConversion.notRequired">
      <srcfiles dir= ".">
    <include name="*.gif"/>
      </srcfiles>
      <globmapper from="*.gif" to="*.png"/>
    </uptodate>

    <target name="gifGraphics" depends="logging" 
        if="convert-is-installed" unless="gifConversion.notRequired">
      <apply executable="convert" parallel="false" relative="true">
    <srcfile/>
    <targetfile/>
    <fileset dir="${basedir}" includes="*.gif"/>
    <globmapper from="*.gif" to="*.png"/>
      </apply>
    </target>

    <available property="ext-file-exists" 
           file="${doc}.ext.tex" filepath="."/>

    <uptodate property="makeSourceCodeHTML.notRequired">
      <srcfiles dir= ".">
    <include name="*.h"/>
    <include name="*.cpp"/>
    <include name="*.java"/>
    <include name="*.listing"/>
      </srcfiles>
      <globmapper from="*" to="*.html"/>
    </uptodate>
    <uptodate property="makeSourceCodeTex.notRequired">
      <srcfiles dir= ".">
    <include name="*.h"/>
    <include name="*.cpp"/>
    <include name="*.java"/>
    <include name="*.listing"/>
      </srcfiles>
      <globmapper from="*" to="*.tex"/>
    </uptodate>

    <target name="makeSourceCodeTex" depends="logging" 
        unless="makeSourceCodeTex.notRequired">
      <apply executable="java">
    <arg value="-cp"/>
    <arg value="../../templates/codeAnnotation/codeAnnotation.jar"/>
    <arg value="edu.odu.cs.codeAnnotation.Code2TeX"/>
    <fileset dir=".">
      <include name="**/*.h"/>
      <include name="**/*.cpp"/>
      <include name="**/*.java"/>
    </fileset>
    <globmapper from="*" to="*.tex"/>
      </apply>
      <apply executable="java">
    <arg value="-cp"/>
    <arg value="../../templates/codeAnnotation/codeAnnotation.jar"/>
    <arg value="edu.odu.cs.codeAnnotation.Listing2TeX"/>
    <fileset dir=".">
      <include name="**/*.listing"/>
    </fileset>
    <globmapper from="*" to="*.tex"/>
      </apply>
    </target>

    <target name="makeSourceCodeHTML" depends="logging" 
        unless="makeSourceCodeHTML.notRequired">
      <apply executable="java">
    <arg value="-cp"/>
    <arg value="../../templates/codeAnnotation/codeAnnotation.jar"/>
    <arg value="edu.odu.cs.codeAnnotation.Code2HTML"/>
    <arg value="-footer"/>
    <arg value="&lt;footer/&gt;"/>
    <fileset dir=".">
      <include name="**/*.h"/>
      <include name="**/*.cpp"/>
      <include name="**/*.java"/>
    </fileset>
    <globmapper from="*" to="*.html.xml"/>
      </apply>
      <apply executable="java">
    <arg value="-cp"/>
    <arg value="../../templates/codeAnnotation/codeAnnotation.jar"/>
    <arg value="edu.odu.cs.codeAnnotation.Listing2HTML"/>
    <fileset dir=".">
      <include name="**/*.listing"/>
    </fileset>
    <globmapper from="*" to="*.html.xml"/>
      </apply>
    </target>

    <target name="makeSourceCode" depends="makeSourceCodeHTML, makeSourceCodeTex"/>



    <target name="makeExt" unless="ext-file-exists">
      <echo file="${doc}.ext.tex">% External documents referenced from here</echo>
    </target>

    <target name="properties" depends="logging,convertDB">
      <loadfile property="doctitle" srcfile="${doc}.info.tex">
    <filterchain>
      <linecontains>
        <contains value="\title{"/>
      </linecontains>
      <tokenfilter>
        <replaceregex pattern=" *\\title[{]([^}]*)[}]"
              replace="\1"/>
      </tokenfilter>
    </filterchain>
      </loadfile>
      <echo file="title.xml">&lt;title doc="${doc}"&gt;${doctitle}&lt;/title&gt;</echo>
      <copy file="../../templates/index.html" tofile="index.html" overwrite="true">
    <filterset>
      <filter token="doc" value="${doc}"/>
      <filter token="title" value="${doctitle}"/>
    </filterset>
      </copy>
    </target>

    <target name="makeHTML" depends="makeSources">
      <dependset>
    <srcfileset dir="." includes="*.html.xml"/>
    <targetfileset dir="." includes="*.html"/>
      </dependset>
      <xslt style="../../templates/modifyHTML.xsl" destdir=".">
    <fileset dir=".">
      <include name="*.html.xml"/>
    </fileset>
    <globmapper from="*.html.xml" to="*.html.tmp"/>
      </xslt>
      <copy todir=".">
    <fileset dir='.' includes="*.html.tmp"/>
    <globmapper from="*.html.tmp" to="*.html"/>
    <filterset>
      <filtersfile file="../../course.properties"/>
    </filterset>
      </copy>
      <delete>
    <fileset dir='.' includes="*.html.tmp"/>
      </delete>
    </target>


    <target name="setup" depends="convertDB,makeHTML,makeGraphics,makeSourceCode,makeExt"
        description="Prepare all source files prior to running LaTeX"
        >
      <replaceregexp file="index.html" match="@[^@]+@" replace="none" flags="g"/>
    </target>

    <dependset>
      <srcfileset dir=".">
    <include name="*.tex"/>
    <include name="*.ltx"/>
      </srcfileset>
      <targetfileset dir="." includes="${doc}-*.pdf"/>
    </dependset>

    <uptodate property="pdfGen.notRequired">
      <srcfiles dir= ".">
      <include name="*.ltx"/>
      </srcfiles>
      <globmapper from="*.ltx" to="*.pdf"/>
    </uptodate>

    <target name="genPDFs" depends="setup" unless="pdfGen.notRequired">
      <apply executable="latexmk" parallel="false">
    <arg value="-pdf"/>
    <env key="TEXMFHOME" value="../../templates//"/>
    <fileset dir="." includes="*.ltx"/>
    <globmapper from="*.ltx" to="*.pdf"/>
      </apply>
    </target>


    <target name="slides" depends="setup"
        description="Force a (single) latex run on the slides format - used for debugging slide content."
        >
      <exec executable="pdflatex">
    <arg value="${doc}-slides.ltx"/>
    <env key="TEXMFHOME" value="../../templates//"/>
      </exec>
    </target>

    <target name="printable" depends="setup"
        description="Force a (single) latex run on the printable format - used for debugging non-slide content."
        >
      <exec executable="pdflatex">
    <arg value="${doc}-printable.ltx"/>
    <env key="TEXMFHOME" value="../../templates//"/>
      </exec>
    </target>

    <target name="web" depends="setup"
        description="Force a (single) latex run on the web format - used for debugging non-slide content."
        >
      <exec executable="pdflatex">
    <arg value="${doc}-web.ltx"/>
    <env key="TEXMFHOME" value="../../templates//"/>
      </exec>
    </target>

    <target name="bookweb" depends="setup"
        description="Force a (single) latex run on the Book web format - used for debugging non-slide content."
        >
      <exec executable="pdflatex">
    <arg value="${doc}-bookweb.ltx"/>
    <env key="TEXMFHOME" value="../../templates//"/>
      </exec>
    </target>

    <target name="build" depends="genPDFs" 
        description="Generate all documents">
    </target>

    <target name="deploy" depends="build"
        description="Generate all documents and sync with the deployment directory (usually a website)"
        >
      <sync todir="${deploymentDestination}/${relPath}/${doc}" 
      includeEmptyDirs="true" granularity="2000">
    <fileset dir=".">
      <exclude name="**/*~"/>
      <exclude name="**/*.aux"/>
      <exclude name="**/*.fdb_latexmk"/>
      <exclude name="**/*.fls"/>
      <exclude name="**/*.log"/>
      <exclude name="**/*.out"/>
      <exclude name="**/*.toc"/>
      <exclude name="**/*.nav"/>
      <exclude name="**/*.snm"/>
      <exclude name="**/*.vrb"/>
      <exclude name="**/*.tex"/>
      <exclude name="**/*.ltx"/>
    </fileset>
    <preserveintarget>
      <include name="**/.ht*"/>
    </preserveintarget>
      </sync>
    </target>

    <target name="clean"
        description="Remove temporary files created when running LaTeX"
        >
      <delete>
    <fileset dir=".">
      <include name="*.fdb_latexmk"/>
      <include name="*.fls"/>
      <include name="*.nav"/>
      <include name="*.snm"/>
      <include name="*.vrb"/>
      <include name="*.log"/>
      <include name="*.out"/>
      <include name="*.h.html.xml"/>
      <include name="*.cpp.html.xml"/>
      <include name="*.java.html.xml"/>
    </fileset>
      </delete>
    </target>

    <target name="cleaner" depends="clean"
        description="Remove all files that can be easily regenerated, including the PDF documents, but leaving the aux and toc files (which can affect other documents in the website)."
        >
      <delete>
    <fileset dir=".">
      <include name="index.html"/>
      <include name="${doc}-*.pdf"/>
      <include name="*.h.tex"/>
      <include name="*.cpp.tex"/>
      <include name="*.java.tex"/>
      <include name="*.h.html"/>
      <include name="*.cpp.html"/>
      <include name="*.java.html"/>
    </fileset>
      </delete>
    </target>

    <target name="cleanest" depends="cleaner"
        description="Remove all files that can be automatically regenerated"
        >
      <delete>
    <fileset dir=".">
      <include name="${doc}-*.ltx"/>
      <include name="${doc}-*.main.tex"/>
      <include name="${doc}-*.aux"/>
      <include name="${doc}-*.toc"/>
    </fileset>
      </delete>
    </target>


</project>

4. Eclipse/Ant Integration


Limitations of Eclipse Builder


Project Dependencies

Eclipse supports the idea of projects that depend on other projects, so you could do


Eclipse/Ant Integration

Eclipse is generally ant-friendly.


Eclipse Builders

Eclipse supports multiple, plug-able builders.