converting javac to be a modular app
Jonathan Gibbons
jonathan.gibbons at oracle.com
Mon May 24 19:25:15 PDT 2010
On the face of it, it ought to be easy to change javac to be executed
with module mode instead of legacy mode. You might think it is
sufficient to simply remove the reference to -J-Xmode:legacy in the
appropriate line of jdk/make/launchers/Makefile, as in the following diff:
> $ hg diff -U 0
> diff -r 7e1d7e037819 make/launchers/Makefile
> --- a/make/launchers/Makefile Mon May 24 14:27:31 2010 -0700
> +++ b/make/launchers/Makefile Mon May 24 16:43:30 2010 -0700
> @@ -64,1 +64,1 @@
> -$(call make-launcher, javac, com.sun.tools.javac.Main, -J-Xmode:legacy, )
> +$(call make-launcher, javac, com.sun.tools.javac.Main, , )
If only it were that simple ...
To understand the real problem, you need to understand javac's role in
building JDK. For a full description of the build process, see Kelly's
blog, "Anatomy of the JDK Build":
http://blogs.sun.com/kto/entry/anatomy_of_the_jdk_build
Here's a quick summary:
1. Build the latest javac with the BOOTJAVA javac to create a hybrid
javac (call it hybrid-1) that can run on BOOTJAVA but which can compile
JDK7 code.
2. Use hybrid-1 javac to compile all the langtools repository for
delivery into the final bundles.
3. Use hybrid-1 javac to compile the corba, jaxws, jaxp, repositories
4. Build the jdk repository using hybrid-1 javac, and including all the
classes compiled in steps 1, 2 and 3, to produce candidate JDK bundles.
Many developers stop at this point. But up to this point, the JDK
created in step 4 has not been tested, so a common step is to perform
the build with SKIP_BOOT_CYCLE=false. If that variable is set, the build
will repeat steps 1-4 using the JDK from step 4 (call it "interim JDK")
as the setting for BOOTJAVA.
5. Build the latest javac with the interim JDK javac to create a hybrid
javac (call it hybrid-2) that can run on the interim JDK and which can
compile JDK7 code.
6. Use hybrid-2 javac to compile all the langtools repository for
delivery into the final bundles.
7. Use hybrid-2 javac to compile the corba, jaxws, jaxp, repositories
8. Build the jdk repository using hybrid-2 javac, and including all the
classes compiled in steps 1, 2 and 3, to produce final JDK bundles.
So where's the problem? Not surprisingly, it's in those hybrid-1 and
hybrid-2 versions of javac. Currently, we synthesize those hybrid
versions of javac by using -J-Xbootclasspath/p: to override the location
of the javac classes being used by the underlying JDK. As long as we
build javac to execute in legacy mode, that works just fine. But once we
switch javac to use module mode, we lose the ability to use
-J-Xbootclasspath/p:. Instead, we have to use the new "-L library"
option, which replaces "-Xbootclasspath/p:classes". What does that entail?
Currently, there is no explicit artifact that is identifiable as
"hybrid-1" or "hybrid-2" javac. Instead, the langtools part of the build
delivers a set of classes, to be used as part of a hybrid javac, and
each downstream repository in the forest uses those classes with
-J-Xbootclasspath to synthesize the hybrid javac. So, there are two sets
of changes to be made.
- The langtools repository must determine if it has been given a legacy
JDK or a modular JDK for its bootstrap. If it has been given a modular
JDK, it needs to create a module library to be used for downstream
compilations.
- All downstream builds need to determine if they have been given a
legacy JDK or a modular JDK for their bootstrap, and so should
synthesize their hybrid javac using "-Xbootclasspath/p:classes" or "-L
library" (or rather, "-J-Xbootclasspath/p:classes" or "-J-L -Jlibrary".
Mild uugh!)
Note that we cannot hard-code the change to use "-L library" through the
life of JDK7. In other words, for as long as we need to start the build
using a legacy JDK, such as JDK 6, the build must be "bimodal", able to
work with both a legacy JDK, or a modular JDK such as may just have been
built.
The changes to have the langtools repository build a module library are
essentially as described here:
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2010-May/000960.html
However, the changes described there concerned a developer build of
javac; the changes need to be replicated to apply to the bootstrap
builds as well. This corresponds to langtools having settings for two
different versions of JDK -- one to build with, and one to execute what
it builds: the langtools build needs to be prepared for each setting to
be given either a legacy JDK or a modular JDK.
The changes to have each downstream repository determine whether to use
-Xbootclasspath or L are not particularly difficult. One minor
complication to take into account is that some repositories use Ant
instead of "make". Another complication is whether or not this needs to
be a synchronized build change across all repositories. One way to avoid
that would be a two phase approach, such that we first change all
repositories to explicitly force the use of legacy mode for javac, then
we can change the default mode for javac, then finally update the
repositories to work with the default.
That's almost it. You'd think.
If only it were that simple ...
Who spotted that sometimes developers perform "partial builds" and don't
necessarily use and build a copy of the langtools repository? Instead,
you can set ALT_JDK_IMPORT_PATH to a recent build of JDK. So yes, we
need to make the build work in that case as well. And, for now, that is
left as an exercise for the reader.
More information about the jigsaw-dev
mailing list