使用ant构建时的VerifyError,从Eclipse构建时是OK

时间:2013-03-01 11:56:06

标签: android eclipse adt javac verifyerror

我的Android java项目有几种配置。以前我切换它们并手动从eclipse构建apk,但最近我开发了几个ant任务让我的生活更轻松:我启动cmd文件并构建所有配置(每次更改配置变量,移动资源,修改清单,等)。

但今天我发现由ant(它使用javac)和android工作流编译的代码(我的build.xml包含$ {sdk.dir} /tools/ant/build.xml)与代码不同由Eclipse中的ADT工具生成。并且差异是致命的。

在编译阶段,javac声称某些文件包含BOM,而且一个类太大(对于许多静态数组)。我已经将所有文件转换为utf8 w / o bom,将大类拆分为两个,javac没有更多问题。很容易。

但是,如果我在4.0.x设备或模拟器上启动ant-made apk(同时适用于1.6,2.2,4.1,4.2),它会在运行时关闭并说:

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

但eclipse-adt-made apk在4.0.x上工作得相当好!此外 - 我从未在编译时看到关于utf bom或类大小的adt声明。

所以我假设我们应该在ant build中使用比javac更好的东西。但Google在其build.xml中使用了完全正确的javac。 在使用ant构建时,我们如何使用ADT编译器代替javac?

当然我仍然可以在eclipse中进行构建,但是当我花20分钟时,ant脚本花费1分钟,而且在更改cfg变量时它们从未犯过愚蠢的错误(它们之间存在一些依赖关系)。

提前致谢!

UPDT: 我怀疑它与我使用的java版本有某种联系。 Ant以1.7 x86 jdk执行,而eclipse使用jdk1.6.0_26 x64。有人说Dalvik dex不了解一些java 1.7字节码,但我应该检查一下。

UPDT1:不,我删除了所有jdks,然后安装了jdk 1.6.0_41 x86和x64,将eclipse工作设置为1.6.0_41 x64并将JAVA_PATH设置为jdk 1.6.0_41 x86。同样的事情 - 在eclipse(Android工具 - &gt;导出签名的apk)编译的apk工作,蚂蚁编译apk说VerifyError。

1 个答案:

答案 0 :(得分:1)

认为我已经解决了这个问题。

我花了几个小时来切换java版本,重新定义默认的google ant任务,尝试从几个jdk中独立启动不同的javac来编译我的类。在过去的五年里,我从来没有使用控制台工具编译java,因此很难和混乱。我对任何javac没有运气,同样的验证错误。

然后我读了Eclipse和Android文档,发现当我们在eclipse中构建apk时,ADT使用Eclipse的JDT(Eclipse Compiler for Java)代替javac将java代码编译成类,然后使用dx工具制作dalvik代码。 所以我们需要启动JDT而不是普通的编译ant任务,对吧?不,实际上一切都更容易。因为它经常发生,我从最后开始,但一旦我明白我需要这个编译工具,我是在正确的方式。

Eclipse Compiler for Java(JDT ECJ)是比实际javac更智能的工具。这对我来说是一个新工具,有很多参数,但是JDT提供了非常酷的ant javac adapter,我们可以在javac ant任务中使用它 - 设置“build.compiler”属性,然后启动正常的android ant -compile任务:< / p>

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

但除非你有ecj.jar,否则这不会奏效。日食中没有这样的文件!继续调查我发现Eclipse Compiler for Java可以是downloaded as standalone。要完成这项工作,您需要将此jar复制到ant / lib文件夹。但奇怪的是 - ecj 4.2.2编译代码具有相同的验证问题。幸运的是我已经尝试过ecj 3.5.1 - 它有效!但是我不满意 - 我仍然不能说为什么ecj 4.2.2在3.5.1没有帮助。如果我升级eclipse会编译坏类怎么办?我比较了字节代码 - 它略有不同(由jd-gui反编译),所以我认为问题在于产生类文件。我想知道什么是哎呀,但我甚至无法想象要寻找什么。

无论如何,还有更多。当你查看eclipse / plugins文件夹时,你会看到一个名为“org.eclipse.jdt.core_3.6.2.v_A76_R36x.jar”的文件。它包含jdtCompilerAdapter.jar文件(因为jar是一个zip存档)。如果你将它复制到ant / lib然后复制org.eclipse.jdt.core_xxxxxx.jar文件本身,你得到的是当前eclipse版本所具有的完全相同的编译器!瞧!这样你就可以确定如果eclipse成为一个“好”的代码 - 蚂蚁也会这样做。


所以最后一切都产生了两个简单的步骤:

  1. 将org.eclipse.jdt.core_xxxxxx.jar和jdtCompilerAdapter.jar从里面复制到你的ant / lib文件夹。

  2. 将以下内容添加到project.properties文件中:

    • java.target = 1.6
    • java.source = 1.6
    • build.compiler = org.eclipse.jdt.core.JDTCompilerAdapter
  3. 这就是全部!

    但是如果你有想法为什么来自eclipse juno package(4.2.2)的ecj无法编译正确的代码我想听!