From af3ee37d6c4bb73e4502129becd1710f95a60a39 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Mon, 17 Jun 2019 16:55:54 +0200 Subject: [PATCH] Option to target system JDK instead of JDK8 (#27083) Inspired by the proposal by @nvollmar in 0940dfc --- build.sbt | 1 - project/AkkaBuild.scala | 23 ++++++++----------- project/CrossJava.scala | 51 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/build.sbt b/build.sbt index bdee61b4f2..67049035ed 100644 --- a/build.sbt +++ b/build.sbt @@ -23,7 +23,6 @@ import spray.boilerplate.BoilerplatePlugin initialize := { // Load system properties from a file to make configuration from Jenkins easier loadSystemProperties("project/akka-build.properties") - assert(CrossJava.Keys.fullJavaHomes.value.contains("8"), "JDK 8 is not installed but required to build akka") initialize.value } diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala index 0472523bf0..1190b976f4 100644 --- a/project/AkkaBuild.scala +++ b/project/AkkaBuild.scala @@ -11,8 +11,11 @@ import java.time.format.DateTimeFormatter import java.time.ZonedDateTime import java.time.ZoneOffset -import sbt.Keys._ +// Overriding CrossJava imports #26935 +import sbt.Keys.{fullJavaHomes=>_,_} import sbt._ + +import CrossJava.autoImport._ import org.scalafmt.sbt.ScalafmtPlugin.autoImport._ import scala.collection.breakOut @@ -128,21 +131,15 @@ object AkkaBuild { // compile options scalacOptions in Compile ++= DefaultScalacOptions, - // Makes sure that, even when compiling with a jdk version greater than 8, the resulting jar will not refer to - // methods not found in jdk8. To test whether this has the desired effect, compile akka-remote and check the - // invocation of 'ByteBuffer.clear()' in EnvelopeBuffer.class with 'javap -c': it should refer to - // "java/nio/ByteBuffer.clear:()Ljava/nio/Buffer" and not "java/nio/ByteBuffer.clear:()Ljava/nio/ByteBuffer": - scalacOptions in Compile ++= ( - if (JavaVersion.isJdk8) - Seq("-target:jvm-1.8") - else - // -release 8 is not enough, for some reason we need the 8 rt.jar explicitly #25330 - Seq("-release", "8", "-javabootclasspath", CrossJava.Keys.fullJavaHomes.value("8") + "/jre/lib/rt.jar")), + scalacOptions in Compile ++= + CrossJava.targetJdkScalacOptions(targetSystemJdk.value, fullJavaHomes.value), scalacOptions in Compile ++= (if (allWarnings) Seq("-deprecation") else Nil), scalacOptions in Test := (scalacOptions in Test).value.filterNot(opt => opt == "-Xlog-reflective-calls" || opt.contains("genjavadoc")), - javacOptions in compile ++= DefaultJavacOptions ++ JavaVersion.sourceAndTarget(CrossJava.Keys.fullJavaHomes.value("8")), - javacOptions in test ++= DefaultJavacOptions ++ JavaVersion.sourceAndTarget(CrossJava.Keys.fullJavaHomes.value("8")), + javacOptions in compile ++= DefaultJavacOptions ++ + CrossJava.targetJdkJavacOptions(targetSystemJdk.value, fullJavaHomes.value), + javacOptions in test ++= DefaultJavacOptions ++ + CrossJava.targetJdkJavacOptions(targetSystemJdk.value, fullJavaHomes.value), javacOptions in compile ++= (if (allWarnings) Seq("-Xlint:deprecation") else Nil), javacOptions in doc ++= Seq(), diff --git a/project/CrossJava.scala b/project/CrossJava.scala index bdd468ff95..142258a71c 100644 --- a/project/CrossJava.scala +++ b/project/CrossJava.scala @@ -15,8 +15,9 @@ import akka.CrossJava.nullBlank /* * Tools for discovering different Java versions, - * will be in sbt 1.3.0 (https://github.com/sbt/sbt/pull/4139 et al) - * but until that time replicated here + * + * Some of these will be in sbt 1.3.0 (https://github.com/sbt/sbt/pull/4139 et al) + * but are replicated here until that time */ case class JavaVersion(numbers: Vector[Long], vendor: Option[String]) { def numberStr: String = numbers.mkString(".") @@ -49,21 +50,59 @@ object JavaVersion { def sourceAndTarget(fullJavaHome: File): Seq[String] = if (isJdk8) Seq.empty else Seq("-source", "8", "-target", "8", "-bootclasspath", fullJavaHome + "/jre/lib/rt.jar") + } -object CrossJava { - object Keys { +object CrossJava extends AutoPlugin { + object autoImport { val discoveredJavaHomes = settingKey[Map[String, File]]("Discovered Java home directories") val javaHomes = settingKey[Map[String, File]]("The user-defined additional Java home directories") val fullJavaHomes = settingKey[Map[String, File]]("Combines discoveredJavaHomes and custom javaHomes.") + val targetSystemJdk = settingKey[Boolean]("Target the system JDK instead of building against JDK 8. When this is enabled resulting artifacts may not work on JDK 8!") } + import autoImport._ - import Keys._ + def targetJdkScalacOptions(targetSystemJdk: Boolean, fullJavaHomes: Map[String, File]): Seq[String] = + selectOptions( + targetSystemJdk, + fullJavaHomes, + Seq("-target:jvm-1.8"), + // '-release 8' is not enough, for some reason we need the 8 rt.jar + // explicitly. To test whether this has the desired effect, compile + // akka-remote and check the invocation of 'ByteBuffer.clear()' in + // EnvelopeBuffer.class with 'javap -c': it should refer to + //""java/nio/ByteBuffer.clear:()Ljava/nio/Buffer" and not + // "java/nio/ByteBuffer.clear:()Ljava/nio/ByteBuffer". Issue #27079 + (java8home: File) => Seq("-release", "8", "-javabootclasspath", java8home + "/jre/lib/rt.jar") + ) + def targetJdkJavacOptions(targetSystemJdk: Boolean, fullJavaHomes: Map[String, File]): Seq[String] = + selectOptions( + targetSystemJdk, + fullJavaHomes, + Nil, + // '-release 8' would be a neater option here, but is currently not an + // option because it doesn't provide access to `sun.misc.Unsafe` #27079 + (java8home: File) => Seq("-source", "8", "-target", "8", "-bootclasspath", java8home + "/jre/lib/rt.jar") + ) + + private def selectOptions(targetSystemJdk: Boolean, fullJavaHomes: Map[String, File], jdk8options: Seq[String], jdk11options: File => Seq[String]): Seq[String] = + if (targetSystemJdk) + Nil + else if (JavaVersion.isJdk8) + jdk8options + else fullJavaHomes.get("8") match { + case Some(java8home) => + jdk11options(java8home) + case None => + throw new MessageOnlyException("A JDK 8 installation was not found, but is required to build Akka. To target your system JDK, use the \"set every targetSystemJdk := true\" sbt command. Resulting artifacts may not work on JDK 8") + } val crossJavaSettings = Seq( discoveredJavaHomes := CrossJava.discoverJavaHomes, javaHomes := ListMap.empty, - fullJavaHomes := CrossJava.expandJavaHomes(discoveredJavaHomes.value ++ javaHomes.value)) + fullJavaHomes := CrossJava.expandJavaHomes(discoveredJavaHomes.value ++ javaHomes.value), + targetSystemJdk := false, + ) // parses jabaa style version number adopt@1.8 def parseJavaVersion(version: String): JavaVersion = {