Antlibs & Namespaces
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
This page is written against Apache Ant 1.10.18. Every example was run on JDK 26 on 2026-10-16 with the Ant 1.10.18
distribution unpacked in a scratch directory and the ant launch script on the PATH. The optional libraries were downloaded
from Maven Central and their SHA-1 checked: AntUnit 1.5.0, Apache Ivy 2.6.0, the Props antlib 1.0.0, the Compress antlib 1.5 and
Ant-Contrib 1.0b3. Paths in console output were shortened to /work/..., $ANT_HOME and /home/user.
A build file can only use a task whose name Ant knows. Before Ant 1.6 (2003) a library of tasks could ship a properties file with
all its names, but the build file writer had no way to prefix those names or to override one that clashed with another library.
Ant 1.6 added two things that solve this and that this page is about: XML namespaces for build files, so that a definition lives in a
namespace and cannot clash with another one, and the antlib, a descriptor file that lists the definitions of a library, which can
be found automatically from the name of a namespace. The page starts with how Ant’s own tasks are registered,
explains namespaces and the descriptor, packages the tidepool <checkstations> task of
Writing Custom Tasks as an antlib, and ends with the
places where a library can be installed and a tour of the optional libraries.
Core, optional and third-party: where a name comes from
Three kinds of definitions coexist in a build, and they differ in how Ant finds them, not in how they look in the XML:
| Kind | Examples | How Ant finds it |
|---|---|---|
Core |
|
Registered by lists inside |
Optional |
|
Registered by the same lists, but implemented in an |
Antlib |
AntUnit, Compress, CycloneDX, Props (Apache), Ivy, Ant-Contrib and your own |
Not registered by Ant. Declared by the build with |
The registration of core and optional definitions is plain text inside ant.jar, which can be listed and read:
$ unzip -l $ANT_HOME/lib/ant.jar | grep -E 'antlib.xml|defaults.properties'
org/apache/tools/ant/antlib.xml
org/apache/tools/ant/listener/defaults.properties
org/apache/tools/ant/taskdefs/defaults.properties
org/apache/tools/ant/types/conditions/antlib.xml
org/apache/tools/ant/types/defaults.properties
org/apache/tools/ant/types/resources/comparators/antlib.xml
org/apache/tools/ant/types/resources/selectors/antlib.xml
$ unzip -p $ANT_HOME/lib/ant.jar org/apache/tools/ant/taskdefs/defaults.properties | grep -E '^(copy|javac|junitlauncher|sshexec)='
copy=org.apache.tools.ant.taskdefs.Copy
javac=org.apache.tools.ant.taskdefs.Javac
junitlauncher=org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.JUnitLauncherTask
sshexec=org.apache.tools.ant.taskdefs.optional.ssh.SSHExec
The task lists are defaults.properties files, one name=class line per task, and the ones for conditions, selectors and
comparators are antlib.xml files with componentdef entries marked onerror="ignore":
$ unzip -p $ANT_HOME/lib/ant.jar org/apache/tools/ant/antlib.xml | grep -B1 -A1 -m3 'componentdef name'
<!-- conditions -->
<componentdef name="and" onerror="ignore"
classname="org.apache.tools.ant.taskdefs.condition.And"/>
<componentdef name="canCreateSymlink" onerror="ignore"
classname="org.apache.tools.ant.taskdefs.condition.CanCreateSymbolicLink"/>
<componentdef name="contains" onerror="ignore"
classname="org.apache.tools.ant.taskdefs.condition.Contains"/>
Ant parses that antlib.xml when it starts a build, as a run with -v shows:
$ ant -v -f where.xml | grep antlib.xml
parsing buildfile jar:file:$ANT_HOME/lib/ant.jar!/org/apache/tools/ant/antlib.xml with URI = jar:file:$ANT_HOME/lib/ant.jar!/org/apache/tools/ant/antlib.xml from a zip file
The consequence of "registered by name, implemented in another JAR" is that an optional task whose JAR is missing is known but
not loadable, and Ant says so. The experiment runs <junitlauncher/> in the full distribution and in a copy of the lib
directory without ant-junitlauncher.jar (every other JAR was linked from the distribution):
$ ant -f launcher.xml
Buildfile: /work/tidepool-antlib/launcher.xml
try:
BUILD SUCCESSFUL
Total time: 0 seconds
$ ANT_HOME=fakeant ant -f launcher.xml
Buildfile: /work/tidepool-antlib/launcher.xml
try:
BUILD FAILED
/work/tidepool-antlib/launcher.xml:4: Problem: failed to create task or type junitlauncher
Cause: the class org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.JUnitLauncherTask was not found.
This looks like one of Ant's optional components.
Action: Check that the appropriate optional JAR exists in
-fakeant/lib
-/home/user/.ant/lib
-a directory added on the command line with the -lib argument
Do not panic, this is a common problem.
The commonest cause is a missing JAR.
This is not a bug; it is a configuration problem
Total time: 0 seconds
The message names the class, says that it is one of Ant’s optional components and lists the three places where a JAR is looked
up (ANT_HOME/lib, the user’s ~/.ant/lib and directories added with -lib). Those places come back below.
XML namespaces in a build file
Ant 1.6 turned namespace support on in its XML parser. The effect is that a colon in an element name now means a prefix, and
an attribute called xmlns or xmlns:prefix is a namespace declaration rather than a parameter of the task. Build files from
before 1.6 that used colons in custom task names, or tasks that had attributes called xmlns..., broke at that point.
A definition is placed in a namespace with the uri attribute of <taskdef> and <typedef>; the build file then maps a prefix
to the same URI with xmlns:prefix, at the root or on any element. The URI is just an identifier, it is never fetched. The rules
from the manual page XML Namespace Support:
-
The default namespace of Ant itself is
antlib:org.apache.tools.ant. Elements with no namespace belong to it, and a definition withouturigoes there: this is why a<taskdef>withouturidefines a bare element. -
An element in a namespace can be written with a prefix (
<my:task xmlns:my="...">) or by making the namespace the default for a subtree (<task xmlns="...">). -
Elements nested in a namespaced element are expected in the same namespace; since Ant 1.6.2 they may also be in Ant’s default namespace.
-
Attributes are used to configure an element only if they have no namespace (the default namespace does not apply to attributes) or are in the namespace of their element. Attributes of another namespace are ignored, so build files can carry metadata; an element of a namespace that was never defined is an error.
-
A definition can only be used where its type is accepted, so mixing namespaces works for typed nesting, such as a custom condition inside Ant’s
<condition>.
The tidepool antlib below is used under the prefix td in one build file and under the prefix tide and the URI urn:tidepool
in another. Neither the prefix nor the URI is a property of the library; the build file chooses both when it defines.
The antlib descriptor
An antlib file is an XML file with the root element antlib. Its children are the definition tasks that Ant bundles with
this role, namely taskdef, typedef, macrodef, presetdef and scriptdef, and any other task that extends
org.apache.tools.ant.taskdefs.AntlibDefinition, such as componentdef. That is how a single descriptor can define Java
tasks, a macro written in XML and defaults for an existing task. The descriptor of the tidepool library:
<?xml version="1.0" encoding="UTF-8"?>
<antlib xmlns:current="ant:current">
<taskdef name="checkstations" classname="io.tidepool.ant.CheckStationsTask"/>
<taskdef name="foreachstation" classname="io.tidepool.ant.ForEachStationTask"/>
<presetdef name="check-strict">
<current:checkstations minconstituents="2" failonerror="true"/>
</presetdef>
<macrodef name="check-all">
<attribute name="dir" default="data"/>
<attribute name="includes" default="stations.csv"/>
<sequential>
<current:check-strict>
<fileset dir="@{dir}" includes="@{includes}"/>
</current:check-strict>
</sequential>
</macrodef>
</antlib>
Three lines carry the ideas of the page:
-
The
<taskdef>elements have anameand aclassnamebut noclasspathand nouri: the library is loaded from a class path that is already set up, and the namespace is whatever the user’suriorxmlnssays. -
xmlns:current="ant:current"declares a prefix for the special namespaceant:current. While an antlib is being loaded, every definition it makes lands in the namespace chosen by the caller, which the antlib cannot know.ant:currentnames that namespace, whatever it is, so the macrocheck-allcan use the task and the presetcheck-strictthat the same file defines. The log of a run shows the prefix: the preset runs under the namecurrent:check-strict(see below). -
Names can be reused from the core: the manual’s example defines a
presetdefnamedjavacin an antlib, which users who put it in their own namespace get aslocal:javac, with defaults, without touching the core<javac>. The definitions of Macros & Presets work the same way inside an antlib.
A macro or preset that forgets current: fails as soon as the antlib is used from a namespace, because the unprefixed name is looked
up in the default namespace. The experiment is a variant of the descriptor whose preset says <checkstations .../> and not
<current:checkstations .../>:
<antlib>
<taskdef name="checkstations" classname="io.tidepool.ant.CheckStationsTask"/>
<presetdef name="check-strict">
<checkstations minconstituents="2"/>
</presetdef>
</antlib>
$ ant -lib build/broken -f use-broken.xml
Buildfile: /work/tidepool-antlib/use-broken.xml
check:
BUILD FAILED
/work/tidepool-antlib/use-broken.xml:5: The following error occurred while executing this line:
Unable to find typedef checkstations
Total time: 0 seconds
The message names the definition that is missing but not the file that contains the mistake.
Source: Apache Ant manual: Antlib and the current namespace
Packaging the tidepool task as an antlib
The tasks keep their classes. The only new file is the descriptor, which goes in the package directory of the library under the
fixed name antlib.xml. The JAR then has the classes and, next to them, the descriptor:
<?xml version="1.0" encoding="UTF-8"?>
<project name="tidepool-antlib" default="jar" basedir=".">
<property name="classes.dir" location="build/classes"/>
<property name="jar.file" location="build/tidepool-ant.jar"/>
<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="tidepool-ant/src/main/java" destdir="${classes.dir}"
release="21" includeantruntime="false" encoding="UTF-8">
<classpath>
<pathelement location="${ant.core.lib}"/>
</classpath>
</javac>
</target>
<target name="jar" depends="compile">
<jar destfile="${jar.file}">
<fileset dir="${classes.dir}"/>
<fileset dir="tidepool-ant/src/main/resources"/>
</jar>
</target>
</project>
$ ant jar
Buildfile: /work/tidepool-antlib/build.xml
compile:
[mkdir] Created dir: /work/tidepool-antlib/build/classes
[javac] Compiling 2 source files to /work/tidepool-antlib/build/classes
jar:
[jar] Building jar: /work/tidepool-antlib/build/tidepool-ant.jar
BUILD SUCCESSFUL
Total time: 0 seconds
$ unzip -l build/tidepool-ant.jar
META-INF/
META-INF/MANIFEST.MF
io/
io/tidepool/
io/tidepool/ant/
io/tidepool/ant/CheckStationsTask$ReportMode.class
io/tidepool/ant/CheckStationsTask$Require.class
io/tidepool/ant/CheckStationsTask.class
io/tidepool/ant/ForEachStationTask.class
io/tidepool/ant/antlib.xml
The <javac> classpath uses ${ant.core.lib}, the built-in property that holds the absolute path of ant.jar. Two other
properties that the launcher sets are ant.home and ant.library.dir, the directory from which Ant’s JARs were loaded (usually
ANT_HOME/lib); the latter is not set when Ant runs inside an IDE.
<?xml version="1.0" encoding="UTF-8"?>
<project name="where" default="show">
<target name="show">
<echo>ant.home=${ant.home}</echo>
<echo>ant.core.lib=${ant.core.lib}</echo>
<echo>ant.library.dir=${ant.library.dir}</echo>
<echo>ant.version=${ant.version}</echo>
</target>
</project>
$ ant -q -f where.xml
[echo] ant.home=$ANT_HOME
[echo] ant.core.lib=$ANT_HOME/lib/ant.jar
[echo] ant.library.dir=$ANT_HOME/lib
[echo] ant.version=Apache Ant(TM) version 1.10.18 compiled on September 3 2026
BUILD SUCCESSFUL
Total time: 0 seconds
Using the antlib
There are three ways to bring the library to a build, from the least to the most explicit.
By namespace: antlib:java.package
A namespace URI of the form antlib:java.package is special. When Ant meets an element in such a namespace and nothing has been
defined for it yet, it looks for a resource java/package/antlib.xml on its own class path and, if it finds one, loads it
into that namespace. The class path here is Ant’s own, not the build’s: the JAR must be in ANT_HOME/lib, in ~/.ant/lib,
or on -lib or CLASSPATH. The manual notes that the restriction to the default class path may be removed in a later version.
The build file needs only the namespace declaration:
<?xml version="1.0" encoding="UTF-8"?>
<project name="use" default="check" basedir="."
xmlns:td="antlib:io.tidepool.ant">
<target name="check">
<td:checkstations file="data/stations.csv" minconstituents="2" report="full"/>
<td:check-all/>
<td:foreachstation file="data/stations.csv">
<echo>station ${station.id}</echo>
</td:foreachstation>
</target>
</project>
Without the JAR on Ant’s class path, the namespace is "an antlib declaration" with no definitions, and Ant tells where it looked (three paths, shown here after shortening):
$ ant -f use.xml
Buildfile: /work/tidepool-antlib/use.xml
check:
BUILD FAILED
/work/tidepool-antlib/use.xml:6: Problem: failed to create task or type antlib:io.tidepool.ant:checkstations
Cause: The name is undefined.
Action: Check the spelling.
Action: Check that any custom tasks/types have been declared.
Action: Check that any <presetdef>/<macrodef> declarations have taken place.
No types or tasks have been defined in this namespace yet
This appears to be an antlib declaration.
Action: Check that the implementing library exists in one of:
-$ANT_HOME/lib
-/home/user/.ant/lib
-a directory added on the command line with the -lib argument
Total time: 0 seconds
With the library on -lib the same file runs, and uses all three kinds of definition in the library: a task, a macro that wraps a
preset that wraps the task, and the task container. The log prefix current:check-strict is the ant:current namespace at work:
$ ant -lib build/tidepool-ant.jar -f use.xml
Buildfile: /work/tidepool-antlib/use.xml
check:
[td:checkstations] Stations seen: BOS,HNL,SF
[td:checkstations] 1 file(s), 3 station(s): OK
[current:check-strict] 1 file(s), 3 station(s): OK
[echo] station SF
[echo] station BOS
[echo] station HNL
BUILD SUCCESSFUL
Total time: 0 seconds
By taskdef or typedef from inside the build file
When the JAR belongs to the project (checked into the repository, or built by the same build) and should not be installed in Ant,
the build loads it explicitly with <taskdef> or <typedef>, with a resource, a uri and a classpath. The manual calls this
"the best solution" for the case, because it needs no setup outside the project:
<?xml version="1.0" encoding="UTF-8"?>
<project name="use-taskdef" default="check" basedir="."
xmlns:td="antlib:io.tidepool.ant">
<taskdef uri="antlib:io.tidepool.ant" resource="io/tidepool/ant/antlib.xml"
classpath="build/tidepool-ant.jar"/>
<target name="check">
<td:check-all/>
</target>
</project>
$ ant -f use-taskdef.xml
Buildfile: /work/tidepool-antlib/use-taskdef.xml
check:
[current:check-strict] 1 file(s), 3 station(s): OK
BUILD SUCCESSFUL
Total time: 0 seconds
<typedef> and <taskdef> are interchangeable for a resource that points at an antlib, because the descriptor says which
definitions are tasks. The uri need not be an antlib: URI; any name works, as long as the xmlns of the build file uses
the same string. The next file picks urn:tidepool and the prefix tide, and checks every CSV in the data directory (the build
fails, because bad.csv is in there; the second half of the output is the error, whose location is inside the JAR, where the
failing preset was written):
<?xml version="1.0" encoding="UTF-8"?>
<project name="use-urn" default="check" basedir="."
xmlns:tide="urn:tidepool">
<typedef resource="io/tidepool/ant/antlib.xml" uri="urn:tidepool"
classpath="build/tidepool-ant.jar"/>
<target name="check">
<tide:check-all includes="*.csv" dir="data"/>
</target>
</project>
$ ant -f use-urn.xml
Buildfile: /work/tidepool-antlib/use-urn.xml
check:
[current:check-strict] bad.csv:3 latitude 137.8 is outside [-90.0, 90.0]
[current:check-strict] bad.csv:4 latitude is not a number: 'north'
[current:check-strict] bad.csv:4 has 1 constituent(s), at least 2 required
[current:check-strict] bad.csv:5 duplicate station id SF
[current:check-strict] bad.csv:5 has 0 constituent(s), at least 2 required
[current:check-strict] stations.csv:2 duplicate station id SF
[current:check-strict] stations.csv:3 duplicate station id BOS
BUILD FAILED
/work/tidepool-antlib/use-urn.xml:9: The following error occurred while executing this line:
jar:file:/work/tidepool-antlib/build/tidepool-ant.jar!/io/tidepool/ant/antlib.xml:14: 7 problem(s) found in station data
Total time: 0 seconds
Leaving out the uri defines the names in Ant’s default namespace, so that the build file needs no prefix at all. That is
convenient and gives up the protection against clashes, which is the reason for namespaces in the first place:
<?xml version="1.0" encoding="UTF-8"?>
<project name="use-global" default="check" basedir=".">
<taskdef resource="io/tidepool/ant/antlib.xml" classpath="build/tidepool-ant.jar"/>
<target name="check">
<check-all/>
</target>
</project>
$ ant -f use-global.xml
Buildfile: /work/tidepool-antlib/use-global.xml
check:
[current:check-strict] 1 file(s), 3 station(s): OK
BUILD SUCCESSFUL
Total time: 0 seconds
Two ways to get this wrong. The <taskdef> without a uri, used with a namespace prefix, defines the names, but in the wrong place
(the message is the same one as with a missing JAR, which is why it is so confusing):
<project xmlns:td="antlib:io.tidepool.ant">
<taskdef resource="io/tidepool/ant/antlib.xml" classpath="build/tidepool-ant.jar"/>
...
<td:check-all/>
$ ant -f wrong-uri.xml
Buildfile: /work/tidepool-antlib/wrong-uri.xml
check:
BUILD FAILED
/work/tidepool-antlib/wrong-uri.xml:8: Problem: failed to create task or type antlib:io.tidepool.ant:check-all
Cause: The name is undefined.
Action: Check the spelling.
Action: Check that any custom tasks/types have been declared.
Action: Check that any <presetdef>/<macrodef> declarations have taken place.
No types or tasks have been defined in this namespace yet
This appears to be an antlib declaration.
Action: Check that the implementing library exists in one of:
-$ANT_HOME/lib
-/home/user/.ant/lib
-a directory added on the command line with the -lib argument
Total time: 0 seconds
And a resource that does not exist, in a <taskdef> that has no onerror. Despite the default of fail, a missing
resource is only a warning, and the build goes on; onerror="failall" (Ant 1.6) makes it an error:
$ ant -f wrong-resource.xml
Buildfile: /work/tidepool-antlib/wrong-resource.xml
[taskdef] Could not load definitions from resource io/tidepool/antlib.xml. It could not be found.
check:
BUILD SUCCESSFUL
Total time: 0 seconds
$ ant -f wrong-resource-failall.xml
Buildfile: /work/tidepool-antlib/wrong-resource-failall.xml
BUILD FAILED
/work/tidepool-antlib/wrong-resource-failall.xml:3: Could not load definitions from resource io/tidepool/antlib.xml. It could not be found.
Total time: 0 seconds
Use failall whenever a missing library should end the build. The other values are report, which also warns when a definition
cannot be loaded, and ignore, which is what Ant’s own antlib.xml uses on every componentdef, so that a definition whose
class is missing is silently skipped; the manual’s antlib example uses onerror="ignore" for the same reason.
Everything said on
Writing Custom Tasks about class loaders applies: a
<taskdef resource=...> with a classpath creates one AntClassLoader for the whole descriptor, so the tasks of one antlib
share classes and cooperate with no loaderref. This is why the manual recommends an antlib for "tasks and types that are
supposed to cooperate".
Installing the library for every build
The third way, the JAR on Ant’s own class path, is a matter of where it is. Ant 1.6 added -lib and the per-user directory; the
order is the one the manual lists:
-
jars given with
-lib, in the order on the command line (theCLASSPATHenvironment variable is also passed to Ant as a-lib, unless-noclasspathis given); -
jars in
${user.home}/.ant/lib(unless-nouserlibis given); -
jars in
ANT_HOME/lib.
Ant itself starts with a minimal class path; the rest is built by its launcher from these three sources. The directory can be
exercised without changing the real home directory, by pointing the user.home system property of the launcher JVM to a scratch
directory through ANT_OPTS:
$ mkdir -p fakehome/.ant/lib && cp build/tidepool-ant.jar fakehome/.ant/lib/
$ ANT_OPTS=-Duser.home=$PWD/fakehome ant -f use.xml
Buildfile: /work/tidepool-antlib/use.xml
check:
[td:checkstations] Stations seen: BOS,HNL,SF
[td:checkstations] 1 file(s), 3 station(s): OK
[current:check-strict] 1 file(s), 3 station(s): OK
[echo] station SF
[echo] station BOS
[echo] station HNL
BUILD SUCCESSFUL
Total time: 0 seconds
$ ANT_OPTS=-Duser.home=$PWD/fakehome ant -nouserlib -f use.xml
Buildfile: /work/tidepool-antlib/use.xml
check:
BUILD FAILED
/work/tidepool-antlib/use.xml:6: Problem: failed to create task or type antlib:io.tidepool.ant:checkstations
Cause: The name is undefined.
Action: Check the spelling.
...
ANT_ARGS carries command-line arguments of Ant that apply to every run in that shell, including -lib; the manual’s
examples are a logger, a listener and -find. Here it carries a -lib and -q:
$ ANT_ARGS="-lib build/tidepool-ant.jar -q" ant -f use.xml
[echo] station SF
[echo] station BOS
[echo] station HNL
BUILD SUCCESSFUL
Total time: 0 seconds
Choose by who must have the library:
| Location | Use it for |
|---|---|
|
One build or one CI job; the JAR can live in the repository and the command line is the documentation. |
|
Tools that belong to one developer (an IDE helper, a personal logger). The build must not depend on it, or it fails on every other machine. |
|
A shared installation (a build server image). Changing it means modifying the Ant installation, which the manual says should be lockable, and the reason to prefer the user directory for personal jars. |
|
A library that is part of the project. Nothing outside the repository is needed. |
For reproducible builds the last row (or -lib with a version-controlled path) is the only one that does not depend on the machine.
The optional antlibs
The Apache Ant project publishes a small set of antlibs, all of which use the mechanism described above and are on Maven Central
(org.apache.ant). The current ones are listed on the Ant Libraries page, with their compatibility with Ant:
| Antlib | Namespace URI (from the JAR) | Purpose | Run on this page |
|---|---|---|---|
AntUnit 1.5.0 |
|
Tests for tasks and build files, with assertion tasks; needs Ant 1.10.13 or later. |
Yes, below and on Writing Custom Tasks |
Props 1.0.0 |
|
Extra property evaluators for the PropertyHelper: nested properties, string operations and others. |
Yes, below |
Compress 1.5 |
|
Archive and compression formats that Ant’s core lacks: 7z, ar, arj, cpio, brotli and others (it needs Commons Compress). Its last release is from 2017. |
Not run here; the namespace was read from the descriptor in the JAR |
CycloneDX 0.2 |
|
Creates CycloneDX SBOMs, from Ivy modules or from information given by hand. |
Not run here; the namespace was read from the descriptor in the JAR. See Supply-Chain Security |
Outside the Ant project, two libraries are in common use. Apache Ivy is a separate Apache project with its own antlib
(antlib:org.apache.ivy.ant), covered on
Ivy Overview. Ant-Contrib (version 1.0b3) is a third-party
library with if, for, foreach, var and many other tasks. It is dormant and not hosted by Apache, although the Ant site lists it on its
projects page and the manual pages of macrodef and script link to it, and most
of what it was used for has a core replacement (import, macrodef, local and the if:/unless: attributes); it is shown here because old
build files use it, and the antlib URI given in the manual page of antlibs is antlib:net.sf.antcontrib.
All three load the same way. This build file declares all three libraries with <taskdef>, which shows that a build can mix
sources and namespaces, and uses one task from each (the Ivy call downloads commons-csv from Maven Central into the Ivy
cache, which is why the report says that nothing was downloaded: the cache of the machine already had the artefacts):
<?xml version="1.0" encoding="UTF-8"?>
<project name="optional" default="all" basedir="."
xmlns:au="antlib:org.apache.ant.antunit"
xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:ac="antlib:net.sf.antcontrib">
<target name="all" depends="antunit, ivy, contrib"/>
<target name="antunit">
<typedef resource="org/apache/ant/antunit/antlib.xml" uri="antlib:org.apache.ant.antunit"
classpath="lib/ant-antunit-1.5.0.jar"/>
<au:assertTrue message="1 is not 1">
<equals arg1="1" arg2="1"/>
</au:assertTrue>
<echo>AntUnit loaded from an explicit classpath</echo>
</target>
<target name="ivy">
<taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant"
classpath="lib/ivy-2.6.0.jar"/>
<ivy:cachepath organisation="org.apache.commons" module="commons-csv" revision="1.14.1"
inline="true" conf="default" pathid="csv.path"/>
<pathconvert property="csv.jar" refid="csv.path" pathsep=", ">
<mapper type="flatten"/>
</pathconvert>
<echo>Ivy resolved: ${csv.jar}</echo>
</target>
<target name="contrib">
<taskdef resource="net/sf/antcontrib/antlib.xml" uri="antlib:net.sf.antcontrib"
classpath="lib/ant-contrib-1.0b3.jar"/>
<ac:for list="SF,BOS,HNL" param="id">
<sequential>
<echo>station @{id}</echo>
</sequential>
</ac:for>
</target>
</project>
$ ant -f optional.xml
Buildfile: /work/tidepool-antlib/optional.xml
antunit:
[echo] AntUnit loaded from an explicit classpath
ivy:
[ivy:cachepath] :: Apache Ivy 2.6.0 - 20260712075753 :: https://ant.apache.org/ivy/ ::
[ivy:cachepath] :: loading settings :: url = jar:file:/work/tidepool-antlib/lib/ivy-2.6.0.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:cachepath] :: resolving dependencies :: org.apache.commons#commons-csv-caller;working
[ivy:cachepath] confs: [default]
[ivy:cachepath] found org.apache.commons#commons-csv;1.14.1 in public
[ivy:cachepath] found commons-io#commons-io;2.20.0 in public
[ivy:cachepath] found commons-codec#commons-codec;1.19.0 in public
[ivy:cachepath] :: resolution report :: resolve 67ms :: artifacts dl 2ms
---------------------------------------------------------------------
| | modules || artifacts |
| conf | number| search|dwnlded|evicted|| number|dwnlded|
---------------------------------------------------------------------
| default | 3 | 0 | 0 | 0 || 3 | 0 |
---------------------------------------------------------------------
[echo] Ivy resolved: commons-csv-1.14.1.jar, commons-io-2.20.0.jar, commons-codec-1.19.0.jar
contrib:
[echo] station SF
[echo] station BOS
[echo] station HNL
all:
BUILD SUCCESSFUL
Total time: 0 seconds
The Props antlib is an example of a library that has no tasks. Its definitions are PropertyHelper delegates, that are plugged in
with the <propertyhelper> task, so the namespace is what makes it useful and a -lib is the usual way to load it:
<?xml version="1.0" encoding="UTF-8"?>
<project name="props" default="show" basedir="."
xmlns:props="antlib:org.apache.ant.props">
<propertyhelper>
<props:nested/>
</propertyhelper>
<property name="station" value="BOS"/>
<property name="name.BOS" value="Boston"/>
<target name="show">
<echo>${name.${station}}</echo>
</target>
</project>
$ ant -lib lib/ant-props-1.0.0.jar -f props.xml
Buildfile: /work/tidepool-antlib/props.xml
show:
[echo] Boston
BUILD SUCCESSFUL
Total time: 0 seconds
Nested property references such as ${name.${station}} do not work in core Ant. Without the <props:nested/> evaluator, Ant
refuses the <propertyhelper> as empty; with it, the inner reference is expanded first and the outer one then finds
name.BOS.
Source: Apache Ant Libraries and Apache AntUnit
Maven and Gradle
Neither tool has a namespace for tasks, because both have a different extension model:
| Maven | Gradle | |
|---|---|---|
How a library of tasks is added |
a plug-in with a version in the POM or in |
a plug-in in |
Name clashes |
a goal is always addressed as |
task names live in the project; registering a second task with an existing name fails the build |
Version of the library |
part of the POM |
part of the build script and the version catalog |
The Ant way of getting a library, a JAR in a directory that the launcher scans or a -lib, has neither versions nor repositories;
the Ivy and Maven Resolver Ant Tasks pages show the two ways to add them
(Ivy Overview and
Maven Resolver Ant Tasks). In the other direction,
a Gradle build calls Ant tasks through its ant object, described on
Ant Integration. The equivalence of concepts is in
Comparing Ant, Maven & Gradle.
Where older material is outdated
-
Books and web pages from before Ant 1.6 declare every task of a library with its own
<taskdef>, or with a properties resource, and no namespace. The mechanism described here (descriptors, theuriattribute andantlib:URIs) is what the Apache libraries use. -
Ant-Contrib examples with
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>define the names globally and rely on a JAR inANT_HOME/libor aclasspath; the antlib form shown above is the one the manual recommends. Most of the library is superseded byimport,macrodef,localand theif:andunless:attributes, covered on Targets & Extension Points. -
The manual page for 1.10.18 still says that the requirement that an
antlib:resource be on the default class path "may be removed in future versions"; it has not been removed, so a JAR that is found by namespace must be on Ant’s own class path. -
Material that says to copy every JAR into
ANT_HOME/libpredates-liband~/.ant/lib; changing the installation is no longer the first choice. -
Pre-1.6 build files with colons in custom task names (
<my:task>) break on current Ant, where the prefix has to be declared. -
Antlibs that were .NET or Visual SourceSafe tools are retired; see the retired-antlibs page rather than old tutorials.
References
-
Apache Ant manual: Antlib
-
Apache Ant manual: XML Namespace Support
-
Apache Ant manual: Taskdef task
-
Apache Ant manual: Typedef task
-
Apache Ant manual: Running Ant, library directories
-
Apache Ant manual: Built-in properties
-
Apache Ant manual: Installing Ant, optional tasks
-
Apache Ant Libraries: Ant Libraries
-
Apache Ant Libraries: Retired Ant Libraries
-
Apache AntUnit: AntUnit
-
Apache Ant: External Tools and Tasks