Skip to content
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

JlinkPlugin: restrict linking to platform modules #1248

Merged
merged 3 commits into from
Jul 12, 2019
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
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,30 @@ object JlinkPlugin extends AutoPlugin {
sys.error("Missing package dependencies")
}

// Collect all the found modules
deps.collect {
val detectedModuleDeps = deps.collect {
case PackageDependency(_, _, PackageDependency.Module(module)) =>
module
}.distinct
}.toSet

// Some JakartaEE artifacts use `java.*` module names, even though
// they are not a part of the platform anymore.
// https://github.com/eclipse-ee4j/ee4j/issues/34
// This requires special handling on our part when deciding if the module
// is a part of the platform or not.
// At least the new modules shouldn't be doing this...
val knownJakartaJavaModules = Set("java.xml.bind", "java.xml.soap", "java.ws.rs")

val filteredModuleDeps = detectedModuleDeps
.filter { m =>
m.startsWith("jdk.") || m.startsWith("java.")
}
.filterNot(knownJakartaJavaModules.contains)

// We always want `java.base`, and `jlink` requires at least one module.
(filteredModuleDeps + "java.base").toSeq
},
// No external modules by default: see #1247.
jlinkModulePath := (jlinkModulePath ?? Nil).value,
jlinkModulePath ++= {
fullClasspath.in(jlinkBuildImage).value.map(_.data)
},
jlinkOptions := (jlinkOptions ?? Nil).value,
jlinkOptions ++= {
val modules = jlinkModules.value
Expand Down Expand Up @@ -186,20 +200,16 @@ object JlinkPlugin extends AutoPlugin {
}

private object JlinkOptions {
@deprecated("1.3.24", "")
def apply(addModules: Seq[String] = Nil, output: Option[File] = None): Seq[String] =
apply(addModules = addModules, output = output, modulePath = Nil)

def apply(addModules: Seq[String], output: Option[File], modulePath: Seq[File]): Seq[String] =
option("--output", output) ++
list("--add-modules", addModules) ++
list("--module-path", modulePath)
list("--add-modules", addModules, ",") ++
list("--module-path", modulePath, ":")

private def option[A](arg: String, value: Option[A]): Seq[String] =
value.toSeq.flatMap(a => Seq(arg, a.toString))

private def list[A](arg: String, values: Seq[A]): Seq[String] =
if (values.nonEmpty) Seq(arg, values.mkString(",")) else Nil
private def list[A](arg: String, values: Seq[A], separator: String): Seq[String] =
if (values.nonEmpty) Seq(arg, values.mkString(separator)) else Nil
}

// Jdeps output row
Expand Down
41 changes: 41 additions & 0 deletions src/sbt-test/jlink/test-jlink-misc/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,44 @@ val issue1243 = project
jlinkIgnoreMissingDependency := JlinkIgnore.everything,
runChecks := jlinkBuildImage.value
)

// Should succeed for JARs with names that don't produce a legal automatic
// module name.
val issue1247BadAutoModuleName = project
.enablePlugins(JlinkPlugin)
.settings(
managedClasspath in Compile += {
// Build an empty jar with an unsupported name
val jarFile = target.value / "foo_2.11.jar"
IO.jar(Nil, jarFile, new java.util.jar.Manifest)
Attributed.blank(jarFile)
},
runChecks := jlinkBuildImage.value
)

// Should succeed for jars containing external modules.
val issue1247ExternalModule = project
.enablePlugins(JlinkPlugin)
.settings(
// An arbitrary JAR with a non-platform module.
libraryDependencies += "com.sun.xml.fastinfoset" % "FastInfoset" % "1.2.16",
runChecks := jlinkBuildImage.value
)

// Should succeed for `java.*` modules from JakartaEE.
val issue1247JakartaJavaModules = project
.enablePlugins(JlinkPlugin)
.settings(
libraryDependencies ++= List(
"jakarta.ws.rs" % "jakarta.ws.rs-api" % "2.1.5",
"jakarta.xml.bind" % "jakarta.xml.bind-api" % "2.3.2",

// We don't use the implementation from
// `com.sun.activation` because that doesn't include an explicit module
// declaration, and automatic modules are not properly supported
// with jdeps 11+.
// https://github.com/eclipse-ee4j/jaf/issues/13
"com.jwebmp.thirdparty" % "jakarta.activation" % "0.67.0.12"
),
runChecks := jlinkBuildImage.value
)
5 changes: 4 additions & 1 deletion src/sbt-test/jlink/test-jlink-misc/test
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# These tasks can be aggregated, but running them one by one means
# more granular output in case of a failure.
> issue1243/runChecks
> issue1243/runChecks
> issue1247BadAutoModuleName/runChecks
> issue1247ExternalModule/runChecks
> issue1247JakartaJavaModules/runChecks
4 changes: 4 additions & 0 deletions src/sphinx/archetypes/misc_archetypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ This plugin builds on Java's `jlink`_ tool to embed a JVM image (a stripped-down
into your package. It produces a JVM image containing only the modules that are referenced
from the dependency classpath.

Note: Current implementation only detects the platform modules (that is, the ones present in
the JDK used to build the image). Modular JARs and directories are packaged as specified
by the `UniversalPlugin`.

.. code-block:: scala

enablePlugins(JlinkPlugin)
Expand Down