Skip to content

Generate JPMS modules #406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions build-logic/src/main/kotlin/MultiReleaseJarUtils.kt
Original file line number Diff line number Diff line change
@@ -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<String> = listOf(
"--module-path", modulePath.asPath,
"--patch-module", "$moduleName=${moduleFiles.asPath}",
"--release", "9"
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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() {
Expand Down
6 changes: 6 additions & 0 deletions bytestring/jvm/module/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module kotlinx.io.bytestring {
requires transitive kotlin.stdlib;

exports kotlinx.io.bytestring;
exports kotlinx.io.bytestring.unsafe;
}
8 changes: 8 additions & 0 deletions core/jvm/module/module-info.java
Original file line number Diff line number Diff line change
@@ -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;
}
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down