Scala 插件扩展了 Java 插件,以增加对 Scala 项目的支持。该插件还支持联合编译,允许您在两个方向上自由混合和匹配 Scala 和 Java 代码及其依赖项。例如,一个 Scala 类可以扩展一个 Java 类,而该 Java 类又可以扩展一个 Scala 类。这使得可以使用最适合工作的语言,并在需要时用另一种语言重写任何类。

请注意,如果您想从 API / 实现分离 中受益,您也可以将 java-library 插件应用于您的 Scala 项目。

用法

要使用 Scala 插件,请在您的构建脚本中包含以下内容

build.gradle.kts
plugins {
    id("scala")
}
build.gradle
plugins {
    id("scala")
}

任务

Scala 插件向项目添加以下任务。有关更改 Java 编译任务依赖项的信息,请参见此处

compileScalaScalaCompile

依赖于compileJava

编译生产 Scala 源文件。

compileTestScalaScalaCompile

依赖于compileTestJava

编译测试 Scala 源文件。

compileSourceSetScalaScalaCompile

依赖于compileSourceSetJava

编译给定源集的 Scala 源文件。

scaladocScalaDoc

为生产 Scala 源文件生成 API 文档。

ScalaCompileScalaDoc 任务开箱即用地支持 Java 工具链

Scala 插件向 Java 插件添加的任务添加以下依赖项。

表 1. Scala 插件 - 附加任务依赖项
任务名称 依赖于

classes

compileScala

testClasses

compileTestScala

sourceSetClasses

compileSourceSetScala

scalaPluginTasks
图 1. Scala 插件 - 任务

项目布局

Scala 插件假定项目布局如下所示。所有 Scala 源目录都可以包含 Scala Java 代码。Java 源目录可能只包含 Java 源代码。这些目录都不需要存在或包含任何内容;Scala 插件只会编译它找到的任何内容。

src/main/java

生产 Java 源代码。

src/main/resources

生产资源,例如 XML 和 properties 文件。

src/main/scala

生产 Scala 源代码。也可能包含用于联合编译的 Java 源文件。

src/test/java

测试 Java 源代码。

src/test/resources

测试资源。

src/test/scala

测试 Scala 源代码。也可能包含用于联合编译的 Java 源文件。

src/sourceSet/java

源集名为 sourceSet 的 Java 源代码。

src/sourceSet/resources

源集名为 sourceSet 的资源。

src/sourceSet/scala

给定源集的 Scala 源文件。也可能包含用于联合编译的 Java 源文件。

更改项目布局

就像 Java 插件一样,Scala 插件允许您为 Scala 生产和测试源文件配置自定义位置。

build.gradle.kts
sourceSets {
    main {
        scala {
            setSrcDirs(listOf("src/scala"))
        }
    }
    test {
        scala {
            setSrcDirs(listOf("test/scala"))
        }
    }
}
build.gradle
sourceSets {
    main {
        scala {
            srcDirs = ['src/scala']
        }
    }
    test {
        scala {
            srcDirs = ['test/scala']
        }
    }
}

Scala 版本

可以直接在 scala 扩展上声明 Scala 版本。依赖项会根据声明的 Scala 版本自动添加到 scalaToolchain 配置中。scalaToolchainRuntimeClasspath 配置解析 scalaToolchain 配置上声明的依赖项,并包含运行 Scala 编译器所需的文件。

当设置 scalaVersion 属性时,无需声明 Scala SDK 的直接依赖项。
build.gradle.kts
repositories {
    mavenCentral()
}

scala {
    scalaVersion = "2.13.12"
}
build.gradle
repositories {
    mavenCentral()
}

scala {
    scalaVersion = "2.13.12"
}

配置 Gradle 以使用 Scala 3 与 Scala 2 没有区别。

build.gradle.kts
repositories {
    mavenCentral()
}

scala {
    scalaVersion = "3.6.3"
}
build.gradle
repositories {
    mavenCentral()
}

scala {
    scalaVersion = "3.6.3"
}
scalaVersion 属性正在孵化中。

声明 Scala 依赖项

当不使用 scalaVersion 属性时,必须在 implementation 配置上手动声明 Scala SDK 依赖项。不建议使用此模式,因为它依赖于从生产运行时类路径推断 Scala 类路径。从 scala 扩展中省略 Scala 版本将在未来的 Gradle 版本中弃用。

Scala 2 项目需要声明 scala-library 依赖项。

build.gradle.kts
repositories {
    mavenCentral()
}

dependencies {
    implementation("org.scala-lang:scala-library:2.13.12")
}
build.gradle
repositories {
    mavenCentral()
}

dependencies {
    implementation("org.scala-lang:scala-library:2.13.12")
}

Scala 3 项目需要声明 scala3-library_3 依赖项

build.gradle.kts
repositories {
    mavenCentral()
}

dependencies {
    implementation("org.scala-lang:scala3-library_3:3.6.3")
}
build.gradle
repositories {
    mavenCentral()
}

