您可以在支持 Gradle 的 IDE 中打开此示例。

本指南演示了如何使用 gradle init 通过 Gradle 创建 Scala 库。您可以按照指南一步一步从头创建新项目,或使用上面的链接下载完整的示例项目。

构建内容

您将生成一个遵循 Gradle 约定的 Scala 库。

所需条件

创建项目文件夹

Gradle 自带一个名为 init 的内置任务,用于在空文件夹中初始化新的 Gradle 项目。init 任务使用(同样内置的)wrapper 任务创建 Gradle wrapper 脚本 gradlew

第一步是为新项目创建一个文件夹并切换到该文件夹中。

$ mkdir demo
$ cd demo

运行 init 任务

在新项目目录中,在终端中使用以下命令运行 init 任务:gradle init。出现提示时,选择 2: library 作为项目类型,选择 4: Scala 作为实现语言。接下来,您可以选择用于编写构建脚本的 DSL - 1 : Kotlin2: Groovy。对于其他问题,按 Enter 使用默认值。

输出将如下所示

$ gradle init

Select type of build to generate:
  1: Application
  2: Library
  3: Gradle plugin
  4: Basic (build structure only)
Enter selection (default: Application) [1..4] 2

Select implementation language:
  1: Java
  2: Kotlin
  3: Groovy
  4: Scala
  5: C++
  6: Swift
Enter selection (default: Java) [1..6] 4

Enter target Java version (min: 7, default: 21):

Project name (default: demo):

Select application structure:
  1: Single application project
  2: Application and library project
Enter selection (default: Single application project) [1..2] 1

Select build script DSL:
  1: Kotlin
  2: Groovy
Enter selection (default: Kotlin) [1..2]

Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]

BUILD SUCCESSFUL
1 actionable task: 1 executed

init 任务生成的新项目结构如下

├── gradle (1)
│   ├── libs.versions.toml (2)
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew (3)
├── gradlew.bat (3)
├── settings.gradle.kts (4)
└── lib
    ├── build.gradle.kts (5)
    └── src
        ├── main
        │   └── scala (6)
        │       └── demo
        │           └── Library.scala
        └── test
            └── scala (7)
                └── demo
                    └── LibrarySuite.scala
├── gradle (1)
│   ├── libs.versions.toml (2)
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew (3)
├── gradlew.bat (3)
├── settings.gradle (4)
└── lib
    ├── build.gradle (5)
    └── src
        ├── main
        │   └── scala (6)
        │       └── demo
        │           └── Library.scala
        └── test
            └── scala (7)
                └── demo
                    └── LibrarySuite.scala
1 生成的 wrapper 文件文件夹
2 生成的版本目录
3 Gradle wrapper 启动脚本
4 定义构建名称和子项目的设置文件
5 lib 项目的构建脚本
6 默认 Scala 源代码文件夹
7 默认 Scala 测试源代码文件夹

现在您已经完成了构建 Scala 库的项目设置。

查看项目文件

settings.gradle(.kts) 文件有两行值得关注的内容

settings.gradle.kts
rootProject.name = "demo"
include("lib")
settings.gradle
rootProject.name = 'demo'
include('lib')
  • rootProject.name 为构建指定了一个名称,这会覆盖按目录名称命名构建的默认行为。建议设置一个固定名称,因为如果项目被共享(例如作为 Git 仓库的根目录),文件夹可能会改变。

  • include("lib") 定义构建包含一个名为 lib 的子项目,该子项目包含实际代码和构建逻辑。可以通过添加更多 include(…​) 语句来添加更多子项目。

我们的构建包含一个名为 lib 的子项目,它代表我们正在构建的 Scala 库。它在 lib/build.gradle(.kts) 文件中配置

lib/build.gradle.kts
plugins {
    scala (1)
    `java-library` (2)
}

repositories {
    mavenCentral() (3)
}

dependencies {
    implementation(libs.scala.library) (4)

    implementation(libs.guava) (5)

    testImplementation(libs.junit) (6)
    testImplementation(libs.scalatest.v2.v13)
    testImplementation(libs.junit.v4.v13.v2.v13)

    testRuntimeOnly(libs.scala.xml.v2.v13) (7)

    api(libs.commons.math3) (8)
}
lib/build.gradle
plugins {
    id 'scala' (1)
    id 'java-library' (2)
}

repositories {
    mavenCentral() (3)
}

dependencies {
    implementation libs.scala.library (4)

    implementation libs.guava (5)

    testImplementation libs.junit (6)
    testImplementation libs.scalatest.v2.v13
    testImplementation libs.junit.v4.v13.v2.v13

    testRuntimeOnly libs.scala.xml.v2.v13 (7)

    api libs.commons.math3 (8)
}
1 应用 scala 插件以添加对 Scala 的支持。
2 应用 java-library 插件以实现 API 和实现的隔离。
3 使用 Maven Central 解析依赖项。
4 在我们的库项目中使用 Scala 2.13
5 此依赖项内部使用,不会暴露给消费者的编译类路径。
6 使用 Scalatest 测试我们的库
7 测试运行时需要 scala-xml
8 此依赖项将导出给消费者,也就是说,它会出现在他们的编译类路径中。

文件 src/main/scala/demo/Library.scala 在此处显示

生成的 src/main/scala/demo/Library.scala
/*
 * This source file was generated by the Gradle 'init' task
 */
package demo

class Library {
  def someLibraryMethod(): Boolean = true
}

生成的测试文件 src/test/scala/demo/Library.scala 接下来显示

生成的 src/test/scala/demo/LibrarySuite.scala
/*
 * This source file was generated by the Gradle 'init' task
 */
package demo

