This page is very out of date

Below are some notes about makefile dependencies for Java files.


  • Java Dependencies
  • Do Nothing
  • -depend
  • javac -depend vs. javac
  • JavaMemberDepend
  • JavaMake
  • JavaDepend
  • JavaSoft Comment
  • Jikes
  • JavaDeps
  • ziplock
  • depfind

  • Java Dependencies

    The problem is that a given .java file is likely to have dependencies on other .java files in different packages. If the .java file in the other package changes we would like the local file to be recompiled automatically.

    Bidirectional dependencies should be avoided. If two packages are dependent upon each other, it makes it hard to determine which package to compile first. Below are the possibilities

  • Remove the dependency
  • Combine the two packages into one package
  • Move the dependency into a third package, which will probably be a subpackage of one of the packages.
  • Hack the build structure so that both files are passed to javac at the same time.
  • A subpackage is a package that is beneath a parent package in the directory hierarchy. For example ptolemy.kernel.util is a subpackage of ptolemy.kernel. The makefiles are structured so that we run make in the subdirectories first so in general, it is best if parent packages depend on their subpackages.

    Below are several possible solutions

    Do Nothing

    If we don't have a dependency system, then running javac will compile files that are directly depended on and missing or out-of-date (see the javac manpage).

    Another alternative is to run javac *.java in each directory. The problem is that javac *.java takes a few minutes to complete, which is painful if we are trying to compile just one file.


    The javac man page says
              Causes recompilation of class files on which the source
              files given as command line arguments
              recursively depend. Without this option, only files that are
              directly depended on and missing or
              out-of-date will be recompiled. Recompilation does not
              extend to missing or out-of-date files
              only depended on by already up-to-date class files. 
    The Java Programmer's Faq has a question about dependencies, but it is not much help:
    7. (Sect. 3) I'm working on a project with lots of classes and I use the
         JDK. A recompile from scratch takes forever when I do it a class at a
         time. How do I recompile everything?
         [*] The first way is
              javac *.java
         Another way is
              javac -depend
         where "" is a class "at the tip of the iceberg", i.e. that
         depends on (uses) all the other classes. Typically, this may be your
         main class. However, "-depend" is known to be buggy and cannot be
         relied upon. It also doesn't issue compile commands in parallel to make
         use of multi-processor systems.
         Without the "-depend" option, the standard "javac files" doesn't look
         beyond the immediately adjacent dependencies to find classes lower down
         the hierarchy where the source has changed.
         The -depend options searches recursively for depending classes and
         recompiles it. This option doesn't help when you have dynamically
         loaded classes whose names cannot be determined by the compiler from
         the dependency graph. E.g. you use something like
         The author of the code using those classes should make sure that those
         classes are mentioned in a Makefile.
    As a test, I compiled (a class from the Ptolemy II system) 3 times without -depend, and got times of 3.31, 3.29 and 3.20 seconds.

    When I compiled the same file with -depend, I got times of 17.30, 16.46 and 16.40 seconds

    Obviously, this is not very scientific, but it is also obvious that -depend slows things down by 4 or 5 times.

    As a test, I rebuilt my Ptolemy II tree without -depend and it took 11 minutes. This number is not exact, but it is a damn sight faster than the usual 45 minutes :-)


    In JDK1.1, the -xdepend option will print out dependencies. However, this option is gone in JDK 1.2.


    In JDK1.2fcs, -depend is now -Xdepend
    cxh@carson 35% /opt/jdk1.2fcs/bin/javac -X
      -Xdepend         Recursively search for more recent source files to recompile
      -Xstdout         Send messages to System.out
      -Xverbosepath    Describe how paths and standard extensions were searched
      -J Pass argument to the java interpreter
    The -X and -J options are non-standard and subject to change without notice.
    I wonder why javac from jdk1.2-beta3 does't have the -depend option
    anymore, it was renamed to -Xdepend.
    Is this because it is beta, or is sun working on a new make system?
     ** From: kriff:
    Replied: Fri Dec 04 11:16:22 PST 1998
    The change is meant to reflect the fact that not all java compilers
    accept the -depend option. Sun is trying to standardize the command
    line options used by Java compilers so that Java tools can easily
    invoke them no matter who created them. Some switches (like
    -classpath) must be supported by any compiler, however other
    non-standard options may be available. Non-standard options will now
    always start with an 'X' to indicate that they are not available
    everywhere. The behavior of -depend is unchanged.

    javac -depend vs. javac

    To illustrate the difference between javac -depend and regular javac, we have three classes, and The constructor of A calls the constructor of B, which in turn calls the constructor of C

    cxh@carson 194% ls
    cxh@carson 195% more *.java |cat
    public class A {
        public A() {
            B b;
            b = new B();
        public static void main(String args[]) {
            A a = new A();
    public class B {
        public B() {
            C c;
            c = new C();
    public class C {
        public C() {
            System.out.println("C() cough"); 
    If we touch the .java files and run javac -verbose, then we can see that all three files get compiled:
    cxh@carson 196% setenv CLASSPATH .
    cxh@carson 197% touch
    cxh@carson 198% javac -verbose
    [parsed in 319 ms]
    [loaded /usr/java1.1/lib/ in 62 ms]
    [checking class A]
    [parsed ./ in 2 ms]
    [loaded /usr/java1.1/lib/ in 21 ms]
    [loaded /usr/java1.1/lib/ in 15 ms]
    [loaded /usr/java1.1/lib/ in 29 ms]
    [loaded /usr/java1.1/lib/ in 2 ms]
    [loaded /usr/java1.1/lib/ in 3 ms]
    [loaded /usr/java1.1/lib/ in 3 ms]
    [wrote A.class]
    [checking class B]
    [parsed ./ in 2 ms]
    [wrote ./B.class]
    [checking class C]
    [wrote ./C.class]
    [done in 1653 ms]
    cxh@carson 199% 
    If we run javac -verbose again, then only A.class gets generated. This is because B.class exists and is up to date.
    cxh@carson 199% javac -verbose
    [parsed in 335 ms]
    [loaded /usr/java1.1/lib/ in 61 ms]
    [checking class A]
    [loaded ./B.class in 4 ms]
    [loaded /usr/java1.1/lib/ in 19 ms]
    [loaded /usr/java1.1/lib/ in 15 ms]
    [loaded /usr/java1.1/lib/ in 30 ms]
    [loaded /usr/java1.1/lib/ in 2 ms]
    [loaded /usr/java1.1/lib/ in 3 ms]
    [loaded /usr/java1.1/lib/ in 3 ms]
    [wrote A.class]
    [done in 1620 ms]
    cxh@carson 200% 
    If we touch, or remove C.class then java -verbose will not recompile
    cxh@carson 200% touch
    cxh@carson 201% javac -verbose
    [parsed in 326 ms]
    [loaded /usr/java1.1/lib/ in 64 ms]
    [checking class A]
    [loaded ./B.class in 4 ms]
    [loaded /usr/java1.1/lib/ in 20 ms]
    [loaded /usr/java1.1/lib/ in 16 ms]
    [loaded /usr/java1.1/lib/ in 30 ms]
    [loaded /usr/java1.1/lib/ in 1 ms]
    [loaded /usr/java1.1/lib/ in 4 ms]
    [loaded /usr/java1.1/lib/ in 3 ms]
    [wrote A.class]
    [done in 1597 ms]
    cxh@carson 202% rm C.class
    cxh@carson 203% javac -verbose
    [parsed in 318 ms]
    [loaded /usr/java1.1/lib/ in 61 ms]
    [checking class A]
    [loaded ./B.class in 4 ms]
    [loaded /usr/java1.1/lib/ in 19 ms]
    [loaded /usr/java1.1/lib/ in 15 ms]
    [loaded /usr/java1.1/lib/ in 29 ms]
    [loaded /usr/java1.1/lib/ in 2 ms]
    [loaded /usr/java1.1/lib/ in 3 ms]
    [loaded /usr/java1.1/lib/ in 3 ms]
    [wrote A.class]
    [done in 1578 ms]
    cxh@carson 204% 
    If we touch, then java -verbose will recompile and then go on to recompile because depends on it
    cxh@carson 204% touch
    cxh@carson 205% javac -verbose
    [parsed in 329 ms]
    [loaded /usr/java1.1/lib/ in 62 ms]
    [checking class A]
    [parsed ./ in 3 ms]
    [loaded /usr/java1.1/lib/ in 21 ms]
    [loaded /usr/java1.1/lib/ in 16 ms]
    [loaded /usr/java1.1/lib/ in 30 ms]
    [loaded /usr/java1.1/lib/ in 2 ms]
    [loaded /usr/java1.1/lib/ in 3 ms]
    [loaded /usr/java1.1/lib/ in 3 ms]
    [wrote A.class]
    [checking class B]
    [parsed ./ in 3 ms]
    [wrote ./B.class]
    [checking class C]
    [wrote ./C.class]
    [done in 1732 ms]
    cxh@carson 206% 
    Now, if we touch and use the -depend option, (i.e. java -verbose -depend, then gets recompiled. Note that this is different than the behaviour we saw above with java -verbose
    cxh@carson 206% touch
    cxh@carson 207% javac -verbose -depend
    [parsed in 317 ms]
    [loaded /usr/java1.1/lib/ in 61 ms]
    [checking class A]
    [loaded ./B.class in 6 ms]
    [parsed ./ in 3 ms]
    [loaded /usr/java1.1/lib/ in 20 ms]
    [loaded /usr/java1.1/lib/ in 16 ms]
    [loaded /usr/java1.1/lib/ in 30 ms]
    [loaded /usr/java1.1/lib/ in 2 ms]
    [loaded /usr/java1.1/lib/ in 4 ms]
    [loaded /usr/java1.1/lib/ in 3 ms]
    [wrote A.class]
    [loaded /usr/java1.1/lib/ in 26 ms]
    [loaded /usr/java1.1/lib/ in 2 ms]
    [loaded /usr/java1.1/lib/ in 2 ms]
    [loaded /usr/java1.1/lib/ in 14 ms]
    [loaded /usr/java1.1/lib/ in 3 ms]
    [loaded /usr/java1.1/lib/ in 17 ms]
    [loaded /usr/java1.1/lib/ in 8 ms]
    [checking class B]
    [parsed ./ in 2 ms]
    [wrote ./B.class]
    [checking class C]
    [wrote ./C.class]
    Output truncated to save space -cxh

    To see the difference between javac -depend and regular javac in Ptolemy II, run the C-shell commands below:

    setenv CLASSPATH ../..
    cd $PTII/ptolemy; make clean
    cd $PTII/ptolemy/actor
    javac -verbose >& /tmp/nodepend1
    # Process the output to get rid of the timing info
    awk '{print $1, $2}' /tmp/nodepend1 | sort > /tmp/nodepend2
    cd $PTII/ptolemy; make clean
    cd $PTII/ptolemy/actor
    javac -verbose -depend >& /tmp/depend1
    # Process the output to get rid of the timing info
    awk '{print $1, $2}' /tmp/depend1 | sort > /tmp/depend2
    # Do a diff
    diff /tmp/nodepend2 /tmp/depend2
    For example, javac -depend compiles ptolemy/graph/DirectedAcyclicGraph but javac without -depend does not. The reason is that data/TypeLattice includes a private method
    private static DirectedAcyclicGraph _setup()
    and a static variable:
    private static DirectedAcyclicGraph _typeLattice = _setup();
    TypeLattice is compiled by both compilation methods.

    In this case, java -depend would protect us against problems in DirectedAcyclicGraph, such as having missing methods



    The JavaMemberDepend application, which is part of the Sun CDC, see:

    1. download
    2. cd cdcfoundation/src/share/javavm/jcc
      javac -classpath ".;../test"
    3. java -classpath ".;../test" JavaMemberDepend -classpath d:/tmp/ptII/ptolemy/copernicus/java/cg/OrthogonalCom/tst -loadClass -showAll

    JavaMake is java dependency tool written in Java that uses javac to manage a database of file dependencies


    JavaDepend is a Java dependency generator by Warren Pfeffer <>

    However, the JavaDepend home page is dead.

    Jamie Marconi <> was kind enough to send me a copy ( Jamie Marconi is thinking of setting up a JavaDepend web page.

    (Local users can view the unzipped JavaDepend distribution at ~ptII/devel/JavaDepend).

    Java Generic Library

    JavaDepend uses Java Generic Library (JGL) version 3.1.0, which is available from

    Local users can view the JGL installation at ~ptII/devel/jgl3.1.0.

    The JGL license says

    Licensee may not distribute in any form of electronic or printed
    communication the materials within or otherwise related to JGL
    that bear the ObjectSpace copyright, including but not limited
    to the source code, documentation, help files, examples, and
    benchmarks, without prior written consent from ObjectSpace,
    Inc. Send any requests for limited distribution rights to 
    The Licensee may distribute binaries (.class files) derived from
    or contained within JGL ("Binaries") provided that: 
    1) The Binaries are not integrated, bundled, combined, or
    otherwise associated with a Java development environment or
    Java development tool; and
    2) The Binaries are not a documented part of any distribution
    Below are a few questions about JGL:
  • Is Ptolemy II a Java development environment?
  • It looks like we could not distribute source code for JGL? We could just try shipping the class files?
  • Perhaps we should update this to use the JDK1.2 collections package? It looks like JavaDepnd uses jgl.HashMap and jgl.HashSet only.
  • How JavaDepend works

    JavaDepend is a program that will generate a makefile that can be included in the makefile in the directory. The alternative to this approach is to use a makedepend approach and create a makefile that is based on a make.template but has the dependency rules tacked on to the end of the file.

    One interesting thing about JavaDepend is that .java files are dependent on .class files instead of being dependent on .java files. I'm not sure why this is, but javac apparently reads .class files, and only compiles .java files if they are out of date with regard to the .class files

    Local use

    For an example see: ~ptII/devel/JavaDepend/examples/1/Makefile

    To use JavaDepend, I edited and added

    # Rules for using JavaDepend
    JGL_HOME =	/users/ptII/devel/jgl3.1.0
    JD_HOME =	/users/ptII/devel/JavaDepend
    JGL_CLS = $(JGL_HOME)/lib/jgl3.1.0.jar
    JD_CLS = $(JD_HOME)/
    	CLASSPATH=$(CLASSPATH):$(JDCLASSPATH) $(JAVA) -Drules=$(ROOT)/mk/ -Dmakestream=$@ -Dfiles=" $(JSRCS) "
    I also commented out the .SUFFIXES rule and set it to null
    #.SUFFIXES: .class .java

    Problems with JavaDepend

  • The original author cannot be found anywhere. We have the source though, so we could in theory distribute the source or binaries. Jamie Marconi may set up a JavaDepend website.
  • JavaDepend is under GNU Copyleft, which includes the onerous
        b) You must cause any work that you distribute or publish, that in
        whole or in part contains or is derived from the Program or any
        part thereof, to be licensed as a whole at no charge to all third
        parties under the terms of this License.
  • If we run JavaDepend in the ptolemy/kernel directory, and the .class files in ptolemy/kernel/util do not exist, then JavaDepend creates a file includes text like:
    ComponentEntity.class : \
    		Entity.class \
    		CompositeEntity.class \
    		/usr/java1.1/lib/ \
    		Port.class \
    	rm -f `basename $< .java`.class
    # WARNING: [, 75] Cannot resolve dependency for possible type Workspace.class, so none created
    # WARNING: [, 94] Cannot resolve dependency for possible type IllegalActionException.class, so none created
    # WARNING: [, 94] Cannot resolve dependency for possible type NameDuplicationException.class, so none created
    # WARNING: [, 122] Cannot resolve dependency for possible type Nameable.class, so none created
    I think this is a short coming in JavaDepend, since it looks like it is depending on the presence of the .class files in the subdirectory. It should be able to look for the .java file instead

    The workaround here is to create the .class files in the subdirectory before creating the file in the current directory. This is sort of lame.

    One side effect of this workaround is that since GNU make automatically builds, if we run make clean, then the .class files get built and then we remove them.

    This workaround fails for files like ptolemy/kernel/util/test/PtestWorkspace, which depend on a class in the parent directory. We get:

    make[2]: *** No rule to make target `../../../../ptolemy/kernel/util/PtolemyThread.class', needed by `PtestWorkspace.class'.  Stop.
    make[2]: Leaving directory `/export/carson/carson2/cxh/ptII/ptolemy/kernel/util/test'
    make[1]: *** No rule to make target `../../../ptolemy/kernel/CompositeEntity.class', needed by `TopologyEvent.class'.  Stop.
    make[1]: Leaving directory `/export/carson/carson2/cxh/ptII/ptolemy/kernel/event'
    One solution would be to hack in rules that would cd to the appropriate directory and run make there. This could cause problems with two packages that are dependent on each other.
  • JavaDepend creates a file which depends on the JDK zip file
    If the user has a different JDK, then they will need to regenerate
    Will this work properly with JDK1.2, which uses lib/tools.jar instead of lib/
  • Since the build system has dependencies on .class files instead of .java files, it takes several runs of make to completely build the system. If a .class file has other files that depend on it, then each time the .class file is built, the other files will be rebuilt as well.
  • Before is created, we get warnings like:
    ../../../../mk/ No such file or directory
    One workaround is to add a '-' before the include
    However, I think the leading dash will only work with GNU make. An alternative is to use
    but this fails with Solaris /usr/ccs/bin/make
  • The build system does not work with Solaris /usr/ccs/bin/make
    cxh@carson 34% make NamedObj.class
    make: Warning: Infinite loop: Target `Nameable.class' depends on itself
    make: Warning: Infinite loop: Target `Nameable.class' depends on itself
    rm -f `basename  .java`.class
    CLASSPATH="../../.." /usr/java1.1/bin/javac -g 
    use: javac [-g][-O][-debug][-depend][-nowarn][-verbose][-classpath path][-nowrite][-deprecation][-d dir][-J]
    *** Error code 1
    make: Fatal error: Command failed for target `InvalidStateException.class'
    The problem is that the rule uses $<, which Solaris /usr/ccs/bin/make is failing to interpret correctly
  • JavaSoft Comment says:
    Javac make(1) dependency generation
    Category           general:compiler
    Reported Against:  1.2beta4 
    Release Fixed:  
    State:             In progress, request for enhancement
                         Submit Date  Sep 22, 1998 
           Like all good C/C++ compilers, javac should offer
           a command line option for generating makefile
           dependencies. This should be very easy to do for
           the compiler and would be a very cool feature for
           all of us guys managing big projects with the help
           of make(1).
           Thanks, tom.
           (Review ID: 37053)
           Hi Tom,
           It is not straightforward to write make rules for general java programs.
           I wanted to add a feature like this but ran into troubles...
           In C or C++, your interfaces are put into separate header files. In
           make you add dependencies on the header files to represent a
           dependency on an external api. In java, you have no separate header
           files. If class Foo and Bar depend on each others external api's, then
           you have two .java files which depend on each other. This is not
           something that happens with .c files. Also, compile-time constants are
           mandated by the JLS to be inlined. Class Foo may inline a compile
           time constant from Bar and class Bar may also inline a compile time
           constant from Foo. (In the C/C++ world, this is akin to having two
           header files both depend on each other's #defines -- doesn't work.) If
           both and have been modified, then you may need
           to compile both simultaneously (same command line) in order to get
           the correct results. I don't know of a straightforward rule system for
           make which can build up these cliques of sources which must be
           compiled simultaneously and issue them in the same command.
           I realize this is a short explanation. I think that a make-like tool for
           java would be very valuable for java programmers. I believe that it
           will probably have to be integrated into the compiler to get it to be
           robustly correct.
           xxxxx@xxxxx 1998-09-28


    Jikes is a compiler that reads in .java files and generates .class files. It is a replacement for javac, and does not include the Java runtime (

    Jikes has a +M option which will generate Java dependencies.

    Local users can view information about the local Jikes installation


  • active website
  • original website
  • ziplock

    Ziplock is "a free program to find static class dependencies by reading class files". from - Local Copy

    To generate a list of classes:

    java -classpath ~cxh/public_html/java/javadepend:$PTII ZipLock

    To create a jar file cd $PTII; jar -cf orthocom.jar `java -classpath ~cxh/public_html/java/javadepend:$PTII ZipLock`


    (Last updated: 1/03) says:

    The goal of this project is to have a tool, or suite of tools, that can extract class dependencies from compiled Java code. The tools can get all the necessary information out of the .class files.

    Last updated: 01/02/07
    My Toplevel Java Page

    cxh at eecs
    Copyright © 1998, The Regents of the University of California. All rights reserved.