-
Notifications
You must be signed in to change notification settings - Fork 624
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
Add explicit module-info's for JPMS compatability #1624
Conversation
After some more testing I observed that the Kotlin compiler does not check if the correct To circumvent this problem altogether I took an alternative route where the
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it would be ok to use jdeps once to find the dependencies of a module, but after that the resulting module-info file should be committed in the repository and maintained manually in order to have control on what is being exported.
"--release", "9", | ||
"--module-path", compileKotlinJvm.classpath.asPath, | ||
"--patch-module", "$moduleName=${compileKotlinJvm.destinationDir}", | ||
"-Xlint:-requires-transitive-automatic" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will fail (as expected) when running build on JDK 8. Do we have a manual about setting up the environment for building kotlinx.serialization? It may need a note about required JDKs and their location.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, good point. Is that something I should add to the README?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I figured docs/building.md
would be the correct place.
An alternative would be to only configure the compilation task of the module-info
if the JDK is version 9 or higher.
Maybe with a warning that the resulting JAR is not JPMS compatible due to the used JDK?
I could add the resulting |
AFAIK, |
Is it possible to go with a similar to binary compatibility validator and apiCheck approach? I.e. add two tasks:
|
But it seems that we anyway have to use Java 9 to compile module-info.java even if it is committed to the repository? Or it can be simply ignored by JDK 8 |
My mistake, As for the required JDK: to compile the module-info file you would need at least JDK 9. But since the module-info file is compiled separately you could choose to skip the compilation completely instead of throwing an exception. Of course the resulting JAR would not work with the Java 9 module system if that direction is chosen. My personal preference would be to make JDK 9+ mandatory for building (but not for running) Kotlin serialization. To support older JVM runtimes the compiled |
I do like the idea of having a separate moduleInfoCheck task that visually shows the repository version of the module-info vs a generated one. I think this is actually the purpose of jdeps 'check' command, I'll do a bit of research there. |
Per your suggestions I reworked my branch so it now has the (generated) For checking the contents of the This is the output when the contents of the
And this is the output when the contents of the
|
dependsOn(outputJarTask) | ||
doLast { | ||
val jdeps = ToolProvider.findFirst("jdeps").orElseThrow { IllegalStateException("Tool 'jdeps' is not available") } | ||
jdeps.run( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice if we could detect if jdeps
reports different dependencies from the current module-info and fail the task. This is needed to check automatically on CI that no new dependencies are accidentally introduced.
However, this may block us from removing some dependencies manually
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also don't see task to 'write' module-info. But from your comment I assume the same CheckModuleInfo
task can be invoked and results copied from console, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To automatically check differences I could capture the (console) output that comes from jdeps
and throw an exception if something along the lines of [Suggested module descriptor for xxx]
is in the output. If you remove dependencies you would need to remove the appropriate requires
line from the module-info too, which I believe to be the desired effect.
For 'writing' the module-info you would indeed need to copy the suggested module-descriptor manually from the console output into the repository version of the module-info.
@@ -0,0 +1,7 @@ | |||
module kotlinx.serialization.json { | |||
requires transitive kotlin.stdlib; | |||
requires transitive kotlinx.serialization.core; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although json definitely uses some things from kotlinx.serialization.internal
package, it isn't mentioned in 'requires' here. Can this cause issues?
If not, I'd prefer removing exports kotlinx.serialization.*.internal
compiletely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line requires the kotlinx.serialization.core
module, not the package. Since the kotlinx.serialization.core
module exports the kotlinx.serialization.internal
package it can be used by kotlinx.serialization.json
.
As an alternative, we could export kotlinx.serialization.internal
to only the format modules.
I reworked the whole modularity configuration a bit. It now also supports 'regular' Kotlin projects such as the A nice side-effect of the dedicated Lastly, I couldn't remove the export of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me (modulo comments). I'm still not sure whether need to put module-info in a separate compilation (as in previous version) or just as a separate task (current), but it seems it doesn't matter much
NB: I've changed base branch to |
I rebased my branch on |
It looks like module-info.java in the main source set causes issues in binary compatibility validator: Kotlin/binary-compatibility-validator#68 So I think I'll merge this after that issue would be resolved |
I've checked resulting jars — it has |
I noticed that version 0.7.1 of the binary compatibility validator just came available on Maven central, so I updated the version accordingly. The build succeeds locally now 😄 |
Many thanks for your efforts! |
You're welcome. I'm planning to create a PR for |
@lion7 Have you opened the project jvmMain souceset in the IDE? I'm now experiencing problems with it: https://youtrack.jetbrains.com/issue/KTIJ-19614 |
Follow up is in #1665 |
In this pull request I added a few
module-info.java
files so thekotlinx.serialization
library can be used in Java JPMS (Jigsaw) projects. I also extended the rootbuild.gradle
script so that the appropriate subprojects do a separate compilation of themodule-info.java
file.To maintain backwards compatibility with Java 8, I marked the resulting JAR as a multi-release JAR with the
module-info.class
moved toMETA-INF/versions/9/module-info.class
which is similar as how it's done in the Kotlin stdlib. See https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/jdk8/build.gradle#L80, https://github.com/JetBrains/kotlin/blob/master/buildSrc/src/main/kotlin/LibrariesCommon.kt#L22 and https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/jdk8/java9/module-info.java for more details.Note that moving the
module-info.class
was / is not really necessary for JPMS to work, but I believe it's a bit cleaner than just adding the compiledmodule-info.class
to the root of the JAR.This change allows bundling projects using
jlink
, such as requested in #940.jlink
requires that all dependencies are explicit JPMS (Jigsaw) modules. That means all JAR's must contain amodule-info.class
, automatic modules don't work withjlink
.In 1 of my own projects I am trying to bundle an OpenJFX / TornadoFX application, which currently works using a SNAPSHOT version of this branch.
Note that at least JDK 9 is needed to build this branch (for compiling the
module-info.java
file). Existing code can of course be compiled using a Java 8 target.