import org.scalatest.funsuite.AnyFunSuite
import org.junit.runner.RunWith
import org.scalatestplus.junit.JUnitRunner

@RunWith(classOf[JUnitRunner])
class LibrarySuite extends AnyFunSuite {
  test("someLibraryMethod is always true") {
    def library = new Library()
    assert(library.someLibraryMethod())
  }
}

生成的测试类包含一个 ScalaTest 测试。该测试实例化 Library 类,调用其上的一个方法,并检查它是否返回预期值。

关于 java-library 插件为任何 JVM 库项目添加的特性(例如 API 和实现的隔离),更多信息可以在 Java 库插件文档 中找到。

组装库 JAR

要构建项目,运行 build 任务。您可以使用常规的 gradle 命令,但当项目包含 wrapper 脚本时,建议使用它。

$ ./gradlew build

BUILD SUCCESSFUL in 0s
4 actionable tasks: 4 executed
第一次运行 wrapper 脚本 gradlew 时,可能会出现延迟,因为该版本的 gradle 会被下载并本地存储在您的 ~/.gradle/wrapper/dists 文件夹中。

第一次运行构建时,Gradle 会检查您的 ~/.gradle 目录下的缓存中是否已有所需的依赖项。如果没有,库将被下载并存储在那里。下次运行构建时,将使用缓存的版本。build 任务会编译类、运行测试并生成测试报告。

您可以通过打开位于 lib/build/reports/tests/test/index.html 的 HTML 输出文件来查看测试报告。

您可以在 lib/build/libs 目录中找到新打包的 JAR 文件,文件名为 lib.jar。运行以下命令来验证存档是否有效

$ jar tf lib/build/libs/lib.jar
META-INF/
META-INF/MANIFEST.MF
lib/
lib/Library.class

您应该会看到必需的清单文件 —MANIFEST.MF— 和编译后的 Library 类。

所有这些都无需在构建脚本中进行额外配置,因为 Gradle 的 java-library 插件假定您的项目源文件按照 约定式项目布局 进行排列。如果需要,您可以按照 用户手册中的说明 自定义项目布局。

恭喜,您已成功完成了创建 Scala 库的第一步!现在您可以根据自己的项目需求进行自定义。

自定义库 JAR

您通常希望 JAR 文件名包含库的 版本。这可以通过在构建脚本中设置顶级的 version 属性来实现

build.gradle.kts
version = "0.1.0"
build.gradle
version = '0.1.0'

除了版本之外,库的其他重要标识属性是其 名称。名称直接来源于代表该库的子项目名称。在示例中是 lib,所以您可能需要通过更改 lib 文件夹的名称以及 settings.gradle(.kts) 文件中相应的 include(…​) 语句来调整它。 用于在发布时为您的库提供完整的坐标。您可以直接在构建脚本中通过设置 group 属性来定义它,方式类似于设置版本(如上所示)。

现在运行 jar 任务

$ ./gradlew jar

BUILD SUCCESSFUL
2 actionable tasks: 1 executed, 1 up-to-date

您会注意到,生成的位于 lib/build/libs/lib-0.1.0.jar 的 JAR 文件包含版本,与预期一致。

另一个常见的需求是自定义清单文件,通常是通过添加一个或多个属性来实现。让我们通过 配置 jar 任务 将库名称和版本包含在清单文件中。将以下内容添加到构建脚本末尾

build.gradle.kts
tasks.jar {
    manifest {
        attributes(mapOf("Implementation-Title" to project.name,
                         "Implementation-Version" to project.version))
    }
}
build.gradle
tasks.named('jar') {
    manifest {
        attributes('Implementation-Title': project.name,
                   'Implementation-Version': project.version)
    }
}

为了确认这些更改按预期工作,再次运行 jar 任务,这次也从 JAR 中解压清单文件

$ ./gradlew jar
$ jar xf lib/build/libs/lib-0.1.0.jar META-INF/MANIFEST.MF

现在查看 META-INF/MANIFEST.MF 文件的内容,您应该会看到以下内容

META-INF/MANIFEST.MF
Manifest-Version: 1.0
Implementation-Title: lib
Implementation-Version: 0.1.0

生成源代码 JAR

您可以轻松地为您的库生成一个源代码 JAR

build.gradle.kts
java {
    withSourcesJar()
}
build.gradle
java {
    withSourcesJar()
}

这个额外的 JAR 将作为 assemblebuild 生命周期任务的一部分生成,并将作为发布的一部分。生成的文件位于 lib/build/libs 中,名称使用约定的分类器 -sources

发布构建扫描

了解构建在幕后做了什么的最佳方法是发布 构建扫描。为此,只需运行带有 --scan 标志的 Gradle。

$ ./gradlew build --scan

BUILD SUCCESSFUL in 0s
4 actionable tasks: 4 executed

Publishing a build scan to scans.gradle.com requires accepting the Gradle Terms of Service defined at https://gradle.com/terms-of-service.
Do you accept these terms? [yes, no] yes

Gradle Terms of Service accepted.

Publishing build scan...
https://gradle.com/s/5u4w3gxeurtd2

点击链接,探索执行了哪些任务、下载了哪些依赖项以及更多细节!

总结

就这样!您现在已经成功地使用 Gradle 配置并构建了一个 Scala 库项目。您已经学会了如何

  • 初始化一个用于生成 Scala 库的项目

  • 运行构建并查看测试报告

  • 自定义构建生成的 Jar 文件

现在,您可以通过尝试编译一些使用您刚刚构建的库的 Scala 代码来完成此练习。

后续步骤

构建库只是跨项目边界重用代码的一个方面。接下来,您可能会对以下内容感兴趣