diff --git a/build-logic/src/main/kotlin/MultiReleaseJarUtils.kt b/build-logic/src/main/kotlin/MultiReleaseJarUtils.kt new file mode 100644 index 00000000..28628b13 --- /dev/null +++ b/build-logic/src/main/kotlin/MultiReleaseJarUtils.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2017-2024 JetBrains s.r.o. and respective authors and developers. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENCE file. + */ + +package kotlinx.io.build + +import org.gradle.api.Project +import org.gradle.api.file.FileCollection +import org.gradle.api.tasks.SourceSetContainer +import org.gradle.api.tasks.compile.JavaCompile +import org.gradle.jvm.toolchain.JavaLanguageVersion +import org.gradle.jvm.toolchain.JavaToolchainService +import org.gradle.kotlin.dsl.get +import org.gradle.kotlin.dsl.withType +import org.gradle.process.CommandLineArgumentProvider +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation +import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile +import java.util.* + +private val Project.sourceSets: SourceSetContainer + get() = this.extensions.getByName("sourceSets") as SourceSetContainer + +private val Project.javaToolchains: JavaToolchainService + get() = this.extensions.getByName("javaToolchains") as JavaToolchainService + + +/** + * Setup tasks to compile `module-info.java` file for a module named [moduleName] + * from a source set with name [sourceSetName] using Java toolchain with version [toolchainVersion]. + + * It is assumed that source set with [sourceSetName] only extends main JVM source set. + * [parentCompilation] represent a compilation corresponding to such a main source set. + */ +public fun Project.configureJava9ModuleInfoCompilation( + sourceSetName: String, + toolchainVersion: JavaLanguageVersion, + parentCompilation: KotlinJvmCompilation, + moduleName: String +) { + val moduleOutputs = listOf(parentCompilation.output.allOutputs) + val compileClasspathConfiguration = parentCompilation.configurations.compileDependencyConfiguration + val sourceSetNameCapitalized = sourceSetName.replaceFirstChar { it.titlecase(Locale.getDefault()) } + val javaCompileClasspath = configurations["${sourceSetName}CompileClasspath"] + javaCompileClasspath.extendsFrom(compileClasspathConfiguration) + + tasks.named("compile${sourceSetNameCapitalized}Java", JavaCompile::class.java) { + dependsOn(moduleOutputs) + + targetCompatibility = "9" + sourceCompatibility = "9" + + javaCompiler.set( + javaToolchains.compilerFor { + languageVersion.set(toolchainVersion) + } + ) + + val javaSourceSet = sourceSets[sourceSetName].java + destinationDirectory.set( + javaSourceSet.destinationDirectory.asFile.get() + .resolve("META-INF/versions/9") + ) + options.sourcepath = files(javaSourceSet.srcDirs) + val moduleFiles = objects.fileCollection().from(moduleOutputs) + val modulePath = javaCompileClasspath.filter { it !in moduleFiles.files } + dependsOn(modulePath) + classpath = objects.fileCollection().from() + options.compilerArgumentProviders.add( + JigsawArgumentsProvider( + moduleName, + moduleFiles, + modulePath + ) + ) + } +} + +private class JigsawArgumentsProvider( + private val moduleName: String, + private val moduleFiles: FileCollection, + private val modulePath: FileCollection +) : CommandLineArgumentProvider { + override fun asArguments(): Iterable = listOf( + "--module-path", modulePath.asPath, + "--patch-module", "$moduleName=${moduleFiles.asPath}", + "--release", "9" + ) +} diff --git a/build-logic/src/main/kotlin/kotlinx/io/conventions/kotlinx-io-multiplatform.gradle.kts b/build-logic/src/main/kotlin/kotlinx/io/conventions/kotlinx-io-multiplatform.gradle.kts index 5ac3098b..86efa514 100644 --- a/build-logic/src/main/kotlin/kotlinx/io/conventions/kotlinx-io-multiplatform.gradle.kts +++ b/build-logic/src/main/kotlin/kotlinx/io/conventions/kotlinx-io-multiplatform.gradle.kts @@ -3,6 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENCE file. */ +import kotlinx.io.build.configureJava9ModuleInfoCompilation import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet @@ -41,6 +42,20 @@ kotlin { } } } + + val mrjToolchain = versionCatalog.findVersion("multi.release.toolchain").getOrNull()?.requiredVersion + ?: throw GradleException("Version 'multi.release.toolchain' is not specified in the version catalog") + + // N.B.: it seems like modules don't work well with "regular" multi-release compilation, + // so if we need to compile some Kotlin classes for a specific JDK release, a separate compilation is needed. + configureJava9ModuleInfoCompilation( + sourceSetName = project.sourceSets.create("java9ModuleInfo") { + java.srcDir("jvm/module") + }.name, + parentCompilation = compilations.getByName("main"), + moduleName = project.name.replace("-", "."), + toolchainVersion = JavaLanguageVersion.of(mrjToolchain) + ) } js { @@ -104,6 +119,15 @@ kotlin { } } } + + tasks { + val jvmJar by existing(Jar::class) { + manifest { + attributes("Multi-Release" to true) + } + from(project.sourceSets["java9ModuleInfo"].output) + } + } } fun KotlinSourceSet.configureSourceSet() { diff --git a/bytestring/jvm/module/module-info.java b/bytestring/jvm/module/module-info.java new file mode 100644 index 00000000..9fef9fb3 --- /dev/null +++ b/bytestring/jvm/module/module-info.java @@ -0,0 +1,6 @@ +module kotlinx.io.bytestring { + requires transitive kotlin.stdlib; + + exports kotlinx.io.bytestring; + exports kotlinx.io.bytestring.unsafe; +} diff --git a/core/jvm/module/module-info.java b/core/jvm/module/module-info.java new file mode 100644 index 00000000..3ff9848a --- /dev/null +++ b/core/jvm/module/module-info.java @@ -0,0 +1,8 @@ +module kotlinx.io.core { + requires transitive kotlin.stdlib; + requires transitive kotlinx.io.bytestring; + + exports kotlinx.io; + exports kotlinx.io.files; + exports kotlinx.io.unsafe; +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a26422f1..0b4360ee 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,7 @@ [versions] kotlin = "2.0.0" java = "8" +multi-release-toolchain = "17" dokka = "1.9.20" kover = "0.8.2" bcv = "0.16.3"