sbt update
基本的な導入としては、入門ガイドのライブラリ依存性の基礎をまずは読んでみてほしい。
概要
sbt [query / ] update
説明
sbt は Coursier を使ってライブラリ管理(他エコシステムではパッケージマネージャーとも呼ばれる)を実装している。ライブラリ管理の一般的な考え方は、
- 指定リポジトリにそのバージョンが存在するか確認する
- 間接依存ライブラリ(つまり、ライブラリが使用しているライブラリ)を検索する
- バージョン競合があれば解決を試みる
- リポジトリから JAR ファイルなどのアーティファクトをダウンロードする
ライブラリ依存性
ライブラリ依存性の宣言は以下のようになる:
libraryDependencies += groupID %% artifactID % revision
または
libraryDependencies += groupID %% artifactID % revision % configuration
複数のライブラリ依存性をまとめて宣言することもできる:
libraryDependencies ++= Seq(
groupID %% artifactID % revision,
groupID %% otherID % otherRevision
)
sbt でビルドされたライブラリ依存性を使用する場合、最初の % を %% にする:
libraryDependencies += groupID %% artifactID % revision
これにより、現在使用している Scala のバージョンでビルドされたライブラリ依存性に正しい JAR が使用される。この種のライブラリ依存性の解決中にエラーが発生した場合、そのライブラリ依存性は使用している Scala のバージョン用に公開されていない可能性がある。詳細はクロスビルドを参照。
versionScheme と eviction エラー
sbt では、ライブラリ作者が versionScheme セッティングを使ってバージョン意味論を宣言できる:
// 0.x および 1.x、2.x などにセマンティックバージョニングを適用
versionScheme := Some(VersionScheme.EarlySemVer)
Coursier がライブラリの複数バージョン(例えば Cats Effect 2.x と Cats Effect 3.0.0-M4)を検出すると、グラフから古いバージョンを削除して競合を解決することが多い。このプロセスは eviction(退去)と呼ばれ、「Cats Effect 2.2.0 evict された」のように表現される。
新しいバージョンが Cats Effect 2.2.0 とバイナリ互換性がある場合は問題ない。今回のケースでは、ライブラリ作者がバイナリ互換性がないと宣言しているため、eviction は実際には安全ではない。 安全でない eviction は ClassNotFoundException などのランタイム問題を引き起こすため、Coursier は解決に失敗すべきだった。
lazy val use = project
.settings(
name := "use",
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-blaze-server" % "0.21.11",
"org.typelevel" %% "cats-effect" % "3.0.0-M4",
),
)
sbt は Coursier が候補を返した後に、この二次互換性チェックを行う:
[error] stack trace is suppressed; run last use / update for the full output
[error] (use / update) found version conflict(s) in library dependencies; some are suspected to be binary incompatible:
[error]
[error] * org.typelevel:cats-effect_2.12:3.0.0-M4 (early-semver) is selected over {2.2.0, 2.0.0, 2.0.0, 2.2.0}
[error] +- use:use_2.12:0.1.0-SNAPSHOT (depends on 3.0.0-M4)
[error] +- org.http4s:http4s-core_2.12:0.21.11 (depends on 2.2.0)
[error] +- io.chrisdavenport:vault_2.12:2.0.0 (depends on 2.0.0)
[error] +- io.chrisdavenport:unique_2.12:2.0.0 (depends on 2.0.0)
[error] +- co.fs2:fs2-core_2.12:2.4.5 (depends on 2.2.0)
[error]
[error]
[error] this can be overridden using libraryDependencySchemes or evictionErrorLevel
この機構は eviction エラー と呼ばれる。
eviction エラーを無効にする
ライブラリ作者が互換性の破壊を宣言している場合でも、厳格なチェックを無視したい場合(scala-xml でよくある)は、project/plugins.sbt と build.sbt に以下を記述する:
libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always
全ての eviction エラーを無視するには:
evictionErrorLevel := Level.Info
リゾルバ
sbt はデフォルトで標準の Maven Central リポジトリを使用する。追加のリポジトリは以下の形式で宣言する:
resolvers += name at location
例:
libraryDependencies ++= Seq(
"org.apache.derby" % "derby" % "10.4.1.3",
"org.specs" % "specs" % "1.6.1"
)
resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
リポジトリとして追加すれば、sbt はローカルの Maven リポジトリを検索できる:
resolvers += Resolver.mavenLocal
デフォルトのリゾルバを上書きする
resolvers は追加のインラインユーザーリゾルバを設定する。デフォルトでは、sbt はこれらのリゾルバとデフォルトリポジトリ(Maven Central とローカル Ivy リポジトリ)を組み合わせて externalResolvers を形成する。リポジトリをより細かく制御するには、externalResolvers を直接設定する。通常のデフォルトに加えてリポジトリを指定するだけの場合は、resolvers を設定する。
例えば、デフォルトのリポジトリに加えて Sonatype OSS Snapshots リポジトリを使用するには、
resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
ローカルリポジトリを使用し、Maven Central は使用しない場合:
externalResolvers := Resolver.combineDefaultResolvers(resolvers.value.toVector, mavenCentral = false)
全てのビルドのリゾルバを上書きする
sbt、Scala、プラグイン、アプリケーションのライブラリ依存依存性の取得に使用するリポジトリは、グローバルに設定し、ビルドまたはプラグイン定義で設定されたリゾルバを上書きするように宣言できる。以下の 2つの手順を踏む:
- ランチャー用のリポジトリを定義する。
- これらのリポジトリがビルド定義のリポジトリを上書きすることを指定する。
ランチャーが使用するリポジトリは、~/.sbt/repositories を定義することで上書きできる。このファイルには Launcher 設定ファイルと同じ形式の [repositories] セクションを含める必要がある。例:
[repositories]
local
my-maven-repo: https://example.org/repo
my-ivy-repo: https://example.org/ivy-repo/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]
リポジトリファイルの別の場所は、sbt 起動スクリプトの sbt.repository.config システムプロパティで指定できる。最後に、ライブラリ依存性の解決と取得にこれらのリポジトリを使用するには、sbt.override.build.repos を true に設定する。
間接依存ライブラリを除外する
特定のケースでは、間接依存ライブラリを全てのライブラリ依存性から除外する必要がある。excludeDependencies で ExclusionRules を設定することで実現できる。
excludeDependencies ++= Seq(
// commons-logging は jcl-over-slf4j で置き換えられる
ExclusionRule("commons-logging", "commons-logging")
)
ライブラリ依存性の特定の間接依存ライブラリを除外するには、excludeAll または exclude メソッドを使用する。プロジェクト用の POM を公開する場合は exclude メソッドを使用する。除外するには組織名とモジュール名が必要である。例:
libraryDependencies +=
("log4j" % "log4j" % "1.2.15").exclude("javax.jms", "jms")
明示的な URL
プロジェクトにリポジトリに存在しないライブラリ依存性が必要な場合、その jar への直接 URL を以下のように指定できる:
libraryDependencies += "slinky" % "slinky" % "2.1" from "https://slinky2.googlecode.com/svn/artifacts/2.1/slinky.jar"
URL は、設定されたリポジトリでライブラリ依存性が見つからない場合のフォールバックとしてのみ使用される。また、明示的な URL は公開メタデータ(pom や ivy.xml)には含まれない。
推移性を無効にする
デフォルトでは、これらの宣言は全てのプロジェクトライブラリ依存性を推移的に取得する。場合によっては、プロジェクトにリストされたライブラリ依存性がビルドに不要なことがある。例えば、Felix OSGI フレームワークを使用するプロジェクトでは、コンパイルと実行にメイン jar のみが明示的に必要である。この例のように intransitive() またはnotTransitive() でアーティファクトのライブラリ依存性の取得を避ける:
libraryDependencies += ("org.apache.felix" % "org.apache.felix.framework" % "1.8.0").intransitive()
クラシファイア
classifier メソッドでライブラリ依存性のクラシファイアを指定できる。例えば、TestNG の jdk15 バージョンを取得するには:
libraryDependencies += ("org.testng" % "testng" % "5.7").classifier("jdk15")
複数のクラシファイアには、複数回 classifier を呼び出す:
libraryDependencies +=
"org.lwjgl.lwjgl" % "lwjgl-platform" % lwjglVersion classifier "natives-windows" classifier "natives-linux" classifier "natives-osx"
全てのライブラリ依存性の特定クラシファイアを推移的に取得するには、updateClassifiers タスクを実行する。デフォルトでは、sources または javadoc クラシファイアを持つ全アーティファクトを解決する。取得するクラシファイアは transitiveClassifiers セッティングで選択する。例えば、ソースのみを取得するには:
transitiveClassifiers := Seq("sources")
ソースのダウンロード
ソースと API ドキュメントの JAR ファイルのダウンロードは通常 IDE プラグインが行う。これらのプラグインは updateClassifiers と updateSbtClassifiers タスクを使用し、これらの JAR を参照する UpdateReport を生成する。
IDE プラグインを使わずに sbt にライブラリ依存性のソースをダウンロードさせるには、ライブラリ依存性の定義に withSources() を追加する。API JAR をダウンロードするには withJavadoc() を追加する。例:
libraryDependencies +=
("org.apache.felix" % "org.apache.felix.framework" % "1.8.0").withSources().withJavadoc()
これは推移的ではないことに注意。その場合は update*Classifiers タスクを使用する。