gradle Kotlin多项目设置

0wi1tuuw  于 4个月前  发布在  Kotlin
关注(0)|答案(1)|浏览(56)

我在设置我的Kotlin多项目项目时遇到了困难。我已经花了几个小时阅读文档,但我觉得我毫无进展。也许这里有人可以帮助我,告诉我如何调整我的构建脚本。
我的项目设置是(或应该是):

root
|-> src
    |-> commonMain
        |-> kotlin
    |-> commonTest
        |-> kotlin
    |-> jvmMain
        |-> kotlin
    |-> jvmTest
        |-> kotlin
    |-> nativeMain
        |-> kotlin
        |-> cpp
    |-> nativeTest
        |-> kotlin
        |-> cpp

字符串
nativeMain和nativeTest下名为“cpp”的目录将包含用c++编写的其他平台特定代码,这些代码将取决于Kotlin/Native生成的C库。
目前,我正在尝试实现以下目标:生成一个jar文件,其中包含{commonMain,commonTest,jvmMain,jvmTest}中的所有类。具体来说,我想在我的test-jar中包含JUnit的ConsoleLauncher,因此我在jvmTest sourceSet中添加了对实现的依赖(“org.junit.platform:junit-platform-console-standalone:1.10.1”)。
运行gradle任务jvmTest成功启动了我的所有测试,但它没有生成jar文件(显然,至少我找不到它)。有没有一种方法可以用gradle任务生成jar?
下面是我的build.gradle.kts脚本:

plugins {
    java
    id("java-library")
    kotlin("multiplatform") version "1.9.20"
}

repositories {
    mavenCentral()
}

dependencies {
    implementation(kotlin("stdlib"))
}

kotlin {

    jvm("jvm") {
        compilations.all {
            kotlinOptions {
                jvmTarget = "17"
            }
        }
    }

    linuxX64("linux")
    mingwX64("windows")

    targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
        binaries {
            sharedLib {
                baseName = if(name == "windows") "libnative" else "native"
            }
        }
    }

    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation(kotlin("stdlib"))
                implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.6")
                implementation("org.junit.platform:junit-platform-console-standalone:1.10.1")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
            }
        }
        val windowsMain by getting {
            dependsOn(sourceSets["commonMain"])
        }
        val windowsTest by getting {
            dependsOn(sourceSets["commonTest"])
        }
        val linuxMain by getting {
            dependsOn(sourceSets["commonMain"])
        }
        val linuxTest by getting {
            dependsOn(sourceSets["commonTest"])
            dependencies {
                implementation(kotlin("test"))
            }
        }
        val jvmMain by getting {
            dependsOn(sourceSets["commonMain"])
        }
        val jvmTest by getting {
            dependsOn(sourceSets["commonTest"])
            dependencies {
                implementation("org.junit.platform:junit-platform-console-standalone:1.10.1")

                implementation(kotlin("test"))
                implementation(kotlin("test-junit5"))

                // needed by IDEA?
                implementation("org.junit.jupiter:junit-jupiter-engine:5.10.1")
                implementation("org.junit.jupiter:junit-jupiter-params:5.10.1")
                implementation("org.junit.jupiter:junit-jupiter-api:5.10.1")
            }
        }
    }
}

tasks.withType<Wrapper> {
    gradleVersion = "8.4"
    distributionType = Wrapper.DistributionType.ALL
}

tasks.named<Test>("jvmTest") {
    useJUnitPlatform()
    filter {
        isFailOnNoMatchingTests = false
    }
    testLogging {
        showExceptions = true
        showStandardStreams = true
        events = setOf(
            org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED,
            //org.gradle.api.tasks.testing.logging.TestLogEvent.PASSED,
            org.gradle.api.tasks.testing.logging.TestLogEvent.SKIPPED
        )
        exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
        afterSuite(
            KotlinClosure2({
                desc: TestDescriptor, result: TestResult ->
                    if (desc.parent == null) {
                        // Only execute on the outermost suite
                        val color = if(result.resultType == TestResult.ResultType.SUCCESS) Colors.green else Colors.red
                        val reset = Colors.reset

                        println("")
                        println(" **** Result: $color ${result.resultType} $reset ****")
                        println("  >    Tests: ${result.testCount}")
                        println("  >   Passed: ${result.successfulTestCount}")
                        println("  >   Failed: ${result.failedTestCount}")
                        println("  >  Skipped: ${result.skippedTestCount}")
                    }
            })
        )
    }
}


