Pluggable JDKs

Last revised 11:45 Friday October 19, 2001

Work item: pluggable JDKs

Related work item: "Support for dealing with class files generated by external Java compilers like javac and jikes from an Ant script."

Related issue: remote builds

Other IDEs can claim that when Sun or IBM releases a new JDK, a developer can just "plug it in" to their IDE. We would like Eclipse to be similarly flexible, and be able to make a similar claim.

In practice, what does this mean? There are several different aspects.

  1. The ablility to run Java programs with the JDK's JRE.
  2. The ablility to compile Java source code against the JDK's class libraries.
  3. The ablility to compile Java source code with the JDK's javac compiler.
  4. The ablility to debug Java programs with the JDK's JDPA and JVM.
  5. The ablility to browse the JDK's class library API javadoc (or perhaps other release doc).
  6. The ablility to run the JDK's utility programs like javap, javadoc, javah.
We will take the first four as the most important ones for Eclipse to address, and look at each in turn.

Pluggable JREs

This is supported in Eclipse 1.0.

The org.eclipse.jdt.launching plug-in provides pluggable support ("vmInstallTypes" extension point) for describing installed Java2-style Java runtime environments and launching particular configurations of a Java virtual machine.

JDT defines a workbench preference ("Installed Java Runtime Environments") so that the user can create, remove, and edit JRE definitions (i.e., instances of the known VM installed types). The user chooses which one of the JRE definitions is the default.

JDT also defines a JRE property for each Java project to control which JRE is used to run programs in that project. By default, each project shares the workspace-wide default. The user can elect to specify a JRE for that project, which overrides the workspace-wide default.

Pluggable JDK class libraries

This is supported in Eclipse 1.0.

JDT Core provides a reserved build classpath variable, named "JRE_LIB", which gets bound to the JAR library (and associated source code ZIP) of the current workspace-wide default JRE (e.g., "D:\jdk1.4\jre\lib\rt.jar" with source in "D:\jdk1.4\src.zip"). By default, a classpath entry is included on the build classpath of a newly created project. This library would ordinarily supply the compile-time definitions of the standard class libraries used when browsing and building a Java project.

The client that is not satisfied with this variable is free to remove the classpath entry from the build classpath and replace it with something else. The client could declare their own build classpath variable, bind it to a suitable value, and include that on the build classpath instead (For instance, VAME/WSDD declares a classpath variable named "IVJ_HOME" and references  various class libraries relative to it; e.g., "IVJ_HOME/lib/jclmax.jar".) Or they could just hard-wire a library entry for a particular JRE library.

While the basic mechanism is reasonable, it is unfortunate that it is tied so tightly to the default JRE. It might be more convenient if selecting a different workspace-wide default JRE definition would prompt the user to change the JRE_LIB classpath variable as well.

Paralleling the workbench JRE mechanism, we could consider allowing the user to specify classpath variable bindings at the project level that override the workspace-wide default. This would allow the user to change the binding to affect just that project. Something similar can already be achieved by using distinctly-named classpath variables for each project (e.g., "P1_JRE_LIB" for project P1's "JRE_LIB"). So it's unclear whether any interesting new usecases would be supported by this.

Pluggable Java compilers

Java compilers can differ along many axes: In the simple world of the command line compiler, it's easy to use whatever Java compiler you choose to use. The command lines are substantially the same, and the overt compiler behavior of translating .java source files to .class files is utterly standard.

In additional to the basic compiler functionality, there are usually a number of IDE features that also need to be "language aware" (to some extent), including:

The language aware features require compiler infrastructure (e.g., a scanner).

The standard Sun Java compiler has no official APIs; the compiler infrastructure is not available outside the compiler. This means that Java IDEs have no choice but to reimplement whatever compiler infrastructure they might need. Without standard Java compiler APIs, no Java IDE can be truely pluggable in these regards. The best that a Java IDE can do in the circumstances is to use a pluggable Java compiler for its basic compiler functionality.

In Eclipse 1.0, the IDE's basic Java compiler functionality is provided by the built-in Eclipse compiler. What would it take to make this part pluggable?

In Eclipse, the basic Java compiler functionality is provided through the Java builder. The Java builder is activated when its build method is called. This happens when (a) an explicit Build commands requested by the user, (b) the workspace performs an auto build, or (c) some plug-in instigated a build programmatically.

So the first idea is that the Java builder's build method should invoke a pluggable Java compiler to do a build.

Calling a pluggable javac from within the Java builder

For a full build, this is clearly doable. The source folders mentioned on the build classpath can be walked to identify all Java source files. The corresponding class files in the output folder are deleted, and Java problem markers are removed. The names of these source files are then passed to javac as the ones to compile (large file sets perhaps broken up into reasonable sized batches); the classpath passed is computed from the project's build classpath; the output folder is passed as the target for the generated class files. The compiler will generate class files into the target folder and print text error messages to its output stream. Depending on how "standard" the format of the output stream was, the Java builder might be able to analyze the stream of text error messages and convert these into Java problem markers associated with the offending source files (the complete stream could also be saved and made available to user through some other mechanism). Otherwise the net result is close to that of running the Eclipse compiler. One other difference is that the Java builder would not be able to produce anything resembling its current internal built state (i.e., no dependency graph).

For an incremental build, it is impossible to do anything more than a cursory job without proper dependency information. The Java builder is passed a resource delta for the project showing which source files have changed. The delta would also show that the build classpath had changed (the Java builder could easily remember some classpaths between builds).

How to do an incremental build:

The compiler is called to recompile the identified list of source files. The Java builder might be able to analyze the -verbose output stream to discover which source files were actually compiled and update their Java problem markers.

This kind of simple-minded incremental build handles many simple cases (e.g., changing the body of a method, fixing javadoc comments, reformatting). The results would usually be less satisfactory when the principal structure of class is changed because any dependent source files do not get recompiled, which may lead to incompatible sets of binaries class files. The developer would need to be educated about when to be asking for a full build. Many will already be familiar with these rules from using other Java IDEs. With a Java compiler that does not produce dependency information, it is hard for an IDE with pluggable Java compilers to do any better.

Autobuild is just an incremental build that is triggered automatically. Note that the user may find it intolerable to run with autobuild enabled if the overhead for invoking the pluggable compiler is high (which it is likely to be if a separate JVM would need to be launched).

The conclusion is that this is feasible, although autobuilding may be intolerable. As long as the pluggable Java compiler was very javac-like in terms of command line options and format of generated error messages, it should be possible to use it to build a Java project.

Calling an Ant script instead of the Java builder

An even more flexible approach would be to allow a Java project to be configured with a generic Ant-based incremental project builder instead of the standard Java builder. The Ant-based builder is described in a separate 2.0 Platform Core feature proposal.

All of the above considerations would still apply; the only real difference is that everything is implemented in Ant terms.

Pluggable JDPA Debuggers

Eclipse reimplements the JPDA debugger front end; it does not use the JDI implementation supplied by Sun. Even if it did use Sun JDI, it still would be work for the Eclipse debugger to capitalize on any new debugger functionality thereby introduced. So the debugger front end is upgradeable, but not pluggable.

The JDPA debugger back end is logically part of the Java runtime environment, and ships with the IBM and Sun J2SE JDKs since 1.3. So this part is already pluggable.