From 46ba8d16566fd6cabeb8ed66ba65257ea81b40e9 Mon Sep 17 00:00:00 2001 From: Louis Jacomet Date: Thu, 16 Feb 2023 14:05:34 +0100 Subject: [PATCH 1/3] Update Scala target computation Only use release when an explicit toolchain is configured. Fixes #23905 --- .../executer/AbstractGradleExecuter.java | 3 ++ .../ZincScalaCompilerOutputNormalizer.groovy | 4 +- ...ncScalaCompilerOutputNormalizerTest.groovy | 37 +++++++++++++++++++ .../scala/ScalaPluginIntegrationTest.groovy | 1 + .../ScalaCompileIntegrationTest.groovy | 23 ++++++++++++ .../ScalaCompileOptionsConfigurer.java | 26 +++++++++++-- .../ScalaCompileOptionsConfigurerTest.groovy | 6 +-- 7 files changed, 93 insertions(+), 7 deletions(-) diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/AbstractGradleExecuter.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/AbstractGradleExecuter.java index ccf9dcfe7ea7..bfab617dba75 100644 --- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/AbstractGradleExecuter.java +++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/AbstractGradleExecuter.java @@ -1402,6 +1402,9 @@ private void validate(String output, String displayName) { } else if (line.matches(".*w: .* is deprecated\\..*")) { // A kotlinc warning, ignore i++; + } else if (line.matches("\\[Warn] :.* is deprecated: .*")) { + // A scalac warning, ignore + i++; } else if (isDeprecationMessageInHelpDescription(line)) { i++; } else if (removeFirstExpectedDeprecationWarning(line)) { diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/logging/ZincScalaCompilerOutputNormalizer.groovy b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/logging/ZincScalaCompilerOutputNormalizer.groovy index cf72a68a92ce..0d1eac90a9ff 100644 --- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/logging/ZincScalaCompilerOutputNormalizer.groovy +++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/logging/ZincScalaCompilerOutputNormalizer.groovy @@ -22,11 +22,13 @@ import java.util.regex.Pattern /** * Removes Scala Zinc compilation time logging from the build-init Scala samples output. + * Also removes the potential warning around using `-target` instead of `-release`. * */ class ZincScalaCompilerOutputNormalizer implements OutputNormalizer { private static final PATTERN = Pattern.compile( - "Scala Compiler interface compilation took ([0-9]+ hrs )?([0-9]+ mins )?[0-9.]+ secs\n\n", + "(Scala Compiler interface compilation took ([0-9]+ hrs )?([0-9]+ mins )?[0-9.]+ secs\n\n)" + + "|(\\[Warn] : -target is deprecated: Use -release instead to compile against the correct platform API.\none warning found\n\n)", Pattern.MULTILINE ) diff --git a/subprojects/internal-integ-testing/src/test/groovy/org/gradle/integtests/fixtures/logging/ZincScalaCompilerOutputNormalizerTest.groovy b/subprojects/internal-integ-testing/src/test/groovy/org/gradle/integtests/fixtures/logging/ZincScalaCompilerOutputNormalizerTest.groovy index 02be378f20a1..5594bdced732 100644 --- a/subprojects/internal-integ-testing/src/test/groovy/org/gradle/integtests/fixtures/logging/ZincScalaCompilerOutputNormalizerTest.groovy +++ b/subprojects/internal-integ-testing/src/test/groovy/org/gradle/integtests/fixtures/logging/ZincScalaCompilerOutputNormalizerTest.groovy @@ -67,6 +67,43 @@ Scala Compiler interface compilation took 1 hrs 20 mins 41.884 secs > Task :app:check > Task :app:build +BUILD SUCCESSFUL in 0s +7 actionable tasks: 7 executed +""".trim() + + when: + String normalized = outputNormalizer.normalize(input, executionMetadata) + + then: + normalized == expected + } + + def "successfully normalizes Scala compiler warning"() { + given: + String input = """ +> Task :app:compileJava NO-SOURCE +> Task :app:compileScala +[Warn] : -target is deprecated: Use -release instead to compile against the correct platform API. +one warning found + +> Task :app:processResources NO-SOURCE +> Task :app:classes +> Task :app:jar +> Task :app:startScripts +> Task :app:distTar +> Task :app:distZip +> Task :app:assemble +> Task :app:compileTestJava NO-SOURCE +> Task :app:compileTestScala +[Warn] : -target is deprecated: Use -release instead to compile against the correct platform API. +one warning found + +> Task :app:processTestResources NO-SOURCE +> Task :app:testClasses +> Task :app:test +> Task :app:check +> Task :app:build + BUILD SUCCESSFUL in 0s 7 actionable tasks: 7 executed """.trim() diff --git a/subprojects/scala/src/integTest/groovy/org/gradle/scala/ScalaPluginIntegrationTest.groovy b/subprojects/scala/src/integTest/groovy/org/gradle/scala/ScalaPluginIntegrationTest.groovy index aa2ea132a9de..e6ac5d4be8ec 100644 --- a/subprojects/scala/src/integTest/groovy/org/gradle/scala/ScalaPluginIntegrationTest.groovy +++ b/subprojects/scala/src/integTest/groovy/org/gradle/scala/ScalaPluginIntegrationTest.groovy @@ -81,6 +81,7 @@ class ScalaPluginIntegrationTest extends MultiVersionIntegrationSpec { """ expect: + executer.noDeprecationChecks() succeeds(":a:classes", "--parallel") true } diff --git a/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/ScalaCompileIntegrationTest.groovy b/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/ScalaCompileIntegrationTest.groovy index 9e1699b41ae1..e4ce1bf761e7 100644 --- a/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/ScalaCompileIntegrationTest.groovy +++ b/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/ScalaCompileIntegrationTest.groovy @@ -22,6 +22,8 @@ import org.gradle.integtests.fixtures.ScalaCoverage import org.gradle.integtests.fixtures.TargetCoverage import org.gradle.integtests.fixtures.jvm.JavaToolchainFixture import org.gradle.internal.jvm.Jvm +import org.gradle.util.Requires +import org.gradle.util.TestPrecondition import static org.gradle.scala.ScalaCompilationFixture.scalaDependency @@ -96,4 +98,25 @@ class Person { "immutable list" | "[].asImmutable()" } + @Requires(TestPrecondition.JDK11_OR_LATER) + def "can compile sources using later JDK APIs"() { + file("src/main/scala/App.scala") << """ + object App { + def main(args: Array[String]): Unit = { + var x : String = "Test String" + // isBlank is from JDK 11 + println(x.isBlank) + } + } + """ + + when: + run ":compileScala" + + then: + executedAndNotSkipped(":compileScala") + + JavaVersion.forClass(scalaClassFile("App.class").bytes) == JavaVersion.VERSION_1_8 + } + } diff --git a/subprojects/scala/src/main/java/org/gradle/api/tasks/scala/internal/ScalaCompileOptionsConfigurer.java b/subprojects/scala/src/main/java/org/gradle/api/tasks/scala/internal/ScalaCompileOptionsConfigurer.java index 3ffb94d166bc..326770c866a9 100644 --- a/subprojects/scala/src/main/java/org/gradle/api/tasks/scala/internal/ScalaCompileOptionsConfigurer.java +++ b/subprojects/scala/src/main/java/org/gradle/api/tasks/scala/internal/ScalaCompileOptionsConfigurer.java @@ -79,10 +79,30 @@ private static boolean hasTargetDefiningParameter(List additionalParamet return additionalParameters.stream().anyMatch(s -> TARGET_DEFINING_PARAMETERS.stream().anyMatch(s::startsWith)); } + /** + * Computes parameter to specify how Scala should handle Java APIs and produced bytecode version. + *