此外,当我创建一个单独的gradle任务时,它似乎找不到与Kotlin插件相同的sourceSets。在这个gradle任务中,我只看到sourceSets“main”和“test”,(我想)它们不包含任何代码:

tasks.register("printSourceSetsInfo") {
    doLast {
        sourceSets.all { sourceSet ->
            println("Source set: ${sourceSet.name}")
            println("   - Output directory: ${sourceSet.output}")
            println("   - Source directories: ${sourceSet.allSource.srcDirs}")
            println("   - Resources directories: ${sourceSet.resources.srcDirs}")
            println("   - Compile classpath: ${sourceSet.compileClasspath}")
            println("   - Runtime classpath: ${sourceSet.runtimeClasspath}")
            println()
           true
        }
    }
}

tasks.register("packageTests", Jar::class) {
    val jvmTestSourceSet = sourceSets.findByName("jvmTest") ?: sourceSets.findByName("testJvm") ?: sourceSets.findByName("test")

    if (jvmTestSourceSet != null) {
        from(jvmTestSourceSet.output)
       archiveFileName = "acteo-kotlin-tests.jar"
       destinationDirectory = file("build/libs/")
    } else {
       println("JVM test source set not found. Check your project configuration.")
       println("Available source sets: ${sourceSets.names.joinToString(", ")}")
        //throw GradleException("JVM test source set not found")
    }
}


我觉得这很奇怪/令人困惑,我想知道,我将如何设置特定的任务来在某个阶段生成我的cpp代码(因为我需要在专用的cpp块中访问源代码集,而不是Kotlin块)。也许有人可以给我一个提示,以及给予?但也许这是一个单独的问题,一旦我到了编写额外的cpp代码的地步。

fsi0uk1n

fsi0uk1n1#

Gradle和Kotlin插件

Gradle是一个功能强大的构建工具,你需要的一切都在那里,但有时需要一点挖掘。实际上,你必须查看KotlinGradle插件的代码,看看它是如何组合在一起的,并按照你想要的方式编写额外的任务。
在Kotlin多平台项目中,所有配置都位于Kotlin multiplatform extension上,可以使用build.gradle.kts文件中的kotlin进行访问。该扩展是所有Kotlin多平台配置所在的中心位置,您想要的一切都应该在该对象中的某个位置。

Kotlin源集

此外,当我创建一个单独的gradle任务时,它似乎找不到与Kotlin插件相同的sourceSets。
简短的回答是:当您在build.gradle.kts文件中使用顶级sourceSets访问器时,您访问的是 Java 源集,而不是Kotlin源集。
正如你可能知道的,Gradle的初衷是成为Java程序的构建工具,Gradle提供了一系列为Java程序设计的插件,例如Java插件,它们遵循众所周知的约定。
当一个Kotlin多平台插件有一个JVM目标时,它会应用Java base plugin来利用其中的一些约定。但是Kotlin多平台也会建立自己的源集和编译的并行系统,通常这些应该用于编写额外的任务。
您可以在Kotlin扩展中访问Kotlin源代码集,如下所示(就像您在配置项目时所做的那样):

kotlin {
   sourceSets {
      // Configure source sets
   }
}

字符串

生成文件

有没有一种方法可以用gradle任务生成jar?
当然有。这种任务确实是Gradle存在的理由。
你是对的,测试任务在默认情况下是不会创建的,但是你可以通过编写一个Jardocs)类型的任务来创建任何你想要的任务,就像你开始做的那样。
在Kotlin中,你可以这样写:

tasks.register<Jar>("createTestJar") {
   archiveClassifier.set("test")
   from(kotlin.jvm().compilations.get("test").output)
}

添加依赖关系到一个示例

具体来说,我想在我的测试jar中包括JUnit的ConsoleLauncher
你很快就会发现,依赖项在默认情况下不会打包到一个包中。事实上,这是不鼓励的,因为一般来说,获取所需的依赖项是包的消费者的工作。但是,当然有一些很好的理由将依赖项打包到所谓的影子或胖包中。
这个答案已经太长了,所以我不会再建议你写更多的代码,但你可以开始阅读Gradle文档中的更多内容。只是要确保选择Kotlin编译输出,而不是Java插件。
您可能还想查看Gradle对依赖项进行分组的配置(以便控制哪些依赖项组进入您的队列,哪些不进入)。

相关问题