Android应用程序中的Gradle ANTLR4插件:构建失败 [英] Gradle ANTLR4 plugin in Android app: build fails
问题描述
我花了几天的时间发现这个问题,我想在这里发表我的发现.
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
这里有一些答案建议增加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
}
android模块:
android module:
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
库和antlr4-runtime都包含org.abego.treelayout
类:
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.5
,org.antlr:antlr4-runtime:4.5
和甚至可能出现在org.abego.treelayout:org.abego.treelayout.core:1.0.1
中.我猜这是使用grat的antlr4插件的错误-他们错误地在主程序包中添加了这些类,而应该只将它们放在依赖项中.也许我应该将错误提交给插件跟踪器.
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屋!