Ant Targets & Extension Points
|
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 and was run on JDK 26 on 2026-10-16. Every build file and every console
output below comes from a real run of the Ant 1.10.18 distribution, in a scratch copy of the tidepool-model library
(one record, Height, and one JUnit Jupiter test); the project directory is shortened to /work/tidepool-model in the
output, and the closing Total time line is omitted. Features newer than Ant 1.9 name their release in the text.
A target is Ant’s unit of ordering. The build file lists tasks inside targets, and the targets name the other targets
they need, so a build is a graph that Ant walks from the targets named on the command line. The
Build File Structure page introduced
<project>, <target> and tasks; this page covers the target element completely, the extension points added in Ant 1.8
that make shared build logic extensible, and the conditional features that sit on targets and on single tasks. The
other half of the control flow, the <condition> task and friends, is on
Conditions & Control Flow;
properties, which most conditions test, are on Properties.
What a target is
A target is a named container of tasks and data types that cooperate to reach a desired state during the build, for
example "the classes are compiled" or "the distributable exists". A target can depend on other targets, and Ant makes
sure those have run before the target itself. That is the whole model: unlike Maven, there is no fixed lifecycle, and
unlike Gradle, there is no task graph computed from inputs and outputs. The author draws the graph by hand with
depends, and Ant sorts it. The ideas behind this are compared across the three tools on
Build Automation Fundamentals.
The attributes of <target> in Ant 1.10.18 are:
| Attribute | Meaning | Required |
|---|---|---|
|
the name of the target |
yes |
|
a comma-separated list of the targets this target depends on |
no |
|
the target runs only if this property is set (or the value evaluates to true) |
no |
|
the target runs only if this property is not set (or the value evaluates to false) |
no |
|
a one-line description, printed by |
no |
|
adds this target to the |
no |
|
what to do when |
no; allowed only together with |
Source: Ant manual: Targets
depends and the resolution order
Ant runs the targets in a depends list from left to right, but a target may already have run earlier because an
earlier target depends on it. The manual’s example is the clearest way to see it, so here it is as a runnable file:
<project name="order" default="D">
<target name="A"><echo>A</echo></target>
<target name="B" depends="A"><echo>B</echo></target>
<target name="C" depends="B"><echo>C</echo></target>
<target name="D" depends="C,B,A"><echo>D</echo></target>
</project>
The list of D reads C,B,A, and a quick reading suggests that C runs first, then B, then A. That is wrong,
because C depends on B and B depends on A:
$ ant -f order.xml
Buildfile: /work/tidepool-model/order.xml
A:
[echo] A
B:
[echo] B
C:
[echo] C
D:
[echo] D
BUILD SUCCESSFUL
Within the dependency chain of one target, each target runs only once, however many targets depend on it. A, B and
C are all dependencies of D, but each executed a single time, and Ant never repeated B and A when it came back to
the D list. The rule is a topological sort of the graph, with depends order as the tie-breaker. The corollary is
that the order of a depends list expresses nothing about dependencies between its members: if a target needs another
one to have run first, it must name it in its own depends.
Targets named on the command line are a different matter. The "once" rule holds inside the chain of one named target, and Ant resolves each name on the command line separately, as the next run shows (Ant 1.10.18; the manual does not describe this case):
$ ant -f order.xml B D
Buildfile: /work/tidepool-model/order.xml
A:
[echo] A
B:
[echo] B
A:
[echo] A
B:
[echo] B
C:
[echo] C
D:
[echo] D
BUILD SUCCESSFUL
A and B ran twice, once for B and once for the chain of D. Name a single entry point on the command line, or
build a single target that depends on the others, when a shared dependency should run once. The command-line options
are covered on Running Ant.
Two classic failures come from the graph itself. Naming a target that does not exist, and closing a cycle, both stop
the build before any task runs (the second file is cycle.xml, in which a depends on b and b depends on a):
$ ant -f order.xml nope
Buildfile: /work/tidepool-model/order.xml
BUILD FAILED
Target "nope" does not exist in the project "order".
$ ant -f cycle.xml
Buildfile: /work/tidepool-model/cycle.xml
BUILD FAILED
Circular dependency: a <- b <- a
A target name can be any string that is valid in the encoding of the XML file, including the empty string, a comma or a
space, but the manual asks you to avoid those because they are confusing on the command line and in IDEs and will not
be supported in future versions. Targets that begin with a hyphen, such as -prepare, are valid and are the idiom for
internal targets: Ant’s main class treats every argument that begins with a hyphen as one of its own options, so they
cannot be called from the command line (ant -prepare prints Unknown argument: -prepare followed by the usage text),
although IDEs usually can call them.
Source: Ant manual: Targets
The tidepool target graph
The running build for tidepool-model has two files. common.xml is the shared build logic, imported by each module
(the mechanism is on
Multi-File Builds: import, include & subant).
It defines init, an extension point named ready-to-compile, and the chain compile, test, jar and dist.
build.xml imports it and contributes one target of its own, generate-version, which writes a generated Version
class. The diagram shows the resulting graph; the extension point is drawn as a stadium.
The two files, shortened to the targets that matter here (the full common.xml also holds the property definitions,
the test class path and clean):
<project name="common" xmlns:if="ant:if">
<target name="init">
<tstamp/>
<echo>init: building ${ant.project.name} on ${DSTAMP}</echo>
<mkdir dir="${classes.dir}"/>
<mkdir dir="${gen.dir}"/>
</target>
<extension-point name="ready-to-compile" depends="init"
description="state reached when all sources exist"/>
<target name="compile" depends="ready-to-compile" description="compile main sources">
<echo>compile</echo>
<javac destdir="${classes.dir}" release="21" includeantruntime="false">
<src path="${src.dir}"/>
<src path="${gen.dir}"/>
</javac>
</target>
<target name="test" depends="compile" description="run the unit tests">
<!-- javac for the tests, then the JUnit console launcher via <java> -->
</target>
<target name="jar" depends="test" description="package the library">
<echo>jar</echo>
<jar destfile="${jar.file}" basedir="${classes.dir}"/>
</target>
<target name="dist" depends="jar" description="publish to build/repo (file repository)">
<echo>dist</echo>
<copy file="${jar.file}" todir="${build.dir}/repo"/>
</target>
</project>
<project name="tidepool-model" default="dist" basedir=".">
<import file="common.xml"/>
<target name="generate-version" extensionOf="ready-to-compile" depends="init"
description="write a generated Version class">
<echo>generate-version</echo>
<mkdir dir="${gen.dir}/io/tidepool/model"/>
<echo file="${gen.dir}/io/tidepool/model/Version.java">package io.tidepool.model;
public final class Version { public static final String VALUE = "1.0.0"; }
</echo>
</target>
</project>
Running ant clean dist names two targets, and the build file’s default is dist:
$ ant clean dist
Buildfile: /work/tidepool-model/build.xml
clean:
[delete] Deleting directory /work/tidepool-model/build
init:
[echo] init: building tidepool-model on 20261016
[mkdir] Created dir: /work/tidepool-model/build/classes
[mkdir] Created dir: /work/tidepool-model/build/generated
generate-version:
[echo] generate-version
[mkdir] Created dir: /work/tidepool-model/build/generated/io/tidepool/model
ready-to-compile:
compile:
[echo] compile
[javac] Compiling 2 source files to /work/tidepool-model/build/classes
test:
[mkdir] Created dir: /work/tidepool-model/build/test-classes
[javac] Compiling 1 source file to /work/tidepool-model/build/test-classes
[java]
[java] Test run finished after 24 ms
[java] [ 4 containers found ]
[java] [ 0 containers skipped ]
[java] [ 4 containers started ]
[java] [ 0 containers aborted ]
[java] [ 4 containers successful ]
[java] [ 0 containers failed ]
[java] [ 1 tests found ]
[java] [ 0 tests skipped ]
[java] [ 1 tests started ]
[java] [ 0 tests aborted ]
[java] [ 1 tests successful ]
[java] [ 0 tests failed ]
[java]
jar:
[echo] jar
[jar] Building jar: /work/tidepool-model/build/tidepool-model-1.0.0.jar
dist:
[echo] dist
[copy] Copying 1 file to /work/tidepool-model/build/repo
BUILD SUCCESSFUL
generate-version ran between init and ready-to-compile, so compile found the generated source in
build/generated ("Compiling 2 source files": Height and Version). The extension point itself did no work, which
is why its section of the output is empty.
Source: Ant manual: Extension-Points
if and unless on targets
The if and unless attributes of a target enable or disable that single target depending on a property. They let a
build adapt to the Java version, the operating system or a -D option. In the simplest form Ant only checks whether the
property is set, and its value does not matter:
<project name="cond" default="all">
<target name="all" depends="build-module-A, build-own-fake-module-A"/>
<target name="build-module-A" if="module-A-present">
<echo>using the real module A</echo>
</target>
<target name="build-own-fake-module-A" unless="module-A-present">
<echo>using a fake module A</echo>
</target>
</project>
Without the property the first target is skipped. With the property set to false, it still runs, because the
property is set:
$ ant -f cond.xml
Buildfile: /work/tidepool-model/cond.xml
build-module-A:
build-own-fake-module-A:
[echo] using a fake module A
all:
BUILD SUCCESSFUL
$ ant -f cond.xml -Dmodule-A-present=false
Buildfile: /work/tidepool-model/cond.xml
build-module-A:
[echo] using the real module A
build-own-fake-module-A:
all:
BUILD SUCCESSFUL
The rules, in the order they bite:
-
A skipped target still prints its name followed by an empty body, as above. It is skipped, not removed.
-
Only one property name may appear in an
iforunlessattribute. To combine several tests, compute the result in a helper target with<condition>and test the property it sets. -
If a target has both
dependsandif/unless, thedependslist runs first; the condition is evaluated only when the target is about to run and all its predecessors have finished. The attributes switch off the target they are attached to and never the targets it depends on. -
If neither attribute is present the target always runs.
-
The attribute value may be a property expansion that evaluates to true or false (the manual says "or something evaluating to true"); a value that is not a boolean is treated as a property name.
The expansion case is worth a run (true and yes enable the target, false does not), because an unset property leaves the literal text ${deploy.enabled} in place:
<project name="expand" default="deploy">
<target name="deploy" if="${deploy.enabled}">
<echo>deploying</echo>
</target>
</project>
Running it four times (the lines are the target part of each run) gives:
$ ant -f expand.xml
deploy:
$ ant -f expand.xml -Ddeploy.enabled=true
deploy:
[echo] deploying
$ ant -f expand.xml -Ddeploy.enabled=false
deploy:
$ ant -f expand.xml -Ddeploy.enabled=yes
deploy:
[echo] deploying
The manual’s idiom for several conditions uses a check target that sets the flag. Here the flag needs a jar and the
station data, and the example runs twice, first without data/stations.csv and then with it:
<project name="check" default="publish">
<target name="publish.check">
<condition property="publish.run">
<and>
<available file="build/tidepool-model-1.0.0.jar"/>
<available file="data/stations.csv"/>
</and>
</condition>
</target>
<target name="publish" depends="publish.check" if="publish.run">
<echo>jar and station data are present, publishing</echo>
</target>
</project>
$ ant -f check.xml
Buildfile: /work/tidepool-model/check.xml
publish.check:
publish:
BUILD SUCCESSFUL
$ mkdir data && echo 'id,name' > data/stations.csv
$ ant -f check.xml
Buildfile: /work/tidepool-model/check.xml
publish.check:
publish:
[echo] jar and station data are present, publishing
BUILD SUCCESSFUL
Source: Ant manual: Targets
Source: Ant manual: condition task
description, ant -p and the default target
The description attribute is more than a comment. ant -p (long form -projecthelp) lists the targets that have one,
so the descriptions are the public interface of the build file; targets without a description are considered internal.
-v or -d together with -p list the internal targets too, under "Other targets". The next file has a hyphenated
internal target, a helper without a description and a public target:
<project name="internal" default="release">
<target name="-prepare"><echo>prepare</echo></target>
<target name="check-tools"><echo>check</echo></target>
<target name="release" depends="-prepare, check-tools" description="make a release"><echo>release</echo></target>
</project>
$ ant -f internal.xml -p
Buildfile: /work/tidepool-model/internal.xml
Main targets:
release make a release
Default target: release
$ ant -f internal.xml -p -v
Apache Ant(TM) version 1.10.18 compiled on September 3 2026
Buildfile: /work/tidepool-model/internal.xml
Detected Java version: 26 in: /Library/Java/JavaVirtualMachines/jdk-26.jdk/Contents/Home
Detected OS: Mac OS X
parsing buildfile /work/tidepool-model/internal.xml with URI = file:/work/tidepool-model/internal.xml
Project base dir set to: /work/tidepool-model
Main targets:
release make a release
Other targets:
-prepare
check-tools
Default target: release
Run on the tidepool-model build.xml, ant -p lists the targets of the imported common.xml as well, including
the extension point and its description:
$ ant -p
Buildfile: /work/tidepool-model/build.xml
Main targets:
clean delete build output
compile compile main sources
dist publish to build/repo (file repository)
generate-version write a generated Version class
jar package the library
ready-to-compile state reached when all sources exist
test run the unit tests
Default target: dist
The default attribute of <project> names the target that runs when none is given on the command line. It is
optional. A build file without a default target and without a command-line target runs only the tasks that stand
directly under <project> (allowed since Ant 1.6.0 and handy for a <tstamp/>), and then reports success:
<project name="nodefault">
<tstamp/>
<echo>top-level task runs first, DSTAMP=${DSTAMP}</echo>
<target name="hello"><echo>hello</echo></target>
</project>
$ ant -f nodefault.xml
Buildfile: /work/tidepool-model/nodefault.xml
[echo] top-level task runs first, DSTAMP=20261016
BUILD SUCCESSFUL
$ ant -f nodefault.xml hello
Buildfile: /work/tidepool-model/nodefault.xml
[echo] top-level task runs first, DSTAMP=20261016
hello:
[echo] hello
BUILD SUCCESSFUL
The manual recommends putting <tstamp> in an initialization target, conventionally named init, on which every other
target depends and which comes first in their depends lists, as common.xml above does. Top-level tasks run before
any target, each time and for every invocation, which is why they should be limited to cheap set-up.
Source: Ant manual: Targets
Source: Ant manual: Command-line options
Extension points
An extension point is the answer to a design problem that existed before Ant 1.8: how can an imported build file leave a
slot where the importing file adds its own steps, without editing the shared file or overriding whole targets? Since
Ant 1.8.0 the <extension-point> element is a target with a name and a depends list but with no tasks. Its job is to
stand for a state the build must reach, and to collect the targets that contribute to that state.
Contributors join with the extensionOf attribute on their own target. The manual’s example puts a slot in front of
compile:
<target name="create-directory-layout">
...
</target>
<extension-point name="ready-to-compile"
depends="create-directory-layout"/>
<target name="compile" depends="ready-to-compile">
...
</target>
and a target in the main build file fills it:
<target name="generate-sources"
extensionOf="ready-to-compile">
...
</target>
Ant appends generate-sources to the extension point’s depends list, so it runs after the targets in the explicit
depends attribute of the extension point and before compile. Three details from the manual and the runs above:
-
If several targets add themselves to the same extension point, their relative order is not defined. Do not rely on the order of the contributions. If
generate-versionneedsinitfirst, it says so in its owndepends, as in the example, becauseextensionOfdoes not imply any ordering with respect to other targets. -
An extension point is an ordinary entry point. It can be named on the command line to build only up to that state, and it appears in
ant -pwhen it has adescription. In the tidepool build,ant ready-to-compilerunsinit,generate-versionand the empty extension point, and stops:$ ant ready-to-compile Buildfile: /work/tidepool-model/build.xml init: [echo] init: building tidepool-model on 20261016 generate-version: [echo] generate-version ready-to-compile: BUILD SUCCESSFUL -
The point of the construct is imported build files. A shared file declares the states (
ready-to-compile, and in a larger build alsoready-to-packageorready-to-publish) and each module’s own file adds targets that contribute.
The extension point is not limited to imported files. Within one file it behaves the same:
<project name="ext" default="ready">
<target name="one"><echo>one</echo></target>
<target name="two"><echo>two</echo></target>
<target name="three" depends="one"><echo>three</echo></target>
<extension-point name="ready" depends="one"/>
<target name="late" extensionOf="ready"><echo>late</echo></target>
<target name="late2" extensionOf="ready"><echo>late2</echo></target>
</project>
$ ant -f extonly.xml
Buildfile: /work/tidepool-model/extonly.xml
one:
[echo] one
late:
[echo] late
late2:
[echo] late2
ready:
BUILD SUCCESSFUL
late and late2 ran after one (the explicit depends), the unrelated targets two and three did not run, and
the extension point came last. The contribution order here happens to match the declaration order, but the manual
guarantees nothing about it.
Source: Ant manual: Extension-Points
onMissingExtensionPoint
A contributing target fails the build when the extension point it names does not exist. That is the safe default, since
a typo would otherwise silently drop the target from the build. Since Ant 1.8.2, onMissingExtensionPoint changes the
reaction to warn or ignore, which is how an optional contribution is written: a target that adds itself to an
extension point that exists in some of the files it may be combined with but not in all of them. The three values, with
the same target and an extension point that does not exist:
<project name="miss" default="extra">
<target name="extra" extensionOf="no-such-point" onMissingExtensionPoint="fail">
<echo>extra ran</echo>
</target>
</project>
$ ant -f miss.xml # onMissingExtensionPoint="fail", also the behavior when the attribute is absent
Buildfile: /work/tidepool-model/miss.xml
BUILD FAILED
can't add target extra to extension-point no-such-point because the extension-point is unknown.
$ ant -f miss.xml # onMissingExtensionPoint="warn"
Buildfile: /work/tidepool-model/miss.xml
Warning: can't add target extra to extension-point no-such-point because the extension-point is unknown.
extra:
[echo] extra ran
BUILD SUCCESSFUL
$ ant -f miss.xml # onMissingExtensionPoint="ignore"
Buildfile: /work/tidepool-model/miss.xml
extra:
[echo] extra ran
BUILD SUCCESSFUL
The attribute is allowed only together with extensionOf; the target still runs when it is requested directly, as the
extra runs above show, and in the warn and ignore cases it simply is not attached to anything.
Source: Ant manual: Targets
bindtargets
Sometimes the contributing target lives in a third file, or the shared file cannot be edited, and a bridge target would
be needed only to connect the two. The <bindtargets> task (since Ant 1.8.2) makes that bridge for you: it adds a list
of targets to the depends list of an extension point, but only in the project where it is written, so other projects
that import the same shared files are unaffected. The manual gives the equivalent:
<bindtargets targets="jar,javadoc" extensionPoint="dist"/>
is the same as
<target name="bind-to-dist" depends="jar,javadoc" extensionOf="dist"/>
The attributes are targets (a comma-separated list, required), extensionPoint (required) and
onMissingExtensionPoint (fail by default, with the same warn and ignore as above). It may be used only as a
top-level task, which keeps the dependency graph static and predictable as soon as all the files are loaded. A
build file that binds two documentation targets to the extension point of the shared common.xml:
<project name="bind" default="dist">
<import file="common.xml"/>
<target name="docs"><echo>docs: write the site</echo></target>
<target name="sources-jar" depends="init"><echo>sources-jar: package sources</echo></target>
<bindtargets targets="docs,sources-jar" extensionPoint="ready-to-compile"/>
</project>
$ ant -f bind.xml compile
Buildfile: /work/tidepool-model/bind.xml
init:
[echo] init: building bind on 20261016
[mkdir] Created dir: /work/tidepool-model/build/classes
[mkdir] Created dir: /work/tidepool-model/build/generated
docs:
[echo] docs: write the site
sources-jar:
[echo] sources-jar: package sources
ready-to-compile:
compile:
[echo] compile
[javac] Compiling 1 source file to /work/tidepool-model/build/classes
BUILD SUCCESSFUL
Putting the task inside a target fails at the moment that target runs, not while the file is parsed:
<project name="badbind" default="x">
<target name="x"><echo>x</echo></target>
<target name="t">
<bindtargets targets="x" extensionPoint="y"/>
</target>
</project>
$ ant -f badbind.xml t
Buildfile: /work/tidepool-model/badbind.xml
t:
BUILD FAILED
/work/tidepool-model/badbind.xml:4: bindtargets only allowed as a top-level task
Source: Ant manual: bindtargets task
if and unless on any task
The target-level if and unless act on a whole target. Since Ant 1.9.1 any task or nested element can carry
if and unless as well, through two special namespaces that are declared on the project:
xmlns:if="ant:if"
xmlns:unless="ant:unless"
The namespaces support three conditions, each usable in both directions: true (the value of the attribute evaluates
to true), blank (the value is null or empty) and set (the named property is set). So if:set, unless:set,
if:true, unless:true, if:blank and unless:blank exist as attributes. A file that uses all three kinds:
<project name="ns" default="show" xmlns:if="ant:if" xmlns:unless="ant:unless">
<target name="show">
<condition property="onmac"><os family="mac"/></condition>
<echo if:set="onmac">running on macOS</echo>
<echo unless:set="onmac">not running on macOS</echo>
<echo if:true="${verbose}">verbose is true</echo>
<echo unless:true="${verbose}">verbose is not true</echo>
<echo unless:blank="${who}">hello ${who}</echo>
<echo if:blank="${who}">nobody to greet</echo>
</target>
</project>
$ ant -f ns.xml
Buildfile: /work/tidepool-model/ns.xml
show:
[echo] running on macOS
[echo] verbose is not true
[echo] hello ${who}
BUILD SUCCESSFUL
$ ant -f ns.xml -Dverbose=true -Dwho=tide
Buildfile: /work/tidepool-model/ns.xml
show:
[echo] running on macOS
[echo] verbose is true
[echo] hello tide
BUILD SUCCESSFUL
The first run holds the classic trap of this feature: blank tests the value of the attribute, and an unset property
expands to its own text, ${who}, which is not blank. unless:blank="${who}" therefore ran and echoed hello ${who}
instead of skipping. Use if:set and unless:set with a property name to ask "was it defined", and use blank only
for values that are guaranteed to expand, for example a property given a default with <property name="who" value=""/>.
A build that must run on Ant releases older than 1.9.1 cannot use the namespaces. For checks that stop the build, see
Conditions & Control Flow.
Targets are not functions
The most frequent beginner mistake is to treat a target as a subroutine: to call it with arguments, to call it more than
once and to expect it to return. A target is a node in a graph, which is why the one-execution rule exists. Ant offers
<antcall>, which runs another target of the same file in a new project, and it is the trap, because it runs the
called target together with all of its dependencies again:
<project name="call" default="main">
<target name="init"><echo>init</echo></target>
<target name="greet" depends="init"><echo>greet ${who}</echo></target>
<target name="main" depends="init">
<antcall target="greet"><param name="who" value="tide"/></antcall>
<antcall target="greet"><param name="who" value="moon"/></antcall>
</target>
</project>
$ ant -f call.xml
Buildfile: /work/tidepool-model/call.xml
init:
[echo] init
main:
init:
[echo] init
greet:
[echo] greet tide
init:
[echo] init
greet:
[echo] greet moon
BUILD SUCCESSFUL
init ran three times: once for main and once for every <antcall>, since each call creates a new project and
re-evaluates the dependency chain of the called target. The properties and references set by the called target do not
persist back to the caller either, the <param> values override only inside the call, and a property defined on the
command line cannot be overridden by a <param>. The manual’s <antcall> page lists the attributes target,
inheritAll (default true) and inheritRefs (default false) and the nested <param>, <reference> and <propertyset>
elements.
The guidance that follows from this:
-
Use
dependsfor ordering and for steps that run once; useextension-pointandextensionOffor extensibility. -
Use
<macrodef>(Macros & Presets) for a reusable step with parameters and no dependency graph: it is the real counterpart of a function. -
Use
<ant>,<subant>and<import>when the unit of reuse is a build file (Multi-File Builds). -
Keep
<antcall>for the few cases where a target must run again with different properties, and expect its dependencies to run again.
Source: Ant manual: antcall task
The same ideas in Maven and Gradle
Ant’s explicit target graph has a counterpart in each of the other tools, but it is expressed differently:
| Idea | Ant | Maven | Gradle |
|---|---|---|---|
a step |
|
a plugin goal, bound to a lifecycle phase |
a task |
ordering |
|
the fixed order of the lifecycle phases |
|
run it once |
within one dependency chain |
each phase runs once per module |
each task runs at most once per build |
conditional step |
|
profiles, or the |
|
a slot others can fill |
|
a phase: any plugin can bind a goal to it |
a lifecycle task such as |
public targets |
|
lifecycle phases and plugin goals |
|
The Maven lifecycle is on Maven: Build Lifecycle and its profiles on Maven: Profiles. The Gradle task graph is on Gradle: Build Lifecycle and the task API on Gradle: Tasks. The comparison of all the concepts is in Comparing Ant, Maven & Gradle.
Source: Maven: Build lifecycle basics
Pitfalls and good practice
-
Do not assume the order inside a
dependslist means more than "left to right unless something already ran". Spell out real dependencies in each target. -
A skipped
iforunlesstarget still runs itsdepends. Put expensive work in the target, not in its dependencies. -
if="x"tests whetherxis set, not whether it is true.-Dx=falsestill turns it on. Useif="${x}"(a boolean expansion) when the value matters, and remember that an unset property leaves the text${x}in place. -
Name every public target and give it a
description; leave helpers undocumented, or start their names with a hyphen, so thatant -pshows the real interface. -
Keep
initfirst in thedependslist and never put work that changes the build state into top-level tasks. -
Prefer an
<extension-point>in shared files over overriding a target with the same name in an importing file: an extension point has an explicit contract and a safe failure mode when the name is wrong. -
bindtargetsis top-level only;antcallis only for the rare re-run, and re-runsdepends. -
A target name with a comma or a space is legal but will be rejected by some IDEs and will not be supported in the future.