bootstrapping javac and JDK 7

Jonathan Gibbons Jonathan.Gibbons at Sun.COM
Thu Nov 5 18:45:28 PST 2009


Although I'm not in a position to push any bits yet, I've just reached a 
notable milestone for being able to compile langtools against (selected) 
JDK7 API.

Here's the problem we are dealing with:  we have to be able to compile 
(most of) langtools using the boot JDK. (Currently, JDK 6)   This is 
because we will be using the langtools javac to compile the rest of the 
JDK 7 source code, which means the we don't have a JDK 7 binary to run 
on or even compile against at this point.  Until recently, the boot JDK 
was sufficient for all of langtools, and life was (relatively) simple.

However, now there are new features in JDK 7 we would like to be able to 
use if the compiler is running on JDK 7. So far, there are two such 
features: new NIO, and the module system. My blog entry [1] describes 
how javac can provide a file manager based on the new NIO API. This 
means that a JSR 199 client can wrap any new NIO FileSystem with a 
JavaFileManager for use by javac and related tools.  And separately, 
javac must also be able to interact with the module system when it is 
available. (i.e. when javac is actually running on a fully built JDK 7.)

So, how do we get to build javac such that it can use JDK 7 API, which 
for the most part should be allowed to use JDK 7 language features?

For a start, we have to restrict the use of JDK 7 features within javac 
as much as possible.  That means limiting the use of JDK 7 features to a 
restricted set of javac classes, such that javac can function 
sufficiently well when those classes are not available (i.e. during 
bootstrapping.) For all the other classes, they can be built as before, 
using the boot JDK. The problem is how to compile the remaining classes 
that depend on JDK 7 API.

There are two solutions, each with their respective advantages and 
disadvantages.

The first approach is to restructure the JDK build, so that we can build 
the bootstrap compiler first, then the other repos, like corba, jaxp, 
jaxws, and jdk, and then go back to langtools a second time to build the 
remaining classes, now that we have class files for the rest of JDK that 
we can compile against. This approach is conceptually simple, but would 
be complicated to achieve in practice.

The second approach is to retain the structure of the current JDK build, 
and to compile javac against the source files of the as-yet-uncompiled 
JDK. Here's how this works: at least in theory.   Use the boot JDK to 
compile a bootstrap compiler that can run on the boot JDK. This 
bootstrap compiler must not use any JDK 7 features.  Even though the 
bootstrap compiler must run on the boot JDK, it will be able to read and 
compile JDK 7 code. So we can use it to compile a new copy of javac, 
including those parts that depend on JDK 7 API.  To do that we need to 
put the JDK 7 source code on the source path for the compilation.   Or 
so you would think.   There are two major problems.  The first is that 
when javac reads files from the source path, it will end up trying to 
compile the transitive closure of all the dependencies of those files. 
So even though javac may initially depend on just the new NIO API and 
the module system API, you eventually end up trying to compile files in 
AWT (really!) because of the dependencies that exist. As bad as that is, 
the second problem is worse. At the time we want to compile javac, not 
all of the JDK source code is available.  Some may be platform specific, 
and some will need to be generated automatically by rules inside the JDK 
makefiles that have yet to run.

The problem is that by placing the JDK source tree on the source path, 
we end up having to analyze the implementation details of those classes, 
and from there to all their dependencies. The solution is not to use the 
source files directly, but to compile against stubs files that contain 
the publicly visible details of the class, as needed for the 
compilation.  It would be a maintenance nightmare to create and manually 
maintain the necessary stub files, so I have written a utility which 
strips out enough of the details of the classes we need, such they can 
used to compile langtools. We don't need stub files for all of JDK, just 
for those parts of JDK which we need to be able to use from javac, plus, 
of course, enough of their dependencies to be able to compile the stubs 
themselves.

As a result, langtools can now be built in the following ways:

-- if you don't supply a path for JDK 7 classes, it will build langtools 
excluding any classes that depend on JDK 7 API.  This is done 
automatically to build a bootstrap compiler.

-- if you supply a path for the main JDK 7 source code (i.e. 
jdk/src/share/classes), it will create those stubs necessary to build 
langtools, and then build all of langtools.  This would be the normal 
mode used as part of a full JDK build. The list of stubs is specified 
explicitly, but maintaining a list of the files for which stubs are 
required is a lot simpler than maintaining the stubs themselves.

-- if you supply a path for a previously built version of JDK (i.e. 
jre/lib/rt.jar), it will simply compile langtools in conjunction with 
that jar file. This saves having to create and compile the stub files, 
and is for the convenience of langtools developers who don't need to do 
a full JDK build using the boot JDK.



--------------------
[1] http://blogs.sun.com/jjg/entry/jsr_199_meets_jsr_203





More information about the jigsaw-dev mailing list