Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #35136

Re: Is it necessary the source file should be at the same location with the class file?

From Steven Simpson <ss@my.domain.invalid>
Newsgroups comp.lang.java.programmer
Subject Re: Is it necessary the source file should be at the same location with the class file?
Date 2016-07-25 21:21 +0100
Organization A noiseless patient Spider
Message-ID <209i6d-u46.ln1@s.simpson148.btinternet.com> (permalink)
References (1 earlier) <nn0t8n$17np$1@gioia.aioe.org> <q38e6d-nn9.ln1@s.simpson148.btinternet.com> <nn29sl$old$1@gioia.aioe.org> <8bnf6d-sua.ln1@s.simpson148.btinternet.com> <nn3e5r$dk1$1@gioia.aioe.org>

Show all headers | View raw


On 24/07/16 23:06, Arne Vajhøj wrote:
> On 7/24/2016 5:08 PM, Steven Simpson wrote:
>> With the output directory in the classpath, doesn't it mean that javac
>> will attempt a kind of incremental build?  And doesn't it then miss some
>> not particularly extraordinary cases (inlined constants; return types),
>> leading to broken builds?
> The problem you mention is real and need to be handled. There are
> ways to do that via various build scripts from OS shell to ant to
> newer build frameworks.

I was not convinced that Ant would be enough, as the <javac> task 
behaves largely as [javac -classpath out -d out], comparing timestamps 
of corresponding .java and .class files, so it's exposed to the same 
problems.  Combining <depend> with <javac> should do better, but it 
looked like it would still miss inlined constants, so I tried it out:

mkdir src
cat > build.xml <<EOF
<project>
   <target name="clean">
     <delete dir="build" />
   </target>

   <target name="compile">
     <mkdir dir="build/classes" />
     <!-- depend srcDir="src" destdir="build/classes"
             cache="build/depcache" / -->
     <javac srcdir="src" destdir="build/classes" />
   </target>

   <target name="jar">
     <mkdir dir="build/jar" />
     <jar destfile="build/jar/test.jar" basedir="build/classes">
       <manifest>
         <attribute name="Main-Class" value="A" />
       </manifest>
     </jar>
   </target>

   <target name="run">
     <java jar="build/jar/test.jar" fork="true" />
   </target>
</project>
EOF
cat > src/A.java <<EOF
public class A {
     public static void main(String[] args) throws Exception {
         B.test();
     }
}
EOF
cat > src/B.java <<EOF
public class B {
     public static void test() {
         C.test();
         int d = D.CONSTANT;
         System.out.println("CONSTANT = " + d);
     }
}
EOF
cat > src/C.java <<EOF
public class C {
     public static String test() {
         D.test();
         return null;
     }
}
EOF
cat > src/D.java <<EOF
public class D {
     public static void test() {
     }

     public static final int CONSTANT = 15;
}
EOF


   ant compile && ant jar && ant run

It should run fine, and print the correct constant.  Change the constant 
in class D, compile again, and the old value is printed. Make C.test() 
return Object instead of String, and try again, and you get:

   java.lang.NoSuchMethodError: C.test()Ljava/lang/String;

If you enable the <depend> task, the return-type problem is fixed.  The 
inline problem isn't fixed if you're using Java 7, but I was surprised 
to find that it is for Java 8.  javap reveals why:

   Last modified 25-Jul-2016; size 540 bytes
   MD5 checksum 375791f56bf0e955d6630fdc464c8ea6
