Android 应用程序中的 Gradle ANTLR4 插件:构建失败 [英] Gradle ANTLR4 plugin in Android app: build fails

查看:22
本文介绍了Android 应用程序中的 Gradle ANTLR4 插件:构建失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我花了几天时间发现这个问题,我想在这里发布我的发现.

I spent few days spotting this issue, and I'd like to post my finding here.

我正在构建一个包含多个模块的 Android 应用程序,其中一个模块使用 ANTLR 插件.虽然带有 ANTLR 的模块构建正常,因为它是一个 Java 模块,但 android 模块在 transformClassesWithDexForDebug 任务中失败:

I'm building an Android app with several modules, one of them using ANTLR plugin. While the module with ANTLR builds OK, as it is a Java module, the android module fails in transformClassesWithDexForDebug task:

* What went wrong:
Execution failed for task ':Android:transformClassesWithDexForDebug'.
> com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: java.lang.RuntimeException: Translation has been interrupted

如果我尝试在 build.gradle 中启用 multiDexEnabled,我会收到一条不同的消息:

If I try to enable multiDexEnabled in build.gradle I get a different message:

* What went wrong:
Execution failed for task ':Android:transformClassesWithJarMergingForDebug'.
> com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: org/abego/treelayout/Configuration$AlignmentInLevel.class

这里的一些答案建议增加用于 dexing 的 Java RAM,减少依赖项,例如 google-play 库 - 我这样做了,但并不高兴.

Some answers here suggests increasing Java RAM for dexing, reducing dependencies such as google-play library - I did that but no joy.

这里使用 build.gradle 示例:

Here go build.gradle samples used:

ANTLR4 模块:

apply plugin: 'antlr'
apply plugin: 'java'
apply plugin: 'maven'

sourceCompatibility = 1.7
targetCompatibility = 1.7

final GENERATED_MAIN = "src-gen/main/java"
final GENERATED_TEST = "src-gen/test/java"

sourceSets {
    main {
        java { srcDirs += [GENERATED_MAIN] }
    }
    main {
        java { srcDirs += [GENERATED_TEST] }
    }
}

repositories {
     mavenCentral()   
}

dependencies {
   antlr("org.antlr:antlr4:4.5") {
       exclude group: 'org.antlr', module:'antlr-runtime'
//       exclude group: 'org.antlr', module:'antlr4-runtime'
       exclude group: 'org.antlr', module:'ST4'
   }
    compile ('com.yuvalshavit:antlr-denter:1.0') {
       exclude group: 'org.antlr', module:'antlr4-runtime'
    }
    testCompile group: 'junit', name: 'junit', version:'4.11'
}

generateGrammarSource.doFirst {
    outputDirectory = new File(GENERATED_MAIN)
}
generateGrammarSource.doLast {
    moveAntlrGeneratedFilesToTheirPackages(source, GENERATED_MAIN)
}
generateTestGrammarSource.doFirst {
    outputDirectory = new File(GENERATED_TEST)
}
generateTestGrammarSource.doLast {
    moveAntlrGeneratedFilesToTheirPackages(source, GENERATED_TEST)
}

def moveAntlrGeneratedFilesToTheirPackages(FileTree grammarFiles, generatedFolder) {
    grammarFiles.each {File file ->
        final grammarName = file.name.lastIndexOf('.')>=0 ? file.name[0 .. file.name.lastIndexOf('.')-1] : file.name
        final grammarPackage = extractPackageNameFromGrammerFile(file)
        copy {
            from generatedFolder
            include "${grammarName}*.*"
            into generatedFolder + "/" + grammarPackage.replaceAll("\\.", "/")
        }
    }
    project.delete fileTree(generatedFolder).include('*.*')
}

def extractPackageNameFromGrammerFile(File grammarFile) {
    def grammarPackage = "unknown.package"
    def packageRegex = ~/[ ]*package[ ]*([a-zA-Z]+[a-zA-Z0-9.-_]*)[ ]*;/
    grammarFile.eachLine { line ->
        def matcher = packageRegex.matcher(line)
        if (matcher.find()){
            grammarPackage = matcher.group(1)
        }
    }
    return grammarPackage
}

