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

編譯給定 source set 的 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 和屬性檔。

src/main/scala

生產 Scala 源碼。也可能包含用於聯合編譯的 Java 源碼檔案。

src/test/java

測試 Java 源碼。

src/test/resources

測試資源。

src/test/scala

測試 Scala 源碼。也可能包含用於聯合編譯的 Java 源碼檔案。

src/sourceSet/java

source set 名稱為 sourceSet 的 Java 源碼。

src/sourceSet/resources

source set 名稱為 sourceSet 的資源。

src/sourceSet/scala

給定 source set 的 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 依賴關係。不建議使用此模式,因為它依賴於從生產執行期 classpath 推斷 Scala classpath。從 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。這是透過以下方式完成的

  • 如果在 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 插件未向專案添加任何慣例屬性。

Source set 屬性

Scala 插件將以下擴展添加到專案中的每個 source set。您可以在建置腳本中使用它們,就像它們是 source set 物件的屬性一樣。

scalaSourceDirectorySet (唯讀)

此 source set 的 Scala 源碼檔案。包含在 Scala 源碼目錄中找到的所有 .scala.java 檔案,並排除所有其他類型的檔案。預設值: 非 null。

scala.srcDirsSet<File>

包含此 source set 的 Scala 源碼檔案的源碼目錄。也可能包含用於聯合編譯的 Java 源碼檔案。可以使用理解隱式轉換為檔案集合中描述的任何內容進行設定。預設值: [projectDir/src/name/scala]

allScalaFileTree (唯讀)

此 source set 的所有 Scala 源碼檔案。僅包含在 Scala 源碼目錄中找到的 .scala 檔案。預設值: 非 null。

這些擴展由 ScalaSourceSet 類型的物件支援。

Scala 插件還修改了一些 source set 屬性

表 3. Scala 插件 - source set 屬性
屬性名稱 變更

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,以指向類別資料夾或 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,並且可以透過在 IdeaModel 上配置 targetVersion 來添加 Scala facet 而不是預設 Scala SDK。

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