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?
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