Vampire
07/17/2023, 2:25 PM--release
for the KotlinCompile
task and / or set the Java Toolchain for a specific KotlinCompile
task like for Java-centric tasks like JavaCompile
?
I tried to provide a better and future-proof solution for #2218 of kotlinx.serialization
(https://github.com/Kotlin/kotlinx.serialization/issues/2218).
For that I set the java { toolchain { ... } }
to Java 8 and just set the specific JavaCompile
task that compiles the module-info.java
file to Java 11 toolchain with --release 9
. (Because there is no Java 9 toolchain for certain macOS architectures.
But the consequence of this is, that the KotlinCompile
tasks ignore the module-info.class
files. Before, the KotlinCompile
task considered the module-info.class
files of compile dependencies, so if you for example remove the exports kotlinx.serialization;
from `core`'s module-info.java
, the compilation of formats/json
failed due to the missing exports
in core
. Now as Java 8 is used as toolchain, the module-info.class
of core
is ignored and the compilation succeeds and would then only fail at runtime when using JPMS.
So a solution would probably either need to use a Java 11
toolchain for the KotlinCompile
task, but somehow being able to specify --release 8
, so that the compilation happens against the correct Java 8 API. Alternatively, another KotlinCompile
task would be necessary - for exampled hooked to the check
lifecycle task - that compiles all files again but with Java 11, so that for the real build it compiles against the Java 8 API, but as a verification for the JPMS configuration it is compiled again with Java 11.
Using a Java 11 toolchain with jvmTarget
8 is not a proper solution as that is basically what is done now. Actually in this specific case it would work as the API that has changed here was changed in Java 13. But there might be other cases now or in the future, so it should really compile against the proper Java 8 API like the --release
option is doing for JavaCompile
.Sam
07/17/2023, 2:34 PM-Xjdk-release
option; does that help? https://kotlinlang.org/docs/compiler-reference.html#xjdk-release-versionVampire
07/17/2023, 2:35 PMfreeCompilerArgs
, thanks.Vampire
07/17/2023, 4:18 PM--release
, but unfortunately not sufficiently.
If I add that arg to the current build setup, core
does not compile anymore as it says maaaany symbols declared in module kotlin.stdlib
which is not depended on and unnamed module which is not read.
And if I add it to the setup I changed it to, changing the toolcahin to 11 (or 17 to eventually reproduce the problematic outcome) and setting jvmTarget
and -Xjdk-release
to 1.8
, now produces the intended bytecode, but still does does not complain about the module-info problem πmbonnin
07/18/2023, 10:09 AMVampire
07/18/2023, 10:12 AMVampire
07/18/2023, 10:24 AMmbonnin
07/18/2023, 10:24 AMkotlin {
jvm("java11")
jvm("java8")
}
tasks.withType<KotlinJvmCompile>().configureEach {
if (name.contains("Java8")) {
compilerOptions.jvmTarget.set(JvmTarget.JVM_1_8)
} else {
compilerOptions.jvmTarget.set(JvmTarget.JVM_11)
}
}
This works for membonnin
07/18/2023, 10:25 AMVampire
07/18/2023, 10:26 AMVampire
07/18/2023, 10:26 AMtapchicoma
07/18/2023, 10:29 AMKotlinApiPlugin
plugin which exposes methods to create KotlinJvmCompile
taskVampire
07/18/2023, 6:12 PMProject#plugins
shouldn't be used?
apply<KotlinBaseApiPlugin>()
val verifyModuleTaskName = "verify${compileModuleTaskName.removePrefix("compile").capitalize()}"
val verifyModuleTask = plugins.findPlugin(KotlinBaseApiPlugin::class)!!.registerKotlinJvmCompileTask(verifyModuleTaskName)
verifyModuleTask {
group = VERIFICATION_GROUP
libraries.from(compileKotlinTask.libraries)
source(compileKotlinTask.sources)
source(moduleInfoSourceFile)
kotlinOptions {
jvmTarget = "9"
freeCompilerArgs += "-Xjdk-release=9"
}
}
tasks.named("check") {
dependsOn(verifyModuleTask)
}
Besides that it complains about missing value of ownModuleName
.
So assuming above might be correct, what else would I need to set for it to get it going?tapchicoma
07/18/2023, 6:36 PMcompileKotlinTask
compilerOptions.moduleName
(ownModuleName
could be the same as moduleName
)Vampire
07/18/2023, 6:37 PMVampire
07/18/2023, 6:37 PMmoduleName.set(verifyModuleTaskName)
, but that didn't make the error go awayVampire
07/18/2023, 6:38 PMmoduleName.set(compileKotlinTask.moduleName)
also does not helpVampire
07/18/2023, 6:39 PMVampire
07/18/2023, 6:40 PMkotlinOptions {
moduleName = compileKotlinTask.moduleName.get()
}
also does not change a thingtapchicoma
07/18/2023, 6:43 PMownModuleName.set(compileKotlinTask.compilerOptions.moduleName)
tapchicoma
07/18/2023, 6:44 PMKotlinJvmTask.moduleName
is deprecated in favor of KotlinJvmTask.compilerOptions.moduleName
Vampire
07/18/2023, 6:44 PMownModuleName
, neither on the task, nor the optionstapchicoma
07/19/2023, 8:06 AMVampire
07/19/2023, 8:07 AMVampire
07/19/2023, 8:08 AMVampire
07/19/2023, 8:08 AMtapchicoma
07/19/2023, 8:09 AMtapchicoma
07/19/2023, 8:12 AMownModuleName
is not a part of public api in KotlinJvmCompile
task. Unfortunately in this case you need to fallback to use our internal org.jetbrains.kotlin.gradle.tasks.KotlinCompile
implementationVampire
07/19/2023, 8:16 AMtapchicoma
07/19/2023, 8:17 AMownModuleName
is scheduled to be removed in 2.0. Though this is good point that created task could not be used as is. Could you open an issue?Vampire
07/19/2023, 8:55 AMVampire
07/19/2023, 9:04 AMVampire
07/19/2023, 2:22 PMapply<KotlinBaseApiPlugin>()
val verifyModuleTaskName = "verify${compileModuleTaskName.removePrefix("compile").capitalize()}"
val verifyModuleTask = plugins.findPlugin(KotlinBaseApiPlugin::class)!!.registerKotlinJvmCompileTask(verifyModuleTaskName)
verifyModuleTask {
group = VERIFICATION_GROUP
libraries.from(compileKotlinTask.libraries)
source(compileKotlinTask.sources)
source(sourceFile)
destinationDirectory.set(temporaryDir)
moduleName.set(compileKotlinTask.moduleName)
multiPlatformEnabled.set(compileKotlinTask.multiPlatformEnabled)
kotlinOptions {
jvmTarget = "9"
freeCompilerArgs += "-Xjdk-release=9"
}
this as KotlinCompile
ownModuleName.set(compileKotlinTask.moduleName)
}
tasks.named("check") {
dependsOn(verifyModuleTask)
}
And if yes, how do I make it work? π
Because now I get several
e: file///.../kotlinx.serialization/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt69:6 Declaration annotated with '@OptionalExpectation' can only be used in common module sourcesComparing the `--info`output of
compileKotlinTask
and verifyKotlinJvmModule
suggests they are compiling the same files, except for the additional module info file.Vampire
07/19/2023, 2:23 PMtapchicoma
07/19/2023, 2:32 PMVampire
07/19/2023, 2:33 PMVampire
07/19/2023, 2:33 PMtapchicoma
07/19/2023, 2:44 PMinternal
.... So following hack may work:
verifyModuleTask {
@Suppress("INVISIBLE_MEMBER")
commonSourceSet.from(compileKotlinTask.commonSourceSet)
multiplatformEnabled.set(true)
}
Vampire
07/19/2023, 2:58 PMapply<KotlinBaseApiPlugin>()
val verifyModuleTaskName = "verify${compileModuleTaskName.removePrefix("compile").capitalize()}"
val verifyModuleTask = plugins.findPlugin(KotlinBaseApiPlugin::class)!!.registerKotlinJvmCompileTask(verifyModuleTaskName)
verifyModuleTask {
group = VERIFICATION_GROUP
libraries.from(compileKotlinTask.libraries)
source(compileKotlinTask.sources)
source(sourceFile)
destinationDirectory.set(temporaryDir)
moduleName.set(compileKotlinTask.moduleName)
multiPlatformEnabled.set(compileKotlinTask.multiPlatformEnabled)
kotlinOptions {
jvmTarget = "9"
freeCompilerArgs += "-Xjdk-release=9"
}
this as KotlinCompile
ownModuleName.set(compileKotlinTask.moduleName)
@Suppress("INVISIBLE_MEMBER")
commonSourceSet.from(compileKotlinTask.commonSourceSet)
}
tasks.named("check") {
dependsOn(verifyModuleTask)
}
It detects if I remove exports kotlinx.serialization;
from core
and it detects if I remove requires transitive kotlinx.serialization.core;
from formats/json
.Vampire
07/19/2023, 2:58 PMinternal
at will πVampire
07/19/2023, 3:06 PMcommonSourceSet
requirement be a separate issue, is it intended, or can it be considered part of KT-60541?tapchicoma
07/19/2023, 3:07 PMVampire
07/19/2023, 3:10 PMVampire
07/19/2023, 3:10 PMVampire
07/19/2023, 3:16 PMVampire
07/19/2023, 3:30 PMVampire
07/19/2023, 3:36 PMtapchicoma
07/19/2023, 3:57 PMkotlin-android
plugin. We will consider fixing it πVampire
07/19/2023, 9:00 PMtapchicoma
07/20/2023, 8:28 AMKotlinCompile.incremental = false
Vampire
07/20/2023, 8:35 AMVampire
07/20/2023, 9:22 AMincremental
, just changing `core`'s module-info.java
does not make the task out-of-date, it stays UP-TO-DATE
and only forcing --rerun
makes it run and fail accordingly.
And with incremental, just changing `format/json`'s module-info.java
, the task does execute, but does not fail although it should, due to the incrementality. Using --rerun
again makes the task run non-incrementally and fail properl.y
So two more bugs I'd say, that changes in the module-info.class
of dependencies does not make the task out-of-date and the task needs to run non-incrementally automatically if the compiled module-info.java
changes. Will create those too.Vampire
07/20/2023, 9:22 AMmodule-info.class
in dependency not making the task out-of-date?tapchicoma
07/20/2023, 9:27 AMtapchicoma
07/20/2023, 9:27 AMDefaultTask
Vampire
07/20/2023, 9:28 AMtapchicoma
07/20/2023, 10:21 AMsource(kotlinCompileTask.javaSources)
so task with track changes in .java
filestapchicoma
07/20/2023, 10:23 AMsource(..)
separate sources into 3 task inputs: sources
(.kt
, .kts
files), javaSources
(.java
files), scriptSources
(custom Kotlin script files)Vampire
07/20/2023, 11:21 AMkotlinCompileTask
in my case does not contain the module-info.java
anyway.
I already add the module-info.java
to the new task as the is the main purpose of the task.
The --info
output also says that the module-info.java
is compiled along.
It just does not make the Kotlin files recompiled when only the module-info.java
changes.
And I would not expect that change to care about the module-info.class
files in the dependencies anyway.Vampire
07/20/2023, 11:22 AMincremental = false
for the incrementality problem and for the module-info.class
in the dependencies
inputs.files(
libraries.asFileTree.elements.map { libs ->
libs
.filter { it.asFile.exists() }
.map {
zipTree(it.asFile).filter { it.name == "module-info.class" }
}
}
).withPropertyName("modularInfosOfLibraries")
Vampire
07/20/2023, 11:23 AMVampire
07/20/2023, 11:25 AMsource(compileKotlinTask.javaSources)
to be sure in case there are other Java files in that source task.
But I don't see compileKotlinTask.scriptSources
Vampire
07/20/2023, 11:26 AMinternal
in KotlinCompile
, so
@Suppress("INVISIBLE_MEMBER")
source(compileKotlinTask.scriptSources)
Vampire
07/20/2023, 1:44 PM