ant is a build manager based upon a task dependency graph expressed in an XML file
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
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
The commands that people write into their makefile rules are generally not portable either:
/
in *nix versus \
in Windows, legal characters, quoting rules)
:
in *nix versus ;
in Windows)
Other Criticisms
Other Criticisms
Some feel that make is too low-level with its focus on individual files
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
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.
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.
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?
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.
The ant build file is an XML file.
<project name="382Website" default="deploy">
<description>
Extract Metadata Extractor - top level
</description>
⋮
</project>
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,
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.
➃ 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.
The Ant Manual has a good breakdown on these.
Consistent with their XML structure, tasks can be parameterized via attributes or nested XML attributes
Look at:
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
<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.
➃ Compiles Java source code from src/main/java/
, putting the .class
files into target/classes/
.
➄ Compiles Java source code from src/test/java/
, putting the .class
files into target/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.
➇ 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.
Eclipse is generally ant-friendly.
Drop a build.xml file into a project and Eclipse will recognize 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
Goals | scripting | make | ant |
---|---|---|---|
easy to use? | Y | Y | Y |
easy to set up for a given project? | N | N | N |
efficient: avoid redundant/unnecessary actions | N | Y | ? |
efficient: detect and abort bad builds in progress | ? | Y | ? |
incremental: allow focused/partial builds | ? | Y | Y |
flexible: allow for a variety of build actions | N | Y | Y |
flexible: builds on/for a variety of platforms | N | N | Y |
configurable: permit the management of multiple artifact configurations | ? | ? | Y |