Explicitly empty sourcepath regression
Pepper Lebeck-Jobe
pepper at gradle.com
Fri Jun 16 07:34:14 UTC 2017
On Fri, Jun 16, 2017 at 2:49 PM Alan Bateman <Alan.Bateman at oracle.com>
wrote:
> On 16/06/2017 05:07, Pepper Lebeck-Jobe wrote:
> > I'll start with a question, and then give an opinion.
> >
> > *Question*
> > Why must the source files which make up a module be on the source path
> for
> > the module to be compiled?
> >
> > *Opinion*
> > Build tools, especially Gradle, attempt to make reproducible builds a
> > reality. One thing these tools offer is fine-grained control over the set
> > of java files which will be passed to javac for compilation.
> Historically,
> > we have even explicitly set the `-sourcepath` to be empty to tell the
> > compiler not to look for source files on the classpath or in the current
> > working directory. Combining this with an exact specification of which
> java
> > files should be compiled supports a few important use cases:
> >
> > 1. You can exclude experimental sources (not yet ready to compile)
> > easily to unblock local development without fear that they will
> break the
> > build.
> > 2. You can set up build logic to dynamically include or exclude
> specific
> > files without having to copy those files around to various
> directories
> > which are or are not on the source path, so that you can produce
> different
> > variations of a library from the original sources.
> >
> > We feel that having to isolate the files which make up a module into
> > directories on the `-sourcepath` would limit the flexibility of the build
> > system, and, possibly hurt reproducibility of the builds.
> >
> > *Reproduction*
> > In case anyone on the list doesn't understand what I mean when I say that
> > module source files are required to be on the source path, I've created a
> > tiny GitHub repo <
> https://github.com/eljobe/modules/blob/master/README.md>,
> > with instructions on reproducing what I'm seeing.
> >
> Jon or Jan might want to comment on this but there does appear to be a
> corner case in javac when none of the paths specified to -sourcepath
> exist and the source to compile includes a module-info.java.
>
> That said, the javac command looks fishy and not clear why -cp and
> -sourcepath are specified when compiling the module. Are these just
> inherited from existing build code that hasn't been updated for modules?
>
Not exactly. Let me take them each in turn.
The reason I explicitly "unset CLASSPATH" and "-cp ''" in the
"bin/worksJ9.sh" script is because the documentation says that when
"-sourcepath" isn't specified the class path will be searched for source
files and that when "-cp" is not specified, the default value for the
classpath is the current working directory. We consider it too "fast and
loose" to coincidentally include source files which are in the current
working directory and want to ensure that the only files seen by the
compiler are the ones we explicitly pass it by fully qualified filesystem
paths. That way, those complete set of reachable source files have to be
included among the specified inputs to the task we are running, and we can
use that specified set to calculate whether or not there have been changes
in those files since the previous run of the build and avoid calling javac
at all if we know none of the inputs have changed. I'll put it another way.
Suppose, we didn't explicitly empty the sourcepath, and there was a source
file in the current working directory (say, "Parent.java") which was needed
for compiling one of the sources we explicitly passed to javac (say,
"Child.java"). The first time we run the build, it would succeed. But,
then, suppose someone changes "Parent.java" and runs the build again. Since
only "Child.java" is explicitly known to us, and we know that the source
file has not changed since we last ran the task, we will incorrectly skip
running the task again. I say, "incorrectly" because the result would be a
successful build, but the user would be confused as to why the changes to
"Parent.java" weren't being picked up by the build.
I only left "-cp ''" in "bin/failsJ9.sh" to show that I didn't change
anything between the two invocations except for explicitly setting the
"-sourcepath" to be empty. In fact, given the documentation that when
"-sourcepath" is not set the classpath will be searched for sources, I
actually don't understand why the same failure isn't happening without
explicitly setting "-sourcepath". Whatever rule is being violated by not
having the source files on the source path when compiling the module,
should logically be violated as well when the source path == the classpath
as both are set to the same empty path string.
> Have you looked at using -implicit:none rather than setting using empty
> paths?
>
If I understand the documentation of that option correctly, then it doesn't
alter the scenario described above. Essentially, it would change whether or
not "Parent.class" was generated during the original execution of the
"javac" command, but we still wouldn't know to watch "Parent.java" for
changes so we could know to recompile.
> -Alan
>
Thanks for the timely response.
More information about the jigsaw-dev
mailing list