Reputation: 707
The java 12.0.1 compiler (my tests here are all run in MS Windows) has some really odd behavior when using the -sourcepath argument, with regards to what it decides to compile. The easiest way to explain this is to provide two examples and cite the differences in behavior.
Example 1:
Source file "A.java"
public class A {
public static void main(String[] args) {
System.out.println("Hello World");
B.myMethod();
}
}
Source file "B.java"
public class B {
public static void myMethod() {
System.out.println("Goodbye!");
}
}
To compile example 1, we just use the following:
javac -sourcepath . A.java
This will compile both A.java and B.java and create A.class and B.class. We expect it to also compile B.java because A depends on it. Now wait a second or so and without modifying either ".java" source file, simply re-run the compilation command above. You will find that it re-compiles A.java and a new A.class is created (with updated timestamp), but B.class is not re-compiled. Ok, this is pretty much what one might expect. Now let's compare this to the next example below.
Example 2:
Source file "example2/A.java"
package example2;
public class A {
public static void main(String[] args) {
System.out.println("Hello World");
B.myMethod();
}
}
Source file "example2/B.java"
package example2;
public class B {
public static void myMethod() {
System.out.println("Goodbye!");
}
}
The source files are the same, except everything is moved into a package. We want to compile the two source files while currently in the "example2" folder. So we use the following command:
javac -sourcepath .. A.java
This will again compile both A.java and B.java and create A.class and B.class. No problems here, same as before. Note that -sourcepath is now ".." because that is the "root" source folder now that everything is in a package. Now wait a second or so and without modifying either source file, simply re-run the compilation command above. You will find that it re-compiles BOTH A.java and B.java and a new A.class and B.class file are created (with updated timestamps).
Note the difference in compilation behavior when the javac command is run the second time. When -sourcefile was "." and the files were not in a package, the second "javac" command only compiles the source file specified on the command line. But when -sourcefile is ".." and the classes are in a package, the second "javac" command ALWAYS compiles all the dependent source files, regardless if the unspecified source files need to be recompiled or not.
The question is why? What arguments can I pass to the javac command-line to stop example 2 from unconditionally recompiling all the dependent source files, if their class files have a newer timestamp than the source files?
Upvotes: 4
Views: 2534
Reputation: 707
EDIT: I've removed my suggestion that this is a bug, since I've accepted another answer as the best explanation.
As an aside, there seems to be no sensible way to report this as a bug to the OpenJDK. I googled and searched around the OpenJDK website and it seems that the bugs.openjdk.java.net is only for trusted developers. I guess I could throw it up on the OpenJDK mailing list, but that seems like a hack. So I am not even sure where to report this bug, sadly.
Upvotes: 0
Reputation: 109547
This seems related to ..
. If you go to the source root, the default package:
cd ..
javac -sourcepath . ex/A.java
everything works (at my place): no recompile of B.java.
It might be due to the -classpath
too, but I would rather think of some esoteric problem with package paths.
Upvotes: 0
Reputation: 11621
This issue occurs because javac compares timestamps between the .java file and the .class file. It uses -sourcepath
to find the source files, and -classpath
to find the class files. Therefore, your issue can be fixed by specifying the classpath:
javac -sourcepath .. -classpath .. A.java
Upvotes: 3