安卓模块:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "<some package name here>"
        minSdkVersion 14
        targetSdkVersion 22
//        multiDexEnabled true
    }


    dexOptions {
//        javaMaxHeapSize "4g"
    preDexLibraries = false
    }

    lintOptions {
          abortOnError false
    }

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['iadl']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }
    }

}

dependencies {
    compile project(':texas-board')   // this references the ANTLR module mentioned above
    ...
}

root build.gradle:

root build.gradle:

buildscript {
    repositories {
        jcenter()
    mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'
    }
}

分析依赖(gradle dependencies)表明问题是antlr gradle插件通过antlr4库包含org.abego.treelayout类用于编译和 antlr4-runtime:

analyzing dependencies (gradle dependencies) shows that the problem is that antlr gradle plugin includes org.abego.treelayout classes both via antlr4 library used for compilation, and antlr4-runtime:

+--- project :texas-board
|    \--- project :rules_engine
|         +--- org.antlr:antlr4:4.5
|         |    +--- org.antlr:antlr4-runtime:4.5
|         |    |    \--- org.abego.treelayout:org.abego.treelayout.core:1.0.1
|         |    \--- org.antlr:antlr-runtime:3.5.2
|         \--- com.yuvalshavit:antlr-denter:1.0

再一次 - 问题是 org.abego.treelayout 类同时存在于 org.antlr:antlr4:4.5org.antlr:antlr4-runtime:4.5 甚至可能在 org.abego.treelayout:org.abego.treelayout.core:1.0.1 中.我猜这是 antlr4 gradle 插件的一个错误 - 他们错误地在主包中添加了这些类,而它们应该只存在于依赖项中.可能我应该向插件跟踪器提交一个错误.

once again - the matter is that the org.abego.treelayout classes are present both in org.antlr:antlr4:4.5, org.antlr:antlr4-runtime:4.5 and probably even in org.abego.treelayout:org.abego.treelayout.core:1.0.1. I guess that it is a bug with antlr4 plugin for gradle - they wrongly added those classes in main package while they are supposed to be in dependencies only. Probably I should submit a bug to the plugin tracker.

此外,antlr4 插件甚至添加了 antlr3-runtime 依赖,这可能会重新定义 org.abego.treelayout 类(所以我也排除了它).

Moreover, antlr4 plugin even adds antlr3-runtime dependency which may redefine org.abego.treelayout classes as well (so I also excluded it).

虽然 Java 应用程序接受 java 类的额外副本(我相信它们从类路径中获取第一个副本),但 android 插件在 dex 阶段失败,报告上述错误.

While Java apps accept extra copies of java classes (they take the first one from classpath I believe), android plugin fails in dex stage reporting errors mentioned above.

推荐答案

我的解决方案是删除重复的依赖项:

My solution was to remove duplicate dependencies:

apply plugin: 'antlr'
apply plugin: 'java'
apply plugin: 'maven'

sourceCompatibility = 1.7
targetCompatibility = 1.7

final GENERATED_MAIN = "src-gen/main/java"
final GENERATED_TEST = "src-gen/test/java"

sourceSets {
    main {
        java { srcDirs += [GENERATED_MAIN] }
    }
    main {
        java { srcDirs += [GENERATED_TEST] }
    }
}

repositories {
     mavenCentral()   
}

dependencies {
   antlr("org.antlr:antlr4:4.5") {
       exclude group: 'org.antlr', module:'antlr-runtime'
       exclude group: 'org.antlr', module:'antlr4-runtime'
       exclude group: 'org.antlr', module:'ST4' // just in case :-)
   }
    compile ('com.yuvalshavit:antlr-denter:1.0') {
       // denter library also has dependency on antlr4-runtime ...
       exclude group: 'org.antlr', module:'antlr4-runtime' 
    }
    testCompile group: 'junit', name: 'junit', version:'4.11'
}
...

我愿意为您提供任何更好的解决方案 - 我不擅长 gradle.

I'm open for any better solution you can suggest - I'm not good with gradle.

这篇关于Android 应用程序中的 Gradle ANTLR4 插件:构建失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