| Summary: | [batch][compiler] ecj behaves differently than javac wrt -sourcepath and -classpath options | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Product: | [Eclipse Project] JDT | Reporter: | Olivier Lefevre <lefevrol> | ||||||
| Component: | Core | Assignee: | 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
Olivier Lefevre
Created attachment 87954 [details]
The script to run
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. 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. 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. 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. It would be trivial to dump the timestamps in the console. 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.) Is this coarse-granularity for timestamps only a problem on certain OS ? 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). to investigate by M6 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. 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. Created attachment 92463 [details]
Test case
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. 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. " 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. (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. Looks like we don't have an answer for M6. Still I'd like to see alignment for 3.4 (if possible). ACK 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.
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). 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. 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. 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. I agree to the conclusion in comment 22 & comment 23. WONTFIX -> WORKSFORME |