dependencies {
    implementation("org.scala-lang:scala3-library_3:3.6.3")
}

如果 Scala 仅用于测试代码,则应将 scala-library 依赖项添加到 testImplementation 配置中

build.gradle.kts
dependencies {
    testImplementation("org.scala-lang:scala-library:2.13.12")
}
build.gradle
dependencies {
    testImplementation("org.scala-lang:scala-library:2.13.12")
}

scalaClasspath 的自动配置

ScalaCompileScalaDoc 任务通过两种方式使用 Scala 代码:在其 classpath 上及其 scalaClasspath 上。前者用于定位源代码引用的类,通常包含 scala-library 以及其他库。后者用于加载和执行 Scala 编译器和 Scaladoc 工具,分别应仅包含 scala-compiler 库及其依赖项。

如果未设置 scala 扩展的 scalaVersion 属性,并且未显式配置任务的 scalaClasspath,则 Scala(基本)插件将尝试从任务的 classpath 推断类路径。这样做的方法如下

  • 如果在 classpath 上找到 scala-library jar,并且项目至少声明了一个仓库,则会将相应的 scala-compiler 仓库依赖项添加到 scalaClasspath

  • 否则,任务的执行将失败,并显示一条消息,指出无法推断 scalaClasspath

配置 Zinc 编译器

Scala 插件使用名为 zinc 的配置来解析 Zinc 编译器 及其依赖项。Gradle 将提供 Zinc 的默认版本,但如果您需要使用特定的 Zinc 版本,则可以更改它。Gradle 支持 1.6.0 及更高版本的 Zinc。

build.gradle.kts
scala {
    scalaVersion = "2.13.12"
    zincVersion = "1.10.4"
}
build.gradle
scala {
    scalaVersion = "2.13.12"
    zincVersion = "1.10.4"
}

Zinc 编译器本身需要与您的应用程序所需的版本兼容的 scala-library 版本。Gradle 会负责为您指定兼容的 scala-library 版本。

您可以通过为 zinc 配置运行 dependencyInsight 来诊断所选 Zinc 编译器版本的问题。

表 2. Zinc 兼容性表
Gradle 版本 支持的 Zinc 版本 Zinc 坐标 所需的 Scala 版本 支持的 Scala 编译版本

7.5 及更高版本

SBT Zinc。版本 1.6.0 及更高版本。

org.scala-sbt:zinc_2.13

运行 Zinc 需要 Scala 2.13.x

可以编译 Scala 2.10.x3.x

6.0 到 7.5

SBT Zinc。版本 1.2.0 及更高版本。

org.scala-sbt:zinc_2.12

运行 Zinc 需要 Scala 2.12.x

可以编译 Scala 2.10.x2.13.x

1.x 到 5.x

已弃用 Typesafe Zinc 编译器。 版本 0.3.0 及更高版本,但 0.3.2 到 0.3.5.2 除外。

com.typesafe.zinc:zinc

运行 Zinc 需要 Scala 2.10.x

可以编译 Scala 2.9.x2.12.x

向 Scala 编译器添加插件

Scala 插件添加了一个名为 scalaCompilerPlugins 的配置,用于声明和解析可选的编译器插件。

build.gradle.kts
dependencies {
    scalaCompilerPlugins("org.typelevel:kind-projector_2.13.12:0.13.2")
}
build.gradle
dependencies {
    scalaCompilerPlugins("org.typelevel:kind-projector_2.13.12:0.13.2")
}

约定属性

Scala 插件没有向项目添加任何约定属性。

源集属性

Scala 插件向项目中的每个源集添加以下扩展。您可以在构建脚本中使用它们,就像它们是源集对象的属性一样。

scalaSourceDirectorySet (只读)

此源集的 Scala 源文件。包含在 Scala 源目录中找到的所有 .scala.java 文件,并排除所有其他类型的文件。默认值:非空。

scala.srcDirsSet<File>

包含此源集的 Scala 源文件的源目录。也可能包含用于联合编译的 Java 源文件。可以使用理解隐式转换为文件集合中描述的任何内容进行设置。默认值: [projectDir/src/name/scala]

allScalaFileTree (只读)

此源集的所有 Scala 源文件。仅包含在 Scala 源目录中找到的 .scala 文件。默认值:非空。

这些扩展由 ScalaSourceSet 类型的对象支持。

Scala 插件还修改了一些源集属性

表 3. Scala 插件 - 源集属性
属性名称 更改

allJava

添加在 Scala 源目录中找到的所有 .java 文件。

allSource

添加在 Scala 源目录中找到的所有源文件。

目标字节码级别和 Java API 版本

运行 Scala 编译任务时,Gradle 始终会添加一个参数来配置 Scala 编译器的 Java 目标,该目标派生自 Gradle 配置

  • 当使用工具链时,将选择 -release 选项,或者对于较旧的 Scala 版本,将选择 target,其版本与配置的工具链的 Java 语言级别匹配。

  • 当不使用工具链时,Gradle 将始终传递一个 target 标志 - 确切值取决于 Scala 版本 - 以编译为 Java 8 字节码。

