Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 216684

Summary: [batch][compiler] ecj behaves differently than javac wrt -sourcepath and -classpath options
Product: [Eclipse Project] JDT Reporter: Olivier Lefevre <lefevrol>
Component: CoreAssignee: Stephan Herrmann <stephan.herrmann>
Status: CLOSED WORKSFORME QA Contact:
Severity: normal    
Priority: P3 CC: jerome_lanneluc, kent_johnson, Olivier_Thomann, philippe_mulet, stephan.herrmann
Version: 3.4   
Target Milestone: 4.15 M3   
Hardware: PC   
OS: Windows XP   
Whiteboard:
Attachments:
Description Flags
The script to run
none
Test case none

Description Olivier Lefevre CLA 2008-01-26 18:14:26 EST
Run the attached script: it will create a skeleton project and compile
Foo, then Bug3 which depends on Foo. Looking at the log you will see 
that when compiling Bug3 javac found and used the existing Foo.class:

   [loading d:\work\bugs\ecj\classes\pkg\Foo.class]

but that ecj, with the exact same arguments, recompiled it:

   [analyzing  d:\work\bugs\ecj\src\pkg\Foo.java - #2/2]
   [writing    pkg\Foo.class - #2]

I don't think this is correct behaviour and it is undesirable anyhow,
as it would seem to make separate compilation impossible. This is 
with the batch compiler, not using Eclipse.
Comment 1 Olivier Lefevre CLA 2008-01-26 18:15:10 EST
Created attachment 87954 [details]
The script to run
Comment 2 Kent Johnson CLA 2008-01-28 15:20:59 EST
This is a batch compiler issue not a JavaBuilder issue.

We may not be trusting a .class file created at the same time as a source file.
Comment 3 Olivier Lefevre CLA 2008-01-28 15:30:44 EST
Indeed: if one tries a bit later Foo is not recompiled. It
is impossible in this scenario for Foo.java and Foo.class 
to have been created at the exact same time, though.

NB: Just to be clear, all the bugs I reported are against 
ecj used as batch compiler.
Comment 4 Kent Johnson CLA 2008-01-28 15:41:04 EST
So the question becomes: should we trust .class files with the same timestamp as a source file?

If we do and the source file was changed a split second after the .class file was created, we would miss the changes.

If we do not, then we spend time recompiling a source file when its .class file was fine.


Unless someone can make a good case, I would leave things as is & live with our current behaviour so we do not miss actual changes.
Comment 5 Olivier Lefevre CLA 2008-01-28 15:53:36 EST
But do they really have the same timestamp? That seems
impossible but if it so I would agree that the current
behaviour should be left alone.
Comment 6 Olivier Thomann CLA 2008-01-28 16:55:05 EST
It would be trivial to dump the timestamps in the console.
Comment 7 Maxime Daniel CLA 2008-01-29 01:45:43 EST
If we happen to be fast enough to dump the class file and need it again within the same time tick but prefer recompiling the source, then we're probably facing an optimization issue. The scenario in which we would miss edits because of not taking into account a source file that would bear the same time stamp does not worry me that much. It would mean that the user continues editing while he builds, which should lead him to dubious results and would be calling for them anyway, or else that the user tampered with the class file's time stamp via other means (aka touch), hence would have cheated and would deserve retaliation.
Anyway, I'll make a few tries and since everyone else votes for security against performances, I'll let the code alone if we are right with the time stamps hypothesis. (I'll try anyway to get a sense of how frequently this may happen, just in case this would lead us to reconsider.)
Comment 8 Philipe Mulet CLA 2008-01-29 13:09:20 EST
Is this coarse-granularity for timestamps only a problem on certain OS ?
Comment 9 Philipe Mulet CLA 2008-01-29 13:20:58 EST
btw, according to ClasspathDirectory#findClass(...), my impression is that we already prefer a binary over a source with same timestamp (which also I would tend to consider suspicious, then prefer the source to be safe rather than sorry).

Comment 10 Philipe Mulet CLA 2008-01-30 04:39:44 EST
to investigate by M6
Comment 11 Maxime Daniel CLA 2008-02-04 03:36:27 EST
We have one case of (pseudo) realistic edits of source files fast enough to trick us if we were to consider a class file dated like its source file to be 'fresher' than it: some of our tests rewrite a source file then rebuild, fast enough to get everything done within the same second.
This is not strong enough an argument to close the debate, but if we change anything here, we should be prepared to get several tests fail for a while, until all of them get equipped with timers or (better) explicit touch of source files at a later point in time.
Comment 12 Maxime Daniel CLA 2008-03-13 11:54:39 EDT
This is not a timing issue. What happens is that we promote sourcepath entries before any classpath entry, hence we find X.java before X.class (will attach patch with test case). This happens into Main, line 3936. Classpath normalization could have helped, but does not really. Will talk to Olivier.
Comment 13 Maxime Daniel CLA 2008-03-13 11:56:19 EDT
Created attachment 92463 [details]
Test case
Comment 14 Maxime Daniel CLA 2008-03-14 10:44:28 EDT
This prompts for a review of what ecj and javac do in terms of sourcepath and classpath interaction. Will start with a series of test cases that illustrate similarities and differences.
Comment 15 Maxime Daniel CLA 2008-03-17 05:29:38 EDT
Released in HEAD BatchCompilerTest#230 to 235 that illustrate some of the differences between ecj and javac (1.6) relative to classpath and sourcepath management. I believe that we should not rush too hastily here. ecj and javac behave differently, but within the bounds of their specifications (that are somewhat lax indeed). And ecj's behavior has some merits of itself.
In any case, as far as the original bug is concerned, it should be noted that ecj behavior is somewhere between javac -Xprefer:newer and javac -Xprefer:source (but matching none of these - in fact, ecj prepends the source path to classpath entries, and treats classpath entries in command line order), and that using only -classpath would work around the undesired behavior.
I rename the bug accordingly.

I would retarget this bug out of M6 in any case, and possibly out of 3.4 as well. Others pls advise.
Comment 16 Olivier Lefevre CLA 2008-03-17 07:21:10 EDT
" ecj prepends the source path to classpath entries". This is effectively denying the programmer full control of the classpath; that doesn't strike me as a good idea. It should be up to him whether to include the source path in the classpath or not.
Comment 17 Maxime Daniel CLA 2008-03-17 09:51:35 EDT
(In reply to comment #16)
> " ecj prepends the source path to classpath entries". This is effectively
> denying the programmer full control of the classpath; that doesn't strike me as
> a good idea. It should be up to him whether to include the source path in the
> classpath or not.
javac does not allow much better in this area, since with it a .class file found anywhere in the classpath supersedes the matching .java file of the sourcepath if any, regardless of the relative positions of classpath and sourcepath on the command line, and regardless of which of the file was written last (unless you specify -Xprefer:source, in which case all .java files take precedence, be they in classpath or sourcepath). As far as full control is concerned, I would go after using classpath only, and play a bit with per classpath entry -d option. Even if we changed something in that area and removed the sourcepath precedence, the accumulation of subtle behaviors would remain due to make full control hard, and sticking to the basics would probably be the safest way to go. Note also that ecj and javac differ in some details when using classpath only.
Comment 18 Philipe Mulet CLA 2008-03-17 10:50:22 EDT
Looks like we don't have an answer for M6. Still I'd like to see alignment for 3.4 (if possible).
Comment 19 Maxime Daniel CLA 2008-03-17 11:29:27 EDT
ACK
Comment 20 Maxime Daniel CLA 2008-04-08 05:09:51 EDT
I released revised BatchCompilerTest#230-238 today to fuel the discussion. I'll have to take back one of my previous claims (javac cares indeed about dates when a source file and a class file compete against each other). However, I think we now have a clearer picture of existing differences, that everyone can experience by using the tests:
- ecj does not tolerate multiple -sourcepath options; it raises an error; javac 
  tolerates multiple -sourcepath options, but silently discards all but the last 
  one; note though that a -sourcepath option can hold multiple entries (for both 
  compilers);
- ecj concatenates -classpath options as if they were part of a single one (more 
  precisely, assuming the file path separator is ':' on the considered platform,
  '-classpath c1 -classpath c2' is equivalent to '-classpath c1:c2' for ecj);
  javac silently ignores all -classpath options but the last one; a -classpath 
  option can hold multiple entries (for both compilers);
- if there is a -sourcepath option and a -classpath option, whatever their 
  respective positions:
  - javac won't take any source file from classpath entries that are not on the 
    sourcepath; ecj will;
  - if a class file on the classpath is newer than a matching source file on the
    sourcepath or the classpath, javac will pick the class file up; ecj will
    only do that if the source file is on the classpath and on the same
    classpath entry as the class file or on a subsequent one;
- when considering two classpath entries (no sourcepath):
  - for two matching source files, ecj and javac will both pick the first one up
    (in classpath entries order - no date involved);
  - for two matching class files, ecj and javac will both pick the first one up
    (in classpath entries order - no date involved);
  - if a source file and a class file match, ecj will pick the first one up,
    while javac will pick the newest up.

We also know that in the case of a single classpath entry, ecj will recompile the source file if it happens not to be strictly older than a matching class file.

There are clear opportunities to spin off separate bugs here for specific differences, depending on how much we want to converge.

Another point of interest that should be debated before we make any source/class file time-based selection decision is that the straightforward rules used so far by ecj (prepend - unique - sourcepath to classpath, pick the first classpath entry that includes a matching file up, then compare source/class file dates in same classpath entry) was well articulated with per classpath entry options like access rules and output directories. Introducing per compilation unit cross-classpath entries time-based selection rules would surely make the picture much more complex here.

Philippe, others, please comment. 
Current plan is: debate, then see if we do anything at all for 3.4.
Comment 21 Maxime Daniel CLA 2008-04-10 08:02:01 EDT
Added BatchCompilerTest#279 and 280 that show that access rules are a separate mechanism that won't provide the same behavior as javac (specifically, the ignore if better access rule may help to pick a class file up downstream on the classpath in place of a source file on the sourcepath, but it won't compare modification dates, putting the user at risk to foresee source modifications).
Comment 22 Maxime Daniel CLA 2008-04-11 03:09:30 EDT
Since it is established that changing our policy would lead to problems with access rules, I believe we may want to think about this in a wider perspective. It is clear that we won't do the same as javac if presented with a representative sample of javac command lines. It is also clear that javac won't accept many valuables ecj options combinations either. Hence the question would boil down to: do we want a compatibility mode in which we would strive to do the same as javac? Which would be the subject of an enhancement request that would need some maturation (and is probably out of scope for 3.4).
And as far as the original issue is concerned, I would personally vote a WONTFIX.
Comment 23 Jerome Lanneluc CLA 2008-05-02 06:01:52 EDT
Maxime, did you enter a bug report for the compatibility mode? Otherwise if by design we cannot do anything for the case described in comment 0 without this compatibility mode, I agree that this bug should be closed as WORKSFORME.
Comment 24 Eclipse Genie CLA 2020-02-01 16:10:59 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. As such, we're closing this bug.

If you have further information on the current state of the bug, please add it and reopen this bug. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 25 Stephan Herrmann CLA 2020-02-02 07:20:37 EST
I agree to the conclusion in comment 22 & comment 23.

WONTFIX -> WORKSFORME