RFR: timestamp oddities -sourcepath vs zip/jar

Martin Buchholz martinrb at google.com
Wed Sep 25 15:08:56 PDT 2013


Jonathan,

I think we're in complete agreement.

For jsr166 development, we have a work around.  IIRC It used to be that we
needed to do a "ant clean" after we updated our JDK or else some of our
sources would fail to be recompiled, but I fiddled with ant/javac for a
while until the problem went away, but I'm fuzzy on the details (probably
-Xprefer:source)


On Thu, Sep 26, 2013 at 1:42 AM, Jonathan Gibbons <
jonathan.gibbons at oracle.com> wrote:

>  Martin,
>
> Your proposal is phrased somewhat better than the earlier one, but
> realistically, it is too late to do anything in this area for JDK 8.
>
> What I disliked about the earlier proposal was the special casing of
> zip/jar files which was just plain wrong. Here, you are implicitly
> suggesting a better rule, which is based more on the logical paths involved
> (i.e. sourcepath, classpath, bootclasspath) than the nature of the file.
> Effectively, you are saying that in javac's game of rock-paper-scissors,
> sourcepath beats bootclasspath, no matter what the timestamps say.  This
> behavior could be embodied in a new value for the -Xprefer option, leaving
> the existing behaviors unchanged.
>
> -- Jon
>
>
> On 09/25/2013 01:23 PM, Martin Buchholz wrote:
>
> Jonathan,
>
>  The current behavior is logical, but it is not what users intuitively
> expect.  There is a problem for anyone who tries to build JDK boot classes
> outside of the normal JDK build process.  E.g. we do this with jsr166.  We
> want to build against an unmodified JDK (rt.jar) but to generate new class
> files for "our" sources.
>
>  I think that most users in this situation would want the behavior of:
> - files in the sourcepath get compiled to the destdir
> - when looking up a type, if it's in the sourcepath, check if it's also in
> destdir with a newer timestamp; if not, (re)compile it.  If in neither,
> consult rt.jar.
>
>  (that may be hard to do compatibly and without introducing complexity)
>
>
>
> On Tue, Sep 24, 2013 at 7:29 AM, Jonathan Gibbons <
> jonathan.gibbons at oracle.com> wrote:
>
>>  Fredrik,
>>
>> It is a misconfiguration to have classes on the sourcepath, with
>> corresponding classes in the compiled classes directory, AND in rt.jar.  If
>> you're compiling the core JDK classes, you should make sure that rt.jar is
>> not on the classpath or bootclasspath.  For example, you should put sources
>> on the source path and then set the bootclasspath to the compiled classes
>> directory.  This is how the "old build" worked, successfully, for many
>> years.
>>
>> Although the situation you are describing is specific to the JDK build,
>> the general recommendation still applies: don't put a zip file on the class
>> path containing compiled classes for any sources you are compiling.
>>
>> -- Jon
>>
>>
>> On 09/23/2013 10:40 PM, Fredrik Öhrström wrote:
>>
>>  It is a serious bug that command line javac can behave in two different
>> ways when given completely static and predictable source code.
>>  Especially since the change in behavior comes from timestamps inside
>> rt.jar, which a normal user has no control of, nor can easily see.
>>
>>  The intent of the timestamp compare is to know if the class file is out
>> of date in respect to the source file.
>>  Thus if the source has been changed then recompile and write the class.
>> Now the class is up to date.
>> However a class inside a jar file and >especially< inside rt.jar is
>> completely outside of this loop and
>> should only be used when there is no class file in bin, nor any source
>> file in src. Only the timestamp
>> of classes in bin, that can actually be affected by recompilation should
>> matter.
>>
>>  As I said, there are several ways to fix this. Another way would be to
>> exclude rt.jar from the comparison.
>> -Xprefer:source is not good enough because it will recompile everything
>> indiscriminately on the sourcepath
>> even though the class has already been compiled and exists in bin.
>>
>>  Thus preferredFileObject is faulty by design and has managed to stay
>> that way since
>> not may people have exercised -sourcepath, especially not when building
>> classes that
>> also exist in rt.jar.
>>
>>  //Fredrik
>>
>>
>>
>>  2013/9/23 Jonathan Gibbons <jonathan.gibbons at oracle.com>
>>
>>>  On 09/22/2013 06:41 AM, Fredrik Öhrström wrote:
>>>
>>>> The preferredFileObject test in ClassReader.java does cause confusion
>>>> when timestamps inside zip files are too new.
>>>>
>>>> Lets say that you have in src/alfa/A.java
>>>> public class A { void a() { java.lang.Object.foo = 42; } }
>>>> and in src/java/lang/Object.java
>>>> public class Object { public static int foo; }
>>>>
>>>> You can now always compile using the following command:
>>>> javac -d bin src/alfa/A.java src/java/lang/Object.java
>>>>
>>>> But you can only >>sometimes<< compile using the following command:
>>>> javac -d bin -sourcepath src src/alfa/A.java
>>>>
>>>> When it fails, javac has picked up java.lang.Object from rt.jar and
>>>> not from the sourcepath. This happens when the timestamp inside rt.jar
>>>> is newer than the source file.
>>>>
>>>> The net result is that when compiling the OpenJDK with --enable-sjavac
>>>> everything works fine, then you upgrade your jdk and the compilation
>>>> fails in very weird ways. And will fail until you touch all your source
>>>> files.
>>>>
>>>> There are several ways to fix this, but all require some thought.
>>>> However a simple fix, would be to ignore the timestamps of class files
>>>> inside zip/jars because they probably do not mean anything important....
>>>>
>>>> Thus in preferredFileObject, if b is a ZipFileIndexFileObject, then use
>>>> the source!
>>>> protected JavaFileObject preferredFileObject(JavaFileObject a,
>>>>                                            JavaFileObject b) {
>>>>     if (preferSource)
>>>>         return (a.getKind() == JavaFileObject.Kind.SOURCE) ? a : b;
>>>>     else {
>>>>         if (b instanceof
>>>> com.sun.tools.javac.file.ZipFileIndexArchive.ZipFileIndexFileObject) {
>>>>             return a;
>>>>         }
>>>>         long adate = a.getLastModified();
>>>>         long bdate = b.getLastModified();
>>>>         // 6449326: policy for bad lastModifiedTime in ClassReader
>>>>         //assert adate >= 0 && bdate >= 0;
>>>>         return (adate > bdate) ? a : b;
>>>>     }
>>>> }
>>>>
>>>> What do you think?
>>>>
>>>> //Fredrik
>>>>
>>>>
>>>>
>>>>
>>>>
>>>  Fredrik,
>>>
>>> There is no guarantee that items in zip files are presented to javac in
>>> the class you test for, so the instanceof test is highly suspicious and
>>> likely to be a source of inconsistent behavior.  For example, what happens
>>> if someone using using javac via the CompilerAPI (JSR 199) and provides
>>> their own custom file manager?
>>>
>>> If you want to make sure you're compiling source code, use
>>> -Xprefer:source.  Or, keep your timestamps straight.
>>>
>>> -- Jon
>>>
>>
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20130925/d6002cae/attachment-0001.html 


More information about the compiler-dev mailing list