我在设置 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 代码,也许这是一个单独的问题......
Gradle 是一个强大的构建工具,你需要的一切都在那里,但有时可能需要一些挖掘。实际上,您必须查看 Kotlin Gradle 插件的代码,了解它是如何组合在一起的,并按照您想要的方式编写额外的任务。
在 Kotlin 多平台项目中,所有配置都位于 Kotlin 多平台扩展 上,可以使用 build.gradle.kts 文件中的
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
}
}
有没有办法用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
}
具体来说,我想将 JUnit 的 ConsoleLauncher 包含在我的测试 jar 中
您很快还会发现默认情况下依赖项不会打包到 JAR 中。事实上,这是不鼓励的,因为一般来说,获取所需的任何依赖项是 JAR 使用者的工作。但肯定有一些充分的理由将依赖项打包到所谓的影子或胖 JAR 中。
这个答案已经太长了,所以我不会向您建议任何更多代码,但您可以开始在 Gradle 文档 中阅读更多内容。请务必选择 Kotlin 编译输出,而不是 Java 插件输出。
您可能还想查看 configurations,这是 Gradle 对依赖项进行分组的方式(以便控制哪些依赖项组进入您的 JAR,哪些不进入您的 JAR)。