deltamind106
deltamind106

Reputation: 707

How To Force Java Compiler to ONLY compile the source file I specify?

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

Answers (3)

deltamind106
deltamind106

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

Joop Eggen
Joop Eggen

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

Klitos Kyriacou
Klitos Kyriacou

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

Related Questions