如何声明渐变Antlr任务输出规格以避免不必要的重建 [英] How do I declare gradle Antlr task output specs to avoid unnecessary rebuilds
问题描述
问题是,毕业生会将6个目标文件视为一直所以每个运行或调试会话都必须重新生成它们,因此即使没有源文件发生变化,也必须重新编译主java项目。
生成文件的任务的输出规范被定义为生成6个输出文件的文件夹。我认为我需要一种方法将其定义为6个特定文件而不是输出文件夹。我只是不知道这样做的语法。
这是我的build.gradle文件的相关部分:
ext.antlr4 = [
pre>
antlrSource:src / main / antlr,
destinationDir:src / main / java / com / myantlrquestion / core / antlr / generated,
grammarpackage:com.myantlrquestion.core.antlr.generated
]
任务makeAntlrOutputDir<<< {
file(antlr4.destinationDir).mkdirs()
}
任务compileAntlrGrammars(类型:JavaExec,dependsOn:makeAntlrOutputDir){
//语法方便排序按字母顺序排列。我认为这将是真的。
//确保名为* Lexer.g4的文件被列出,因此在对应的* Parser.g4
//之前进行处理。这很重要,因为Lexer必须先被处理,因为Parser需要.tokens文件从Lexer。
//另请注意,组合语法的输出文件命名约定与单独的Lexer和Parser语法略有不同。
def grammars = fileTree(antlr4.antlrSource).include('** / *。g4')
def target = file($ {antlr4.destinationDir})
inputs.files语法
// TODO:此输出规范不正确,因此该任务从不被视为最新的。
// TODO:调整输出集合,使其组合语法以及单独的Lexer和Parser语法是正确的。
outputs.dir target
main ='org.antlr.v4.Tool'
classpath = configurations.antlr4
// Antlr命令行参数在https: //theantlrguy.atlassian.net/wiki/display/ANTLR4/ANTLR+Tool+Command+Line+Options
args = [-o,target,
-lib,target,
// - listener,// - listener是默认的
// - no-visitor,// - no-visitor是默认的
-package ,
grammars.files
] .flatten()
//包含可选描述和组(由./gradlew任务命令显示)
描述='从ANTLR4语法生成Java源'
group ='Build'
}
compileJava {
dependsOn compileAntlrGrammars
//下一行isn在技术上需要,除非antdr4.destinationDir不在buildDir,但它不会伤害
源antlr4.destinationDir
}
任务cleanAntlr {
删除antlr4.destinationDir
}
clean.dependsOn cleanAntlr
解决方案我发现问题不在于目标文件过时,而是由于cleanAntlr任务,每次任何毕业任务运行时都会被删除。问题是,cleanAntlr中的所有代码都是在gradle初始化和配置阶段运行的,即使cleanAntlr任务本身没有执行。
最初,任务定义为:
任务cleanAntlr {
delete antlr4.destinationDir
}
clean .dependsOn cleanAntlr
解决方案是定义如下:(注意<)在任务名称之后。)
task cleanAntlr<< {
删除antlr4.destinationDir
}
clean.dependsOn cleanAntlr
...或者,为了更加清楚,使用这个更冗长但功能上相同的任务定义:
task cleanAntlr {
doLast(){
//确保在doLast()中包含执行阶段代码。
//否则,它将在初始化或配置阶段运行,即使运行不相关的任务也是如此。
//当NetBeas IDE首次加载项目时,它也会运行。
// println'删除Antlr目录:'+ antlr4.destinationDir
delete antlr4.destinationDir
}
}
clean.dependsOn cleanAntlr
修复了该错误,compileAntlrGrammars任务的原始输出规范正常工作。不需要指定每个单独的输出文件。这在 https://gradle.org/docs/的第15.9.2节中已经很好地解释了current / userguide / more_about_tasks.html 。
def grammars = fileTree(antlr4.antlrSource).include('* * / *。g4')
def target = file($ {antlr4.destinationDir})
inputs.files语法
outputs.dir目标
I have a typical Antlr 4.5 project with two grammar files: MyLexer.g4 and MyParser.g4. From them, Antlr generates 6 output files: MyLexer.java, MyLexer.tokens, MyParser.java, MyParser.tokens, MyParserBaseListener.java and MyParserListener.java. The gradle tasks are all working correctly so that the output files are all generated, compiled and tested as expected.
The problem is that gradle sees the 6 target files as always being out of date, so every run or debug session has to regenerate them and therefore has to recompile the main java project even if none of the source files have changed.
The gradle task which generates the file has the output spec defined as the folder into which the 6 output files are generated. I think that I need a way to define it as being the 6 specific files rather than the output folder. I just don't know the syntax to do that.
Here's the pertinent part of my build.gradle file:
ext.antlr4 = [ antlrSource: "src/main/antlr", destinationDir: "src/main/java/com/myantlrquestion/core/antlr/generated", grammarpackage: "com.myantlrquestion.core.antlr.generated" ] task makeAntlrOutputDir << { file(antlr4.destinationDir).mkdirs() } task compileAntlrGrammars(type: JavaExec, dependsOn: makeAntlrOutputDir) { // Grammars are conveniently sorted alphabetically. I assume that will remain true. // That ensures that files named *Lexer.g4 are listed and therefore processed before the corresponding *Parser.g4 // It matters because the Lexer must be processed first since the Parser needs the .tokens file from the Lexer. // Also note that the output file naming convention for combined grammars is slightly different from separate Lexer and Parser grammars. def grammars = fileTree(antlr4.antlrSource).include('**/*.g4') def target = file("${antlr4.destinationDir}") inputs.files grammars // TODO: This output spec is incorrect, so this task is never considered up to date. // TODO: Tweak the outputs collection so it is correct with combined grammars as well as separate Lexer and Parser grammars. outputs.dir target main = 'org.antlr.v4.Tool' classpath = configurations.antlr4 // Antlr command line args are at https://theantlrguy.atlassian.net/wiki/display/ANTLR4/ANTLR+Tool+Command+Line+Options args = ["-o", target, "-lib", target, //"-listener", //"-listener" is the default //"-no-visitor", //"-no-visitor" is the default "-package", antlr4.grammarpackage, grammars.files ].flatten() // include optional description and group (shown by ./gradlew tasks command) description = 'Generates Java sources from ANTLR4 grammars.' group = 'Build' } compileJava { dependsOn compileAntlrGrammars // this next line isn't technically needed unless the antlr4.destinationDir is not under buildDir, but it doesn't hurt either source antlr4.destinationDir } task cleanAntlr { delete antlr4.destinationDir } clean.dependsOn cleanAntlr
解决方案I discovered the problem was not that the target files were out of date, but rather, due to a bug in the cleanAntlr task, they were being deleted every time that any gradle task was run. The problem was that all of the code in cleanAntlr was being run during gradle's initialization and configuration phase, even if the cleanAntlr task itself wasn't being executed.
Originally, the task was defined as:
task cleanAntlr { delete antlr4.destinationDir } clean.dependsOn cleanAntlr
The solution was to define it like this: (Note the "<<" after the task name.)
task cleanAntlr << { delete antlr4.destinationDir } clean.dependsOn cleanAntlr
... or, for additional clarity, use this more verbose, but functionally equivalent task definition:
task cleanAntlr { doLast() { // Be sure to wrap the execution phase code inside doLast(). // Otherwise it will run during the initialization or configuration phase, even when an unrelated task is is run. // It would also run when the NetBeas IDE first loaded the project. //println 'Deleting Antlr Directory: ' + antlr4.destinationDir delete antlr4.destinationDir } } clean.dependsOn cleanAntlr
With that bug fixed, the original outputs specification for the compileAntlrGrammars task works correctly. There is no need to specify each individual output file. This is explained quite well in section 15.9.2 of https://gradle.org/docs/current/userguide/more_about_tasks.html.
def grammars = fileTree(antlr4.antlrSource).include('**/*.g4') def target = file("${antlr4.destinationDir}") inputs.files grammars outputs.dir target
这篇关于如何声明渐变Antlr任务输出规格以避免不必要的重建的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!