Task Dependencies: ant
Steven J Zeil
Abstract
ant is a build manager based upon a task dependency graph expressed in an XML file
In this lesson we look at how ant addresses a number of shortcomings of make.
We will look at the task-based build model implemented by ant at how this differs from the dependency-based model of make, and at how to describe projects to the ant tool.
We will look at how ant could be applied to some of our sample projects.
ant
-
ant devised by James Davidson of Sun, contributed to Apache project (along with what would eventually become TomCat), released in 2000
-
Quickly became a standard tool for Java projects
- slower to move into other arenas
What’s Wrong with make?
ant is actually an acronym for Another Neat Tool.
But why do we need “another” tool, however neat, for build management?
-
make works by issuing commands to /bin/sh
- That’s not portable.
-
The commands that people write into their makefile rules are generally not portable either:
- Commands themselves are system-dependent (e.g., mkdir, cp, chmod
- Paths are system-dependent (
/
in *nix versus\
in Windows, legal characters, quoting rules) - Path lists are system-dependent (
:
in *nix versus;
in Windows)
Other Criticisms
-
Some feel that make is too low-level with its focus on individual files
-
Some will feel that ant is too high-level
-
But this is the apparent rationale for moving the focus from file dependencies to task dependencies.
-
-
The makefile syntax is arcane and hard to work with.
-
And XML syntax isn’t?
-
1 The ant Command
![](tasks.png)
-
ant looks for its instructions in a file named, by default, build.xml
-
The ant command can name any target to be built, e.g.,
ant setup
-
If no target is given, ant builds a target explicitly listed in build.xml as a default for the project.
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.
- The build file describes a project.
- The project has a name and a default target.
<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.
-
A target is an XML element and, as attributes, has a name and, optionally,
- a list of dependencies
- a condition
- a human-readable description
-
The target can contain multiple tasks, which contain the actual “commands” to get things done.
ant targets correspond, roughly, to make’s “artificial targets”.
Example of Targets
<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.
- The fact that the tag names resemble familiar commands is intended as self-documentation, but is not otherwise significant.
- The tag names actually map to Java class names that implement the task.
➃ This target illustrates both a dependency and a condition.
-
The tasks within this target would not be executed if I invoked ant like this:
ant -Dtest.skip=1
-
However, the
unittest
task would still be considered to have succeeded, in the sense that tasks that depend on it would be allowed to run.
Task versus File Dependencies
ant targets correspond, roughly, to make’s “artificial targets”.
So this build file
<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
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:
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
-
Each of the tasks is executed, but
-
The
javac
task knows not to re-compile Java files with up-to-date class files -
The
jar
task knows not to update Jar files that are newer than all of the files being added.
-
-
If we remove the
-Dskip.test=1
, however, the tests will be re-run. -
So some level of incremental behavior gets built into many of the individual tasks.
- The idea of avoiding unnecessary work is a fundamental part of
make
. - But it’s not fundamental to
ant
. It depends on the implementation of each individual task.
- The idea of avoiding unnecessary work is a fundamental part of
2.2 Ant Building Blocks and Concepts
(Optional reading. Read on if you actually want to use Ant. Otherwise, jump to Case Studies.)
2.2.1 Properties
Properties are named string values.
-
Can be set from the command line or via
<property
and a few other tasks -
Accessed as
${
_propertyName_}
-
Properties are immutable: once set, attempts to re-assign their values are ignored
-
By convention, properties names are grouped into faux hierarchies with ‘.’
- e.g.,
compile.src
,compile.dest
,compile.options
- e.g.,
The <property
Task
Two basic modes:
-
<property name="compile.options" value="-g -O1"/>
Sets this property to “-g -O1”
-
<property name="compile.src" location="src/main/java"/>
Sets this property to the absolute path of the directory/file named.
- The / and \ characters are changed as necessary to conform to the OS on which ant is being run.
Additional <property
Variants
-
<property file="project.default.properties"/>
Loads property values from a file, written as a series of property
=
_value_ linescourseName=CS795 baseurl=https://www.cs.odu.edu/~zeil/cs795SD/s13 homeurl=https://www.cs.odu.edu/~zeil/cs795SD/s13/Directory/topics.html email=zeil@cs.odu.edu
- A common use of this it to load in a personal file of login credentials and other private data:
<property file="${user.home}/.ant-global.properties"/>
The property
${user.home}
maps to the user’s home directory as appropriate to the operating system. If the file.ant-global.properties
exists, can load private info.- Should be protected (e.g., Unix protection
600
)
If the file does not exist, this does nothing at all.
- Should be protected (e.g., Unix protection
- A common use of this it to load in a personal file of login credentials and other private data:
-
<property environment="env"/>
Copies the OS environment variables into the build state, prefaced by the indicated prefix
- e.g.,
${env.PATH}
- e.g.,
2.2.2 File Sets and Lists
-
A file set is a collection of existing files
- can be specified using wild cards
-
A file list is a collection of files that may or may not exist
- Must be specified explicitly without wild cards
File Sets
<fileset file="src/main.cpp"/>
<fileset dir="src"
includes="main.cpp utility.h utility.cpp"/>
<fileset dir="src" includes="*.cpp,*.h"/>
-
More commonly seen as a nested form
<fileset id="unitTests" dir="bin"> <include name="**/Test*.class"/> <exclude name="**/*$*.class"/> <exclude name="**/*Debug.class"/> </fileset>
-
The
id
in the prior example allows later references:<fileset refid="unitTests"/>
File Lists
<filelist dir="src"
files="main.cpp utilities.h utilities.cpp"/>
- Can also use
id
orrefid
attributes
Mappers
-
Allow for a transformation of file names
-
Some commands use a file set to describe inputs, then a mapper to describe outputs
<fileset dir="src" includes="*.cpp"/> <globmapper from="*.cpp" to="*.o"/>
would map each file in src/*.cpp to a corresponding .o file
-
And
<fileset dir="bin" includes="**/Test*.java"/> <packagemapper from="*.class" to="*"/>
would map a compiled unit test file project/package/TestADT.class to project.package.TestADT
-
There are several other mappers as well
Selectors
Selectors provide more options for selecting files than simple include/exclude based on the names.
-
For example, our previous examples assumed that unit tests would be identified by file name
Test*.java
.Here we look instead for any Java file containing the JUnit4 @Test annotation.:
<fileset id="unitTestSrc" dir="src"> <include name="**/Test*.java"/> <contains text="@Test" casesensitive="no"/> </fileset>
-
Other selectors replicate several of the tests from the classic Unix find command
2.2.3 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
- For reason unclear to me, you cannot name classpaths and re-use them directly, but must do it this way
<path name="test.compile.classpath"> <pathelement path="${env.CLASSPATH}"/> <fileset dir="target/classes"> <include name="**/*.class"/> </fileset> <filelist refid="third-party_jars"/> </path> ⋮ <classpath refid="test.compile.classpath"/>
2.2.4 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>
-
loadfile
loads an entire file into a property -
The
linecontains
filter limits the portion of the file loaded to any line containing a LaTeX\title{
…}
command. - The
tokenfilter
filter does a regular expression match and replace on that line to extract only the portion of that line between the{ ... }
.
2.3 Tasks
The Ant Manual has a good breakdown on these.
-
Consistent with their XML structure, tasks can be parameterized via attributes or nested XML attributes
- Sometimes you can do the same thing either way.
-
Look at:
- File tasks: copy, delete, mkdir, move, fixcrlf, sync
- Compile tasks: javac, depend
- Archive, documentation, testing tasks
- Execution tasks: java, exec, apply
Extending Ant
-
Ant has a built-in macro capability
-
More powerful extension is accomplished by adding Java classes, mapped onto task names:
<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
-
Many Java-oriented tools (e.g. JFlex) come with an ant task as part of the package.
-
Other are contributed by users of the tool, (e.g. LaTeX)
-
Some general-purpose Ant libraries.
e.g., antcontrib adds
- C/C++ compilation
- If and For-loop
- outofdate (a make-like file dependency wrapper)
- enhanced property tasks (e.g., URL encoding)
3 Case Studies
3.1 Simple Java Build
<project name="codeAnnotation" basedir="." default="build"
xmlns:ivy="antlib:org.apache.ivy.ant">
<record name="ant.log" action="start" append="false" /> ➀
<path id="testCompilationPath"> ➁
<fileset dir="lib" includes="*.jar"/>
<pathelement path="target/classes"/>
</path>
<path id="testExecutionPath">
<fileset dir="lib" includes="*.jar"/>
<pathelement path="target/classes"/>
<pathelement path="target/test-classes"/>
</path>
<property name="build.dir" value="build"/>
<property name="src.dir" value="src"/>
<import file="ivyBuild.xml" as="ivy"/> ➂
<target name="compile" depends="ivy.resolve-ivy" ➃
description=
"Compile all source code, including the lexical
analysis code generated using jflex."
>
<mkdir dir="target/classes"/>
<javac srcdir="src/main/java" destdir="target/classes"
source="1.8" includeantruntime="false"/>
</target>
<target name="compile-tests" depends="compile" ➄
description="Compile JUnit tests"
>
<mkdir dir="target/test-classes"/>
<javac srcdir="src/test/java" destdir="target/test-classes"
source="1.8" includeantruntime="false">
<classpath refid="testCompilationPath"/>
</javac>
</target>
<target name="test" depends="compile-tests"
description="Run all JUnit tests, producing a
summary report in target/test-results."
>
<mkdir dir="target/test-results/details"/>
<junit printsummary="yes" ➅
haltonfailure="no" fork="no"
>
<classpath refid="testExecutionPath"/>
<formatter type="xml"/>
<batchtest todir="target/test-results/details">
<fileset dir="target/test-classes">
<include name="**/*Test*.class"/>
</fileset>
</batchtest>
</junit>
<junitreport todir="target/test-results"> ➆
<fileset dir="target/test-results/details">
<include name="TEST-*.xml"/>
</fileset>
<report format="frames" styledir="junit-stylesheets"
todir="target/test-results/html"/>
</junitreport>
</target>
<target name="build" depends="test"
description="Construct a jar file with the
compiled code and a zip file with the project
source code.">
<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>
-
➀ Copy all messages to a log file,
ant.log
-
➁ Set up some useful names for lists of paths.
-
➂ Ignore all “ivy” stuff for now. We’ll cover this in an upcoming lesson.
(OK, if you must know, this retrieves the latest versions of the JUnit and JFlex libraries from the internet and makes them available to this project build.)
-
➃ Compiles Java source code from
src/main/java/
, putting the.class
files intotarget/classes/
. -
➄ Compiles Java source code from
src/test/java/
, putting the.class
files intotarget/testclasses/
.I compile the tests separately from the “real” code so that later we can easily omit the test drivers from the published library’s binary code.
-
➅ Now we run the JUnit tests
haltonfailure
stops the build if we failed tests, so we never move on and produce a jar with known buggy code. -
➆ This produces an HTML report with summaries of how well our tests did. Example
-
➇ The compiled binaries for the “real” code (not the tests) are packaged into a
.jar
file.-
Note that the
.jar
production is simplified by having separated the project and test compilation results.
-
-
➈ Clean up is simple: delete the
target
directory
You can find this entire project, with the Ant files, here.
3.2 Java Build with Code Generation
Not All Sourcecode is Hand-Written
This project adds a stage before compilation to generate some of the source code that then needs to be compiled.
<project name="codeAnnotation" basedir="." default="build"
xmlns:ivy="antlib:org.apache.ivy.ant">
<record name="ant.log" action="start" append="false" />
<path id="testCompilationPath">
<fileset dir="lib" includes="*.jar"/>
<pathelement path="target/classes"/>
</path>
<path id="testExecutionPath">
<fileset dir="lib" includes="*.jar"/>
<pathelement path="target/classes"/>
<pathelement path="target/test-classes"/>
</path>
<property name="build.dir" value="build"/>
<property name="src.dir" value="src"/>
<import file="ivyBuild.xml" as="ivy"/>
<target name="generateSource" depends="ivy.resolve-ivy"
description="Use jflex to process lexeme descriptions
for C++ and Java, generating the Java source code for
the resulting lexical analyzers."
>
<taskdef classpath="lib/jflex-1.4.3.jar" ➀
classname="JFlex.anttask.JFlexTask" name="jflex" />
<mkdir dir="target/gen/java"/>
<jflex file="src/main/jflex/code2html.flex" ➁
destdir="target/gen/java"/>
<jflex file="src/main/jflex/code2tex.flex"
destdir="target/gen/java"/>
<jflex file="src/main/jflex/list2html.flex"
destdir="target/gen/java"/>
<jflex file="src/main/jflex/list2tex.flex"
destdir="target/gen/java"/>
</target>
<target name="compile" depends="generateSource" ➂
description=
"Compile all source code, including the lexical
analysis code generated using jflex."
>
<mkdir dir="target/classes"/>
<javac srcdir="target/gen/java" destdir="target/classes" ➃
source="1.7" includeantruntime="false"/>
<javac srcdir="src/main/java" destdir="target/classes"
source="1.7" includeantruntime="false"/>
</target>
<target name="compile-tests" depends="compile"
description="Compile JUnit tests"
>
<mkdir dir="target/test-classes"/>
<javac srcdir="src/test/java" destdir="target/test-classes"
source="1.7" includeantruntime="false">
<classpath refid="testCompilationPath"/>
</javac>
</target>
<target name="test" depends="compile-tests"
description="Run all JUnit tests, producing a
summary report in target/test-results."
>
<mkdir dir="target/test-results/details"/>
<junit printsummary="yes"
haltonfailure="no" fork="no"
>
<classpath refid="testExecutionPath"/>
<formatter type="xml"/>
<batchtest todir="target/test-results/details">
<fileset dir="target/test-classes">
<include name="**/*Test*.class"/>
</fileset>
</batchtest>
</junit>
<junitreport todir="target/test-results">
<fileset dir="target/test-results/details">
<include name="TEST-*.xml"/>
</fileset>
<report format="frames" styledir="junit-stylesheets" todir="target/test-results/html"/>
</junitreport>
</target>
<target name="build" depends="test"
description="Construct a jar file with the
compiled code and a zip file with the project
source code.">
<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>
<target name="cleaner" depends="clean">
<delete dir="lib"/>
</target>
<target name="cleanest" depends="cleaner">
<delete dir="ivy"/>
</target>
</project>
-
➀ The
taskdef
“declares” a newjflex
task. -
➁ Here we use
jflex
to generate a scanner from several sets of regular expressions.The source code for the new scanner is placed in
target/gen/java
, keeping it separate from our hand-written code. -
➂ Compilation can only occur if
generateSource
was run. -
➃ Here I have modified my original compilation instructions to also compile any Java source code in the new
src/generated/java
directory.
You can find this entire project, with the Ant files, here.
3.3 C++ Multi-project Build
Because this project is divided into multiple subprojects, we will have multiple build.xml
files:
- One per subproject
- And a master to launch them all.
3.3.1 The master file
In the project root directory:
<project name="manhattan" basedir='.' default="build">
<record name="ant.log" action="start" append="false" />
<!-- Invoke this build file as
ant
- to build the project
ant clean
- to clean out all generated files
-->
<target name="build">
<ant target="build" antfile="gtest/build.xml" inheritAll="false"/>
<ant target="build" antfile="lib/build.xml" inheritAll="false"/>
<ant target="build" antfile="exe/build.xml" inheritAll="false"/>
</target>
<target name="clean">
<ant target="clean" antfile="gtest/build.xml" inheritAll="false"/>
<ant target="clean" antfile="lib/build.xml" inheritAll="false"/>
<ant target="clean" antfile="exe/build.xml" inheritAll="false"/>
</target>
</project>
3.3.2 The lib subproject
<project name="manhattan-lib" basedir="." default="build"
xmlns:cpptasks="antlib:net.sf.antcontrib.cpptasks"
>
<description>
Builds the ADTs for the manhattan program.
</description>
<property file="${user.home}/.ant-global.properties"/>
<record name="ant.log" action="start" append="false" />
<taskdef classpath="../antcontrib-cpptasks.jar" ➀
resource="net/sf/antcontrib/cpptasks/antlib.xml" />
<target name="compile">
<mkdir dir="build/objs/main"/>
<mkdir dir="build/libs"/>
<cc outtype="static" ➁
subsystem="console"
name="g++"
outfile="build/libs/main"
objdir="build/objs/main">
<fileset dir="src/main/cpp">
<include name="**/*.cpp"/>
</fileset>
<includepath path="src/main/headers"/>
</cc>
</target>
<target name="compiletest" depends="compile"> ➂
<mkdir dir="build/objs/test"/>
<mkdir dir="build/exe"/>
<cc outtype="executable"
subsystem="console"
name="g++"
objdir="build/objs/test">
<fileset dir="src/mainTest/cpp">
<include name="**/*.cpp"/>
</fileset>
<compilerarg value='-g'/>
<compilerarg value='-pthread'/>
<includepath path="src/main/headers"/>
<includepath path="../gtest/include"/>
</cc>
<apply executable="g++"> <!-- Using apply because I can't get ➃
linking to work in antcontrib -->
<arg value="-o"/>
<arg value="build/exe/runTests"/>
<arg value="../gtest/build/libs/libgtest.a"/>
<arg value="build/libs/libmain.a"/>
<arg value="-lpthread"/>
<fileset dir="build/objs/test">
<include name="*.o"/>
</fileset>
</apply>
</target>
<target name="test" depends="compiletest">
<exec executable="build/exe/runTests"/> ➄
</target>
<target name="build" depends="test"/>
<target name="clean">
<delete dir="build"/>
</target>
</project>
-
➀
AntContrib
provides a set of C++ tasks. -
➁ Compile the source code. The
outtype
indicates that we are generating a (static) library. -
➂ Compile the unit tests. The
outtype
indicates that we are generating an executable. -
➃ Unfortunately, I cannot get linking to work properly with the
cc
task, so I forced that as an OS command. -
➄ Run the unit test executable.
The other subproject build.xml
files are similar, but simpler.
You can find this entire project, with the Ant files, here.
4 Eclipse/Ant Integration
Limitations of Eclipse Builder
-
Cannot run code-proprocessing (e.g., JFlex)
-
An Eclipse project is oriented towards producing a single output product (program, library, … )
-
With C++ projects, a problem if you have a “real” product
(e.g., a library) and a set of test drivers, each of which yields a distinct program executable.
- Java projects have fewer problems (because executables don’t need separate processing),
- but what if you are planning to generate both
- a binary distribution jar, and
- a source distribution jar?
- but what if you are planning to generate both
-
Project Dependencies
Eclipse supports the idea of projects that depend on other projects, so you could do
-
project1 produces the binary distribution jar
-
project2 depends on project1 and produces a source distribution jar
- These projects must reside together in a known relative path from one another
- project2 is not automatically rebuild if project1 has changed
-
Does not scale well.
- For C++ are you going to have a distinct project for each test driver?
Eclipse/Ant Integration
Eclipse is generally ant-friendly.
-
Drop a build.xml file into a project and Eclipse will recognize it.
- Right-clicking on it will bring up options to run it, or to configure how to run it
- including the selection of the target
- some preference given to targets with descriptions
- Right-clicking on it will bring up options to run it, or to configure how to run it
-
Once ant has been run, the “Run Last Tool” button defaults to re-running it.
-
But the default build is still Eclipse’s default build manager
- For projects with elaborate classpaths, requires keeping both the Eclipse project description and the build file up-to-date and consistent.
- Pre-compilation steps (e.g., tools that generate source code) are not re-run automatically when needed.
Eclipse Builders
Eclipse supports multiple, plug-able builders.
-
Open Project Properties and go to “Builders”
- In a typical java project, you have just the “Java Builder”
- Click new to see options.
In this case, select “Ant Builder”.
-
Fill in the main screen. Leave “Arguments” blank.
-
Go to the Targets tab. Select appropriate targets for
Clean: Menu selection
Project->clean
Manual build: What you want done after explicitly requesting a build
Auto build: What you want done after a file has been saved/changed
-
Return to the Builders list and uncheck the “Java Builder”