I have an existing Ant project and would like to speed up the build process by avoiding re-building components that are already up to date.
Ant permits you to specify that one target depends on another, but by default every prerequisite is always rebuilt, even if it is already up to date. (This is a key difference between Ant and make. By default, make only re-builds a target when needed -- that is, if some prerequisite is newer.)
<uptodate property="mytarget.uptodate"> // in set.mytarget.uptodate task
...
</uptodate>
<!-- The prerequisites are executed before the "unless" is checked. -->
<target name="mytarget" depends="set.mytarget.uptodate" unless="mytarget.uptodate">
...
</target>
To make Ant re-build prerequisites only if necessary, there seem to be two general approaches within Ant.
The first approach is to use the uptodate
task to set a property. Then,
your task can test the property and build only if the property is (not)
set.
<uptodate property="mytarget.uptodate"> // in set.mytarget.uptodate task
...
</uptodate>
<!-- The prerequisites are executed before the "unless" is checked. -->
<target name="mytarget" depends="set.mytarget.uptodate" unless="mytarget.uptodate">
...
</target>
An alternate first approach is to use the outofdate
task from ant contrib.
It's nicer in that it is just one target without a separate property being
defined; by contrast, outofdate requires separate targets to set and to
test the property.
The second approach is to create a <fileset>
using the <modified>
selector. It calculates MD5 hashes for files and selects files whose MD5
differs from earlier stored values. It's optional to set
<param name="cache.cachefile" value="cache.properties"/>
inside the selector; it defaults to "cache.properties". Here is an example that copies all files from src to dest whose content has changed:
<copy todir="dest">
<fileset dir="src">
<modified/>
</fileset>
</copy>
Neither of these is very satisfactory, since it requires me to write Ant code for a process (avoiding re-building) that ought to be automatic.
There is also Ivy, but I can't tell from its documentation whether it provides this feature. The key use case in the Ivy documentation seems to be downloading subprojects from the Internet rather than avoiding wasted work by staging the parts of a single project. Maven provides similar functionality, with the same use case highlighted in its documentation. (Moving an existing non-trivila project to Maven is said to be a nightmare; by contrast, starting greenfield development with Maven is more palatable.)
Is there a better way?