+ * The exact result depends on the Scala version in use and if the toolchain is user specified or not. + * + * @param scalaVersion The detected scala version + * @param javaToolchain The toolchain used to run compilation + * @return a Scala compiler parameter + */ private static String determineTargetParameter(VersionNumber scalaVersion, JavaToolchain javaToolchain) { - int effectiveTarget = javaToolchain.isFallbackToolchain() ? FALLBACK_JVM_TARGET : javaToolchain.getLanguageVersion().asInt(); - if (scalaVersion.compareTo(RELEASE_REPLACES_TARGET_SINCE_VERSION) >= 0) { - return String.format("-release:%s", effectiveTarget); + boolean explicitToolchain = !javaToolchain.isFallbackToolchain(); + int effectiveTarget = !explicitToolchain ? FALLBACK_JVM_TARGET : javaToolchain.getLanguageVersion().asInt(); + if (scalaVersion.compareTo(VersionNumber.parse("3.0.0")) >= 0) { + if (explicitToolchain) { + return String.format("-release:%s", effectiveTarget); + } else { + return String.format("-Xtarget:%s", effectiveTarget); + } + } else if (scalaVersion.compareTo(RELEASE_REPLACES_TARGET_SINCE_VERSION) >= 0) { + if (explicitToolchain) { + return String.format("-release:%s", effectiveTarget); + } else { + return String.format("-target:%s", effectiveTarget); + } } else if (scalaVersion.compareTo(PLAIN_TARGET_FORMAT_SINCE_VERSION) >= 0) { return String.format("-target:%s", effectiveTarget); } else { diff --git a/subprojects/scala/src/test/groovy/org/gradle/scala/compile/internal/ScalaCompileOptionsConfigurerTest.groovy b/subprojects/scala/src/test/groovy/org/gradle/scala/compile/internal/ScalaCompileOptionsConfigurerTest.groovy index 18d37a012816..18683dd61fce 100644 --- a/subprojects/scala/src/test/groovy/org/gradle/scala/compile/internal/ScalaCompileOptionsConfigurerTest.groovy +++ b/subprojects/scala/src/test/groovy/org/gradle/scala/compile/internal/ScalaCompileOptionsConfigurerTest.groovy @@ -81,9 +81,9 @@ class ScalaCompileOptionsConfigurerTest extends Specification { 17 | false | '2.13.10' | '-release:17' 17 | false | '3.2.1' | '-release:17' - 17 | true | '2.13.9' | '-release:8' - 17 | true | '2.13.10' | '-release:8' - 17 | true | '3.2.1' | '-release:8' + 17 | true | '2.13.9' | '-target:8' + 17 | true | '2.13.10' | '-target:8' + 17 | true | '3.2.1' | '-Xtarget:8' toolchain = fallbackToolchain ? "$javaToolchain (fallback)" : javaToolchain } From 6ca9eb520629f03d708d8e4e6d603849302658be Mon Sep 17 00:00:00 2001 From: Louis Jacomet Date: Thu, 16 Feb 2023 15:28:24 +0100 Subject: [PATCH 2/3] Document Scala Java bytecode target changes Fixes #21551 --- .../src/docs/userguide/jvm/scala_plugin.adoc | 31 +++++++++++++++++++ .../migration/upgrading_version_7.adoc | 7 +++++ 2 files changed, 38 insertions(+) diff --git a/subprojects/docs/src/docs/userguide/jvm/scala_plugin.adoc b/subprojects/docs/src/docs/userguide/jvm/scala_plugin.adoc index db0ceb60a09d..97ca925988e7 100644 --- a/subprojects/docs/src/docs/userguide/jvm/scala_plugin.adoc +++ b/subprojects/docs/src/docs/userguide/jvm/scala_plugin.adoc @@ -228,6 +228,37 @@ The Scala plugin also modifies some source set properties: | `allSource` | Adds all source files found in the Scala source directories. |=== +[[sec:scala_target]] +== Target bytecode level and Java APIs version + +When running the Scala compile task, Gradle will always add a parameter to configure the Java target for the Scala compiler that is derived from the Gradle configuration: + +* When using toolchains, the `-release` option, or `target` for older Scala versions, is selected, with a version matching the Java language level of the toolchain configured. +* When not using toolchains, Gradle will always pass a `target` flag -- with exact value dependent on the Scala version -- to compile to Java 8 bytecode. + +[NOTE] +==== +This means that using toolchains with a recent Java version and an old Scala version can result in failures because Scala only supported Java 8 bytecode for some time. +The solution is then to either use the right Java version in the toolchain or explicitly downgrade the target when needed. +==== + +The following table explains the values computed by Gradle: + +.Scala target parameter based on project configuration +[%header%autowidth,compact] +|=== +| Scala version | Toolchain in use | Parameter value +.2+| version < `2.13.1` | yes | `-target:jvm-1.` + | no | `-target:jvm-1.8` +.2+| `2.13.1` \<= version < `2.13.9` | yes | `-target:` + | no | `-target:8` +.2+| `2.13.9` \<= version < `3.0` | yes | `-release:` + | no | `-target:8` +.2+| `3.0` \<= version | yes | `-release:` + | no | `-Xtarget:8` +|=== + +Setting any of these flags explicitly, or using flags containing `java-output-version`, on link:{groovyDslPath}/org.gradle.language.scala.tasks.BaseScalaCompileOptions.html#org.gradle.language.scala.tasks.BaseScalaCompileOptions:additionalParameters[`ScalaCompile.scalaCompileOptions.additionalParameters`] disables that logic in favor of the explicit flag. [[sec:scala_compiling_in_external_process]] == Compiling in external process diff --git a/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc b/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc index 30c6a33f4770..88767ed5e7b7 100644 --- a/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc +++ b/subprojects/docs/src/docs/userguide/migration/upgrading_version_7.adoc @@ -693,6 +693,13 @@ In case no toolchains are explicitly configured, the toolchain corresponding to Similarly, tasks from the Groovy and Scala plugins also rely on toolchains to determine on which JVM they are executed. +==== Scala compilation target + +With the toolchain changes described above, Scala compilation tasks are now always provided with a `target` or `release` parameter. +The exact parameter and value depend on toolchain usage, or not, and Scala version. + +See the <> for details. + [[changes_7.6]] == Upgrading from 7.5 and earlier From b52aab744fd4d9f970da71f98206ab770651ed29 Mon Sep 17 00:00:00 2001 From: Louis Jacomet Date: Fri, 17 Feb 2023 09:21:28 +0100 Subject: [PATCH 3/3] 8.0.1 release notes --- subprojects/docs/src/docs/release/notes.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subprojects/docs/src/docs/release/notes.md b/subprojects/docs/src/docs/release/notes.md index 73dcadaa81e9..0b5cf390be77 100644 --- a/subprojects/docs/src/docs/release/notes.md +++ b/subprojects/docs/src/docs/release/notes.md @@ -3,7 +3,9 @@ The Gradle team is excited to announce Gradle @version@. This is the first patch release for Gradle 8.0. It fixes the following issues: -* TODO +* [#21551](https://github.com/gradle/gradle/issues/21551) Document integration of Scala plugin with toolchains and problems with `target` flag +* [#23888](https://github.com/gradle/gradle/issues/23888) `--no-rebuild` suddenly gone without new deprecation cycle and without the reason for its undeprecation being void +* [#23905](https://github.com/gradle/gradle/issues/23905) Gradle 8.0 fails Scala build with isBlank not found in String class error We recommend users upgrade to @version@ instead of 8.0.