Kotlin 多项目项目设置

问题描述 投票:0回答:1

我在设置 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} 中的所有类。具体来说,我想将 JUnit 的 ConsoleLauncher 包含在我的测试 jar 中,因此我在 jvmTest 源集中添加了对实现(“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 代码,也许这是一个单独的问题......

kotlin gradle multiplatform
1个回答
0
投票

Gradle 和 Kotlin 插件

Gradle 是一个强大的构建工具,你需要的一切都在那里,但有时可能需要一些挖掘。实际上,您必须查看 Kotlin Gradle 插件的代码,了解它是如何组合在一起的,并按照您想要的方式编写额外的任务。

在 Kotlin 多平台项目中,所有配置都位于 Kotlin 多平台扩展 上,可以使用 build.gradle.kts 文件中的

kotlin
进行访问。此扩展是所有 Kotlin 多平台配置所在的中心位置,您想要的所有内容都应该位于该对象中的某个位置。

Kotlin 源集

另外,当我创建单独的gradle任务时,似乎没有找到与kotlin插件相同的sourceSets。

简短的答案是:当您在 build.gradle.kts 文件中使用顶级

sourceSets
访问器时,您正在访问 Java 源集,而不是 Kotlin 源集。

你可能知道,Gradle 的初衷是作为 Java 程序的构建工具,Gradle 提供了一系列专为 Java 程序设计的插件,例如 Java 插件,这些插件遵循众所周知的约定。

当 Kotlin 多平台插件具有 JVM 目标时,它会应用 Java 基础插件 来利用其中一些约定。但 Kotlin 多平台还建立了自己的源集和编译并行系统,一般来说,这些应该用于编写额外的任务。

您可以像这样访问 Kotlin 扩展中的 Kotlin 源集(就像配置项目时所做的那样):

kotlin {
   sourceSets {
      // Configure source sets
   }
}

生成 JAR 文件

有没有办法用gradle任务生成jar?

绝对有。这种任务确实是 Gradle 的raison d'être

你说得对,默认情况下不会创建测试 JAR。但是您可以通过编写

Jar
(docs) 类型的任务来创建任何您想要的 jar,就像您已经开始做的那样。

在 Kotlin 中你可以这样写:

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

向 JAR 添加依赖项

具体来说,我想将 JUnit 的 ConsoleLauncher 包含在我的测试 jar 中

您很快还会发现默认情况下依赖项不会打包到 JAR 中。事实上,这是不鼓励的,因为一般来说,获取所需的任何依赖项是 JAR 使用者的工作。但肯定有一些充分的理由将依赖项打包到所谓的影子或胖 JAR 中。

这个答案已经太长了,所以我不会向您建议任何更多代码,但您可以开始在 Gradle 文档 中阅读更多内容。请务必选择 Kotlin 编译输出,而不是 Java 插件输出。

您可能还想查看 configurations,这是 Gradle 对依赖项进行分组的方式(以便控制哪些依赖项组进入您的 JAR,哪些不进入您的 JAR)。

© www.soinside.com 2019 - 2024. All rights reserved.