Gradle 5 Kotlin DSL:多模块项目中的常见任务和 Maven 工件

Posted

技术标签:

【中文标题】Gradle 5 Kotlin DSL:多模块项目中的常见任务和 Maven 工件【英文标题】:Gradle 5 Kotlin DSL: Common Tasks & Maven Artifacts in multi-modules projects 【发布时间】:2019-05-06 23:48:06 【问题描述】:

我真的很想感谢 Gradle 5,尤其是与新的 Kotlin DSL 结合使用,但我很难(在我眼中)获得一个使用 Gradle 运行的非常、非常简单和通用的构建。

任务

发布一个 Java 库,其中包含 Maven 默认目录布局中的多个相互依赖的子模块作为高质量的 Maven 工件/存储库 -point,简单的 Gradle 构建(即 DRY)。

因此:有一个根项目作为定义 & 包含所有通用配置(实际上除了真正的依赖项之外的所有配置)的保护伞。

我目前的挣扎

我将当前的“结果”移植到 a sample project on Github 和 asked this question in the Gradle forum already。

目前,我未能声明在我的 central 构建中提供标准 -sources-javadoc 工件的必要任务。

例如,您在寻找基于 Kotlin DSL 的解决方案时会发现这三个“解决方案”在多模块场景中都不起作用(不再)

https://***.com/a/48070667 https://***.com/a/52596969/1237653 甚至官方的"Maven Publish" documentation 也只能在单模块场景中工作。

不完整的解决方案 (/build.gradle.kts)

完整示例见 Github:https://github.com/bentolor/gradle-maven-multimodule-kotlindsl

subprojects 
    apply(plugin = "java-library")
    apply(plugin = "maven-publish")
    group = "de.bentolor.sampleproject"
    version = "0.1.0"

    repositories 
        jcenter()
    

    dependencies 
        // Dependencies used in EVERY module
        "compile"("commons-logging:commons-logging:1.2")
        "testImplementation"("junit:junit:4.12")
    

    tasks 
        // not working
        /*register("sourcesJar", Jar::class.java) 
            from(sourceSets.main.get().allJava)
            classifier = "sources"
        */

       // not working, eiher
       /* task<Jar>("sourcesJar") 
            from(sourceSets.main.get().allJava)
            classifier = "sources"
        */
    

    configure<JavaPluginExtension> 
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    

    configure<PublishingExtension> 
        publications 
            create<MavenPublication>(project.name) 
                from(components["java"])
                // won't work, beause inaccessible declaration in `tasks`-Block
                //add("archives", javadocJar)
                //add("archives", sourcesJar)
            
        

        repositories 
            mavenLocal()
        
    

示例子模块/module2/build.gradle.kts

group = "de.bentolor.sampleproject.module2"

dependencies 
    compile(project(":module1"))

【问题讨论】:

【参考方案1】:

试试这个:

subprojects 
    apply<JavaLibraryPlugin>()
    apply<MavenPublishPlugin>()

    group = "de.bentolor.sampleproject"
    version = "0.1.0"

    repositories 
        jcenter()
    

    dependencies 
        val implementation by configurations
        val testImplementation by configurations

        implementation("commons-logging:commons-logging:1.2")
        testImplementation("junit:junit:4.12")
    

    // This will work, but as long as these tasks are need only for publishing you can declare them inplace later where you need 
    // tasks 
    //     val sourcesJar by creating(Jar::class) 
    //         val sourceSets: SourceSetContainer by project
    //         from(sourceSets["main"].allJava)
    //         classifier = "sources"
    //     
    //     val javadoc by getting(Javadoc::class)
    //     val javadocJar by creating(Jar::class) 
    //         from(javadoc)
    //         classifier = "javadoc"
    //     
    // 

    configure<JavaPluginExtension> 
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    

    configure<PublishingExtension> 
        publications 
            create<MavenPublication>(project.name) 
                from(components["java"])

                // If you configured them before
                // val sourcesJar by tasks.getting(Jar::class)
                // val javadocJar by tasks.getting(Jar::class)

                val sourcesJar by tasks.creating(Jar::class) 
                    val sourceSets: SourceSetContainer by project

                    from(sourceSets["main"].allJava)
                    classifier = "sources"
                
                val javadocJar by tasks.creating(Jar::class) 
                    from(tasks.get("javadoc"))
                    classifier = "javadoc"
                

                artifact(sourcesJar)
                artifact(javadocJar)
            
        
    

几点说明:

既然可以使用类型安全的apply&lt;T&gt;(),为什么还要使用基于Stringapply? 为什么要在 dependencies 中对 stings 使用调用,而您可以使用委托,这样可以减少 hacky 并更好地重构。 考虑使用implementation instead of compile

为什么sourceSets 在多模块项目中不起作用?

当您使用 Kotlin DSL 时,它会根据应用的插件为项目生成访问器。这是一个两步过程:首先 Gradle 处理插件(这就是为什么建议将它们放在 plugins 块中)并生成访问器,然后您可以在代码中使用它们(访问器生成为 Project 的 Kotlin 扩展,@ 987654332@ 等)。但是如果你配置子项目有两个问题:

父项目在子项目之前评估,因此子项目的扩展在父项目中是未知的。 应用于 parent 和 child 的插件集不同,您需要在 parent 中使用 children 访问器。

sourceSets 是 Kotlin DSL 为孩子生成的访问器之一。它只是在父母中不可用。您可以自己尝试:仅在subprojects 中应用java 插件。 sourceSets 将在子构建脚本中可用,但在父脚本中不可用。

这也是为什么您可以在子级中使用java,但在父级中配置时必须使用configure&lt;JavaPluginExtension&gt;

但您可以使用委托来获取域对象的引用,例如任务、源集、配置等。

【讨论】:

以上是关于Gradle 5 Kotlin DSL:多模块项目中的常见任务和 Maven 工件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 gradle 5.0.0 中将 bootRepackage 任务转换为 kotlin DSL?

gradle kotlin dsl:如何创建使用插件类的共享函数?

如何将 Gradle 中的原生 JUnit 5 支持与 Kotlin DSL 结合使用?

使用 Gradle Kotlin DSL 进行集成测试

isCoreLibraryDesugaringEnabled 在 gradle kotlin dsl / kts 中不起作用

如何使用 gradle kotlin-dsl 添加新的源集