JDK-4014784 : An option to compile entire packages at once
  • Type: Enhancement
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 1.1
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: solaris_2.5
  • CPU: generic
  • Submitted: 1996-11-14
  • Updated: 2000-01-11
  • Resolved: 2000-01-11
Related Reports
Duplicate :  
Relates :  
Description
Currently, "javac" and "make" do not go well together, and as a result,
large projects such as JDK, sqe-tools and the like have substantial 
problems doing sensible builds.

The problem is that there is no easy and quick way to ensure that a package is
up to date.  With C/C++ you just check that each of the object files is up to
date w.r.t. to the corresponding source file AND and imported dependencies.
"javac" has the -depend switch but it is arguably overkill because it arguably
goes too far down the dependency tree.  The alternative is to pass all the
files for a package to javac, which causes them all to be compiled, which
means that any make actions depending on the class files are guaranteed to
happen because the class files get written whether they need to or not.

I would like to propose that a new switch be added to javac to ask it
to ensure that a package is compiled up to date.  I have a trial implementation
if you want to see it; it works as follows:

- new switch   -updatepackage PKGNAME

The switch causes the compiler to load all the class files for the package,
by enumerating pkg.getBinaryFiles() and loading the corresponding class
declarations.   At the same time, it builds a table of the source files
of the corresponding class files, by rummaging around inside the ClassDefinition
to get the source, and by passing the result to pkg.getSourceFile().
The compiler then scans the set of source files for the package, by
enumerating pkg.getSourceFiles(). Any source files that have not already
been found while scanning the class files, are put on the standard list
of source files to be compiled (Vector v in javac.Main) and compiled in the
usual way.

The net effect is that for those files that have already been compiled,
the compiler simply checks to see if the files are up to date.   In
addition, any sources for which there are no pre-existing class files
are also compiled.

That much works pretty well.  However, it doesn't quite go far enough.
The compiler currently never checks binary dependencies. It either checks
no dependencies or it checks all files for source dependencies.  If
the -updatepackage switch were available, a better interim solution
would be possible. In particular, it would be good to check dependencies
within the current package: build and use the dependency graph for 
ClassDeclarations within the package being built, and if a dependency is outside 
the package being built, simply check the lastModified time of the 
dependency .class file.

With this proposal, one could typically build a directory by a command of the
form:
	javac -d CLASSDIR   -updatepackage javasoft.sqe.harness
or similar.

The experiments I have done so far show that this is not surprisingly
much faster than explicitly compiling all the java files in the directory,
especially when no files actually need to be rebuilt.

Comments
SUGGESTED FIX Here is some of the code of the experiment I did. This is a block of code to go before the comment // Parse all input files in javac.Main. The code assumes that a variable `updatePackageString' contains the value of the proposed new -updatepackage option if it is given. It also assumes that the source file vector `v' is empty. If the `if' statement executes, it loads the class declarations for any binary classes and puts in `v' the set of source files that are not referenced by any class files, so that these source files can be parsed by the standard code that this segment precedes. //---------------------------------------------------------------------------- if (updatePackageString != null) { Package pkg = new Package(classPath, Identifier.lookup(updatePackageString)); Hashtable srcClassFiles = new Hashtable(); for (Enumeration e = pkg.getBinaryFiles(); e.hasMoreElements(); ) { ClassFile f = (ClassFile)e.nextElement(); String fn = f.getName(); String name = updatePackageString + "." + fn.substring(0, fn.length() - 6); Identifier id = Identifier.lookup(name); ClassDeclaration decl = env.getClassDeclaration(id); ClassDefinition def = decl.getClassDefinition(env); Object src = def.getSource(); ClassFile cf = (src instanceof ClassFile ? (ClassFile)src : pkg.getSourceFile((String)src)); if (cf != null) { srcClassFiles.put(cf.getPath(), cf); } } for (Enumeration e = pkg.getSourceFiles(); e.hasMoreElements(); ) { ClassFile cf = (ClassFile)e.nextElement(); if (!srcClassFiles.containsKey(cf.getPath())) { v.addElement(cf.getPath()); } } } //----------------------------------------------------------------------------
11-06-2004

PUBLIC COMMENTS A new option isfor the compiler is proposed that would allow faster incremental compilation of a specified package.
10-06-2004

EVALUATION If we do something like this, it should be consistent with whatever mechanism we decide on for compiling directly into jar or zip files. david.stoutamire@Eng 1997-12-05 The proposed mechanism is "front end" processing to determine a list of files which need to be compiled, based on the source files and class files found (via the compiler's standard mechanisms). Once the list of files has been determined, they are passed almost exactly as though they were given explicitly on the command line. Thus there should be no need for the above concern: the compiler will compile files exactly as though the files were given on the command line. jonathan.gibbons@Eng 1997-12-05 I agree that this functionality, in some form, would be very useful. We are looking forward to potentially extending and rationalizing javac's command line behavior in the future. todd.turnidge@Eng 1998-04-09 I have created a new bug for the proposed rationalization of the command line behavior (4304048), and closed this bug as a duplicate. william.maddox@Eng 2000-01-11
09-04-1998