这意味着将工具链与最新的 Java 版本和旧版本的 Scala 版本一起使用可能会导致失败,因为 Scala 在一段时间内仅支持 Java 8 字节码。解决方案是在工具链中使用正确的 Java 版本,或在需要时显式降级目标。

下表解释了 Gradle 计算的值

表 4. 基于项目配置的 Scala 目标参数
Scala 版本 正在使用的工具链 参数值

版本 < 2.13.1

-target:jvm-1.<java_version>

-target:jvm-1.8

2.13.1 <= 版本 < 2.13.9

-target:<java_version>

-target:8

2.13.9 <= 版本 < 3.0

-release:<java_version>

-target:8

3.0 <= 版本

-release:<java_version>

-Xtarget:8

ScalaCompile.scalaCompileOptions.additionalParameters 上显式设置任何这些标志,或使用包含 java-output-version 的标志,会禁用该逻辑,而支持显式标志。

在外部进程中编译

Scala 编译在外部进程中进行。

外部进程的内存设置默认为 JVM 的默认值。要调整内存设置,请根据需要配置 scalaCompileOptions.forkOptions 属性

build.gradle.kts
tasks.withType<ScalaCompile>().configureEach {
    scalaCompileOptions.forkOptions.apply {
        memoryMaximumSize = "1g"
        jvmArgs = listOf("-XX:MaxMetaspaceSize=512m")
    }
}
build.gradle
tasks.withType(ScalaCompile) {
    scalaCompileOptions.forkOptions.with {
        memoryMaximumSize = '1g'
        jvmArgs = ['-XX:MaxMetaspaceSize=512m']
    }
}

增量编译

通过仅编译自上次编译以来源代码已更改的类以及受这些更改影响的类,增量编译可以显着减少 Scala 编译时间。当频繁编译小代码增量时,它特别有效,这在开发时经常完成。

Scala 插件默认使用增量编译,通过与 Zinc 集成,Zinc 是 sbt 增量 Scala 编译器的独立版本。如果要禁用增量编译,请在构建文件中设置 force = true

build.gradle.kts
tasks.withType<ScalaCompile>().configureEach {
    scalaCompileOptions.apply {
        isForce = true
    }
}
build.gradle
tasks.withType(ScalaCompile) {
    scalaCompileOptions.with {
        force = true
    }
}

注意: 仅当至少一个输入源文件已更改时,才会导致重新编译所有类。如果源文件没有更改,则 compileScala 任务仍将像往常一样被视为 UP-TO-DATE

基于 Zinc 的 Scala 编译器支持 Java 和 Scala 代码的联合编译。默认情况下,src/main/scala 下的所有 Java 和 Scala 代码都将参与联合编译。即使 Java 代码也将以增量方式编译。

增量编译需要对源代码进行依赖性分析。此分析的结果存储在 scalaCompileOptions.incrementalOptions.analysisFile 指定的文件中(该文件具有合理的默认值)。在多项目构建中,分析文件会传递到下游 ScalaCompile 任务,以实现跨项目边界的增量编译。对于 Scala 插件添加的 ScalaCompile 任务,无需任何配置即可使其工作。对于您可能添加的其他 ScalaCompile 任务,需要配置属性 scalaCompileOptions.incrementalOptions.publishedCode 以指向代码传递到下游 ScalaCompile 任务的类文件夹或 Jar 存档。请注意,如果 publishedCode 未正确设置,则下游任务可能不会重新编译受上游更改影响的代码,从而导致不正确的编译结果。

请注意,不支持 Zinc 基于 Nailgun 的守护程序模式。相反,我们计划增强 Gradle 自己的编译器守护程序,使其在 Gradle 调用之间保持活动状态,从而重用相同的 Scala 编译器。预计这将为 Scala 编译带来另一个显着的加速。

Eclipse 集成

当 Eclipse 插件遇到 Scala 项目时,它会添加额外的配置,使项目可以开箱即用地与 Scala IDE 一起使用。具体来说,该插件添加了一个 Scala nature 和依赖项容器。

IntelliJ IDEA 集成

当 IDEA 插件遇到 Scala 项目时,它会添加额外的配置,使项目可以开箱即用地与 IDEA 一起使用。具体来说,该插件添加了一个 Scala SDK(IntelliJ IDEA 14+)和一个与项目类路径上的 Scala 版本匹配的 Scala 编译器库。Scala 插件向后兼容早期版本的 IntelliJ IDEA,并且可以通过在 IdeaModel 上配置 targetVersion 来添加 Scala facet 而不是默认的 Scala SDK。

build.gradle.kts
idea {
    targetVersion = "13"
}
build.gradle
idea {
    targetVersion = '13'
}