【问题标题】:Adding a runtime dependency on a generated source set in Gradle在 Gradle 中添加对生成的源集的运行时依赖项
【发布时间】:2019-12-19 18:05:31
【问题描述】:

我想创建一个项目,其构建过程包括一些代码生成。生成的代码在编译时依赖于主代码(它扩展了一个公共基类)和来自 JCenter 的模块。主代码实际上对生成的代码具有运行时依赖性;也许更正确的说法是应用程序对主代码和生成代码以及两者的模块依赖项都有运行时依赖。

编辑:为了使依赖关系更清晰,这是一个伪劣的图表,其中箭头从配置指向它所依赖的东西。如您所见,依赖图中没有循环。

main compile ← generated compile → generated module
      ↑                ↑
main runtime → generated runtime

我真的很想将生成的代码放在主代码的单独源集中。我也很想用应用插件,提供gradle rungradle installDist

我使用的是最新的 Gradle 3.3。

我创建了一个project to try this。其中,源集是:

sourceSets {
    generated {
        java {
            srcDirs = ["$buildDir/src/generated/java"]
            compileClasspath += sourceSets.main.output
        }
    }
    main {
        java {
            runtimeClasspath += sourceSets.generated.output + sourceSets.generated.runtimeClasspath
        }
    }
}

还有一个任务是生成代码:

task generateSource {
    doLast {
        // generate the code into sourceSets.generated.java.srcDirs[0] here
    }
}

compileGeneratedJava.dependsOn generateSource

生成的代码的生成和编译工作正常。如果我说gradle generatedClasses,它会编译主代码,生成源代码,然后编译生成的代码。

但是,运行和分发都不能正常工作。如果我说gradle run,它不会尝试生成或编译生成的代码。如果我说gradle generatedClasses run,那么生成的代码会生成并编译,但不会添加到已执行 Java 进程的类路径中。如果我说gradle installDist,那么它不会尝试生成或编译生成的代码,同样,如果我说gradle generatedClasses installDist,生成的代码会生成并编译,但不包含在分发中。

生成的源集的模块依赖也不包含在类路径或分发中。

真正奇怪的是,如果我用自己的运行任务版本定义:

task runProperly(type: JavaExec) {
    classpath = sourceSets.main.runtimeClasspath
    main = mainClassName
}

效果很好!

那么,为什么编译的类和生成的源集的模块依赖项都没有包含在运行或分发类路径中?

【问题讨论】:

    标签: gradle code-generation


    【解决方案1】:

    因为application 插件在您更改源集之前已经设置了类路径。如果您在sourcesets {} 之后移动apply plugin: 'application',则构建将按预期工作。

    但在我看来,sourceset 不是生成代码的正确位置。您的构建应如下所示:

    apply plugin: 'application'
    
    repositories {
        jcenter()
    }
    
    dependencies {
        compile group: 'org.fusesource.jansi', name: 'jansi', version: '1.14'
        compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.22'
        runtime group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.9'
    }
    
    mainClassName = 'Application'
    
    task generateSources {
      outputs.dir temporaryDir
    
      doLast {
        // Generate some code into temporaryDir
      }
    }
    
    compileJava {
      source generateSources
    }
    

    【讨论】:

    • 在源集定义之后移动插件应用程序确实使gradle run 正常工作,谢谢!但它不会使gradle installDist 工作 - 生成的代码及其依赖项都不包含在分发中。
    • 我非常热衷于将生成的源代码保存在单独的源代码集中,因为这样它就可以拥有自己的依赖项。生成的代码使用了一些普通代码不应使用的特殊库,因此出于卫生考虑,我想将它们分开。这并不重要,但会很有用。
    • 代码中有交叉引用。所以,你不能只在main 中编译一个类,然后在generated 中编译一个类,然后再在main 中编译。生成的代码无论如何都会使用main的类路径。
    • 依赖图中没有循环 - 我在问题中添加了一个(差)图表。无需重新编译main。唯一缺少的是对生成的代码有运行时依赖的主代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-21
    • 1970-01-01
    • 1970-01-01
    • 2019-05-14
    • 1970-01-01
    相关资源
    最近更新 更多