public class B
   minor version: 0
   major version: 52
   flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
    #1 = Methodref          #13.#18        // java/lang/Object."<init>":()V
    #2 = Methodref          #19.#20        // C.test:()Ljava/lang/String;
    #3 = Class              #21            // D
    #4 = Fieldref           #22.#23        // java/lang/System.out:Ljava/io/PrintStream;
    #5 = Class              #24            // java/lang/StringBuilder
    #6 = Methodref          #5.#18         // java/lang/StringBuilder."<init>":()V
    #7 = String             #25            // CONSTANT =
    #8 = Methodref          #5.#26         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    #9 = Methodref          #5.#27         // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   #10 = Methodref          #5.#28         // java/lang/StringBuilder.toString:()Ljava/lang/String;
   #11 = Methodref          #29.#30        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #12 = Class              #31            // B
   #13 = Class              #32            // java/lang/Object
   #14 = Utf8               <init>
   #15 = Utf8               ()V
   #16 = Utf8               Code
   #17 = Utf8               test
   #18 = NameAndType        #14:#15        // "<init>":()V
   #19 = Class              #33            // C
   #20 = NameAndType        #17:#34        // test:()Ljava/lang/String;
   #21 = Utf8               D
   #22 = Class              #35            // java/lang/System
   #23 = NameAndType        #36:#37        // out:Ljava/io/PrintStream;
   #24 = Utf8               java/lang/StringBuilder
   #25 = Utf8               CONSTANT =
   #26 = NameAndType        #38:#39        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #27 = NameAndType        #38:#40        // append:(I)Ljava/lang/StringBuilder;
   #28 = NameAndType        #41:#34        // toString:()Ljava/lang/String;
   #29 = Class              #42            // java/io/PrintStream
   #30 = NameAndType        #43:#44        // println:(Ljava/lang/String;)V
   #31 = Utf8               B
   #32 = Utf8               java/lang/Object
   #33 = Utf8               C
   #34 = Utf8               ()Ljava/lang/String;
   #35 = Utf8               java/lang/System
   #36 = Utf8               out
   #37 = Utf8               Ljava/io/PrintStream;
   #38 = Utf8               append
   #39 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
   #40 = Utf8               (I)Ljava/lang/StringBuilder;
   #41 = Utf8               toString
   #42 = Utf8               java/io/PrintStream
   #43 = Utf8               println
   #44 = Utf8               (Ljava/lang/String;)V
{
   public B();
     descriptor: ()V
     flags: ACC_PUBLIC
     Code:
       stack=1, locals=1, args_size=1
          0: aload_0
          1: invokespecial #1                  // Method java/lang/Object."<init>":()V
          4: return

   public static void test();
     descriptor: ()V
     flags: ACC_PUBLIC, ACC_STATIC
     Code:
       stack=3, locals=1, args_size=0
          0: invokestatic  #2                  // Method C.test:()Ljava/lang/String;
          3: pop
          4: bipush        10
          6: istore_0
          7: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
         10: new           #5                  // class java/lang/StringBuilder
         13: dup
         14: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
         17: ldc           #7                  // String CONSTANT =
         19: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
         22: iload_0
         23: invokevirtual #9                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
         26: invokevirtual #10                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
         29: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         32: return
}

Entry #3 in the constant pool refers to class D, even though no other 
part of the class file uses it.  That's evidently enough to get <depend> 
to force recompilation of B.  Bytecode from javac 7 doesn't include that 
reference.

So Ant will handle the two mentioned cases if used with <depend> and 
javac from JDK8.


-- 
ss at comp dot lancs dot ac dot uk

Back to comp.lang.java.programmer | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Is it necessary the source file should be at the same location with the class file? parmenides <xparmenides@yahoo.com> - 2016-07-24 00:55 +0800
  Re: Is it necessary the source file should be at the same location with the class file? Steven Simpson <ss@my.domain.invalid> - 2016-07-23 20:10 +0100
  Re: Is it necessary the source file should be at the same location with the class file? Arne Vajhøj <arne@vajhoej.dk> - 2016-07-23 19:05 -0400
    Re: Is it necessary the source file should be at the same location with the class file? Steven Simpson <ss@my.domain.invalid> - 2016-07-24 08:42 +0100
      Re: Is it necessary the source file should be at the same location with the class file? Arne Vajhøj <arne@vajhoej.dk> - 2016-07-24 07:47 -0400
        Re: Is it necessary the source file should be at the same location with the class file? Steven Simpson <ss@my.domain.invalid> - 2016-07-24 22:08 +0100
          Re: Is it necessary the source file should be at the same location with the class file? Martin Gregorie <martin@address-in-sig.invalid> - 2016-07-24 21:28 +0000
          Re: Is it necessary the source file should be at the same location with the class file? Arne Vajhøj <arne@vajhoej.dk> - 2016-07-24 18:06 -0400
            Re: Is it necessary the source file should be at the same location with the class file? Steven Simpson <ss@my.domain.invalid> - 2016-07-25 21:21 +0100
              Re: Is it necessary the source file should be at the same location with the class file? Arne Vajhøj <arne@vajhoej.dk> - 2016-07-25 21:03 -0400
    Re: Is it necessary the source file should be at the same location with the class file? Roedy Green <inquiry@mindprod.com> - 2016-07-26 15:24 -0700
  Re: Is it necessary the source file should be at the same location with the class file? Arne Vajhøj <arne@vajhoej.dk> - 2016-07-23 19:06 -0400

csiph-web