Scala 插件扩展了Java 插件以添加对Scala项目的支持。该插件还支持联合编译,允许您自由地混合和匹配 Scala 和 Java 代码,并具有双向依赖关系。例如,Scala 类可以扩展 Java 类,而 Java 类又扩展 Scala 类。这使得可以使用最适合工作的语言,并在需要时用其他语言重写任何类。

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

用法

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

build.gradle.kts
plugins {
    scala
}
build.gradle
plugins {
    id 'scala'
}

任务

Scala 插件将以下任务添加到项目中。有关更改 Java 编译任务的依赖关系的信息可在此处找到。

compileScalaScala 编译

依赖于取决于compileJava

编译生产 Scala 源文件。

compileTestScalaScala 编译

依赖于取决于compileTestJava

编译测试 Scala 源文件。

compileSourceSetScalaScala 编译

依赖于取决于compileSourceSetJava

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

scaladocScalaDoc

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

ScalaCompile和任务ScalaDoc支持开箱即用的Java 工具链。

Scala 插件将以下依赖项添加到 Java 插件添加的任务中。

表 1. Scala 插件 - 其他任务依赖项
任务名称 依赖于取决于

classes

compileScala

testClasses

compileTestScala

sourceSetClasses

compileSourceSetScala

scala插件任务
图 1.Scala 插件 - 任务

项目布局

Scala 插件采用如下所示的项目布局。所有 Scala 源目录都可以包含 ScalaJava 代码。 Java 源目录可能仅包含 Java 源代码。这些目录都不需要存在或包含任何内容; Scala 插件将简单地编译它找到的任何内容。

src/main/java

生产 Java 源代码。

src/main/resources

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

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-library依赖项。然后,此依赖项将用于编译和运行时类路径。它还将分别用于获取 Scala 编译器和 Scaladoc 工具。[ 1 ]

如果 Scala 用于生产代码,scala-library则应将依赖项添加到implementation配置中:

build.gradle.kts
repositories {
    mavenCentral()
}

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

dependencies {
    implementation 'org.scala-lang:scala-library:2.13.12'
    testImplementation 'junit:junit:4.13'
}

如果您想使用 Scala 3 而不是依赖scala-library项,您应该添加scala3-library_3依赖项:

build.gradle.kts
plugins {
    scala
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.scala-lang:scala3-library_3:3.0.1")
    testImplementation("org.scalatest:scalatest_3:3.2.9")
    testImplementation("junit:junit:4.13")
}

dependencies {
    implementation("commons-collections:commons-collections:3.2.2")
}
build.gradle
plugins {
    id 'scala'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.scala-lang:scala3-library_3:3.0.1'
    implementation 'commons-collections:commons-collections:3.2.2'
    testImplementation 'org.scalatest:scalatest_3:3.2.9'
    testImplementation 'junit:junit:4.13'
}

如果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的自动配置

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

除非显式配置任务scalaClasspath,否则 Scala(基本)插件将尝试从任务的classpath.这是按如下方式完成的:

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

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

配置 Zinc 编译器

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

build.gradle.kts
scala {
    zincVersion = "1.9.3"
}
build.gradle
scala {
    zincVersion = "1.9.3"
}

Zinc 编译器本身需要一个兼容版本,scala-library该版本可能与您的应用程序所需的版本不同。 Gradle 负责scala-library为您指定兼容版本。

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

表 2. 锌相容性表
摇篮版本 支持的锌版本 锌坐标 所需的 Scala 版本 支持的Scala编译版本

7.5 及更高版本

SBT 锌。 1.6.0 及以上版本。

org.scala-sbt:zinc_2.13

运行2.13.xZinc需要Scala 。

Scala2.10.x通过3.x可以编译。

6.0 至 7.5

SBT 锌。 1.2.0 及以上版本。

org.scala-sbt:zinc_2.12

运行2.12.xZinc需要Scala 。

Scala2.10.x通过2.13.x可以编译。

1.x 至 5.x

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

com.typesafe.zinc:zinc

运行2.10.xZinc需要Scala 。

Scala2.9.x通过2.12.x可以编译。

向 Scala 编译器添加插件

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

build.gradle.kts
dependencies {
    implementation("org.scala-lang:scala-library:2.13.12")
    scalaCompilerPlugins("org.typelevel:kind-projector_2.13.12:0.13.2")
}
build.gradle
dependencies {
    implementation "org.scala-lang:scala-library:2.13.12"
    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]

allScala文件树(只读)

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

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

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

表 3. Scala 插件 - 源集属性
物业名称 改变

allJava

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

allSource

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

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

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

  • 使用工具链时,选择该-release选项,或者target对于较旧的 Scala 版本,选择与配置的工具链的 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

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

在外部进程中编译

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代码的联合编译。默认情况下,所有Java和Scala下的代码src/main/scala都会参与联合编译。甚至Java代码也会被增量编译。

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

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

Eclipse 集成

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

IntelliJ IDEA 集成

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

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