Actually, Ant does handle the dependency example you present below.

Use the optional <depend> task.  The following build.xml will recompile both
A.java and B.java in your step 4 below.

<project name="tmp" default="all" basedir=".">
  <property name="build" value="./build/" />
  <target name="all" >
    <mkdir dir="${build}" />
    <depend srcdir="${basedir}"
      destdir="${build}"
      cache="depcache"/>
    <javac srcdir="${basedir}"
      depend="on"
      includes="A.java, B.java"
      destdir="${build}"
      classpath=".;${build}"
      debug="on"
      />
  </target>
</project>

If you're interested in reading the docs, I've included the text from the
Ant manual for the depend task.  Thanks for bringing this to my attention--I
had indeed missed it.

Depend
A task to manage Java class file dependencies. 
Description
The depend task works by determining which classes are out of date with
respect to their source and then removing the class files of any other
classes which depend on the out-of-date classes. 

To determine the class dependencies, the depend task analyses the class
files of all class files passed to it. Depend does not parse your source
code in any way but relies upon the class references encoded into the class
files by the compiler. This is generally faster than parsing the Java
source.

To learn more about how this information is obtained from the class files,
please refer to the Java Virtual Machine Specification 

Since a class' dependencies only change when the class itself changes, the
depend task is able to cache dependency information. Only those class files
which have changed will have their dependency information re-analysed. Note
that if you change a class' dependencies by changing the source, it will be
recompiled anyway. You can examine the dependency files created to
understand the dependencies of your classes. Please do not rely, however, on
the format of the information, as it may change in a later release. 

Once depend discovers all of the class dependencies, it "inverts" this
relation to determine, for each class, which other classes are dependent
upon it. This "affects" list is used to discover which classes are
invalidated by the out of date class. The class files of the invalidated
classes are removed, triggering the compilation of the affected classes. 

The depend task supports an attribute, "closure" which controls whether
depend will only consider direct class-class relationships or whether it
will also consider transitive, indirect relationships. For example, say
there are three classes, A, which depends on B, which in-turn depend on C.
Now say that class C is out of date. Without closure, only class B would be
removed by depend. With closure set, class A would also be removed. Normally
direct relationships are sufficient - it is unusual for a class to depend on
another without having a direct relationship. With closure set, you will
notice that depend typically removes far more class files. 

Performance
The performance of the depend task is dependent on a number of factors such
as class relationship complexity and how many class files are out of date.
The following tests have been run when build Ant itself, on the author's
machine using JDK1.3 

Building Ant from clean using Javac 11 seconds 
Building Ant from clean using Jikes 5 seconds 
Running <depend> when up-to-date and no cache 4 seconds (Depend takes 2
seconds) 
Running <depend> when up-to-date and with a cache 2 seconds (Depend takes 1
seconds) 

This involves compiling 177 files. The above figures are indicative only.
The decision about whether it is cheaper to just recompile all classes or to
use the depend task will depend on the size of your project and how
interrelated your classes are. 

Limitations
There are some dependencies which depend will not detect. 

If the Java compiler optimizes away a class relationship, there can be a
source dependency without a class dependency. 
Non public classes cause two problems. Firstly depend cannot relate the
class file to a source file. In the future this may be addressed using the
source file attribute in the classfile. Secondly, neither depend nor the
compiler tasks can detect when a non public class is missing. Inner classes
are handled by the depend task. 
Parameters
Attribute Description Required 
srcDir This is the directory where the source exists. depend will examine
this to determine which classes. If you use multiple source directories you
can pass this a path of source directories. Yes 
destDir This is the root directory of the class files which will be
analysed. If this is not present, the srcdir is used. No 
cache This is a directory in which depend can store and retrieve dependency
information. If this is not present, depend will not use a cache  No 
closure This attribute controls whether depend only removes classes which
directly depend on out of date classes. If this is set to true, depend will
traverse the class dependency graph deleting all affected classes. Defaults
to false No 

Examples
    <depend srcdir="${java.dir}"
    destdir="${build.classes}"
    cache="depcache"
    closure="yes"/>
In this example classes in the ${build.classes} directory will be removed if
they depend on out-of-date classes. Classes are considered out of date with
respect to the source in the ${java.dir} directory using the same mechanism
as the javac task. In this instance the depend task caches its dependency
information in the depcache directory. 


----------------------------------------------------------------------------
----

Copyright © 2000,2001 Apache Software Foundation. All rights Reserved.

> -----Original Message-----
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]]
> Sent: Tuesday, March 20, 2001 11:38 PM
> To: Denis, Ronald J (Ronald)** CTR **
> Cc: JDE Mailing List
> Subject: Re: PROPOSAL: New Java Build Feature 
> 
> 
> 
> In message 
> <[EMAIL PROTECTED]
> m>, "Denis, Ronald J (Ronald)** CTR **" writes:
> : I too use ant for my builds.  It does not compile 
> : every file every time.  However, admittedly there have 
> : been times when compile errors occur which only go away 
> : upon a full rebuild.  This doesn't happen often but does 
> : happen often enough that its annoying.
> 
> It's quite clear why and when this happens.  Ant does an "up to date"
> check on the source files you hand to its "javac" task (which 
> could also
> be handled by jikes) and passes the compiler a list of .java 
> files that
> are older than their corresponding .class files.  This is why Ant will
> always rebuild classes that are not organized in a directory structure
> that mirrors the package hierarchy.
> 
> It's also why Ant cannot handle the following case unless you 
> do a full,
> clean build:
> 
> 1. write the following classes
> class A {
>   void foo() { }
> }
> 
> class B extends A {
>   void bar() { foo(); }
> }
> 
> 2. build and run: everything is fine.
> 
> 3. now change A as follows:
> 
> class A {
>   void foo(int i) { }
> }
> 
> 4. build with Ant and only A gets rebuilt (as it is the only 
> out-of-date
> source file)
> 
> 5. run and you will get a java.lang.NoSuchMethodError
> 
> Conclusions:
> 
> Ant is not the panacea that some, charmingly (alarmingly?) naive users
> claim that it is.  It has a couple of advantages over make: 
> 
> 1. it does not fire up multiple VMs to do a build;
> 2. it is hard to write non-portable build files (with make 
> the inverse is true);
> 3. it does not require much from users - no shell, sed, awk 
> wizardry required;
> 
> With that said, Ant does not offer any fundamental advantage 
> over make in
> terms of dependency analysis.  Using timestamps to recompile 
> class files
> is simply not enough in java, as the example above makes clear.
> 
> Eric
> 

Reply via email to