Question

My java project for Android has several configurations. Previously I switched them and build apk from eclipse manually, but recently I've developed several ant tasks to make my life much easier: I launch cmd file and it builds all the configurations (changing config vars each time, moving resources, modifying manifest, etc.).

But today I've found that code compiled by ant (it uses javac) with android workflow (my build.xml includes ${sdk.dir}/tools/ant/build.xml) is different from code generated by ADT tool in Eclipse. And difference is fatal.

On compile stage javac claimed that some files include BOM, and one class is too big (to many static arrays). I've converted all files to utf8 w/o bom, splitted big class into two and javac had no more issues. It was easy.

However if I launch ant-made apk on 4.0.x device or emulator (while works on 1.6, 2.2, 4.1, 4.2) it force closes in runtime and says:

03-01 09:15:16.247: W/dalvikvm(1993): VFY: register1 v3 type 17, wanted 18
03-01 09:15:16.247: W/dalvikvm(1993): VFY:  rejecting opcode 0xc8 at 0x0023
03-01 09:15:16.247: W/dalvikvm(1993): VFY:  rejected Lcom/myproj/MySomeClass;.doThing (I)V
03-01 09:15:16.247: W/dalvikvm(1993): Verifier rejected class Lcom/myproj/MySomeClass;
03-01 09:15:16.247: W/System.err(1993): java.lang.VerifyError: com/myproj/MySomeClass
...
<stack here>
...

But eclipse-adt-made apk works on 4.0.x pretty well! Moreover - I never saw adt claims about utf bom or class size on compile.

So I assume we should use something else raither than javac in ant build. But Google uses exactly javac in its build.xml. How can we use ADT compiler instead of javac when building with ant?

Of course I still can make builds in eclipse, but ant scripts spends 1 minute when I spend 20 minutes, and it never make silly mistakes while changing cfg vars (there some dependencies between them).

Thanks in advance!

UPDT: I suspect it is somehow connected with java version I use. Ant executes with 1.7 x86 jdk, while eclipse uses jdk1.6.0_26 x64. Someone says that Dalvik dex doesn't understand some java 1.7 bytecodes, but I should check.

UPDT1: No, I've removed all jdks, then installed both jdk 1.6.0_41 x86 and x64, set eclipse work with 1.6.0_41 x64 and set JAVA_PATH to jdk 1.6.0_41 x86. The same thing - apk compiled in eclipse (Android tools->Export signed apk) works, ant-compiled apk says VerifyError.

Was it helpful?

Solution

Think I've solved this issue.

I spent hours switching java versions, re-defining default google ant tasks, trying to launch different javac from several jdk as standalone to compile my classes. During last five years I never compiled java with console tools, so it was hard and confusing. I had no luck with any javac, the same verify error.

Then I read Eclipse and Android docs and found that when we build apk in eclipse, ADT uses Eclipse's JDT (Eclipse Compiler for Java) instead of javac to compile java code into classes, and then dx tool to make dalvik code. So we need to launch JDT instead of normal -compile ant task, right? No, actually everything is easier. As it often happens I started from the end but once I understood that I need this compile tool I was on the right way.

Eclipse Compiler for Java (JDT ECJ) is much smarter tool than actual javac. It's a new tool for me with bunch of parameters, but JDT provides pretty cool ant javac adapter, and we can use it in javac ant task - set "build.compiler" property and then launch normal android ant -compile task:

<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter" />

<javac encoding="${java.encoding}" source="1.6" target="1.6" debug="true" extdirs=""
                   includeantruntime="false" destdir="${out.classes.absolute.dir}"
                   bootclasspathref="project.target.class.path"
                   verbose="${verbose}" classpathref="project.javac.classpath"
                   fork="${need.javac.fork}" >
    <src path="${source.absolute.dir}" />
    <src path="${gen.absolute.dir}" />
    <compilerarg line="${java.compilerargs}" />
</javac>

But this will not work unless you have ecj.jar. And there is no such a file in eclipse! Continuing investigation I've found out that Eclipse Compiler for Java can be downloaded as standalone. To make this work you need to copy this jar to ant/lib folder. But strange thing - ecj 4.2.2 compiled code with the same verify problem. Luckily I've tried ecj 3.5.1 - and it worked! However I'm not satisfied - I still can't say why ecj 4.2.2 doesn't help while 3.5.1 does. What if I upgrade eclipse and it will compile bad classes? I've compared byte code - it differs very slightly (decompiled by jd-gui), so I assume problem is in something inside resulting class files. I'd like to know what's the heck but I even can't imagine what to look for.

Anyway, there is more. When you look to eclipse/plugins folder you'll see a file with name like "org.eclipse.jdt.core_3.6.2.v_A76_R36x.jar". It holds jdtCompilerAdapter.jar file inside (as jar is a zip archive). If you copy it to ant/lib and then copy org.eclipse.jdt.core_xxxxxx.jar file itself you get exactly the same compiler that your current eclipse version has! Voila! This way you can be sure that if eclipse makes a "good" code - ant will do also.


So finally everything resulted in two simple steps:

  1. copy org.eclipse.jdt.core_xxxxxx.jar and jdtCompilerAdapter.jar from inside of it to your ant/lib folder.

  2. add following to you project.properties file:

    • java.target=1.6
    • java.source=1.6
    • build.compiler=org.eclipse.jdt.core.JDTCompilerAdapter

That's all!

But if you have ideas why ecj from eclipse juno package (4.2.2) fails to compile right code I'd like to listen!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top