sbt笔记七 依赖管理

类库依赖可以通过两种方式添加
  • 非托管依赖(unmanaged dependencies)是把jar文件放到lib目录
  • 托管依赖(managed dependencies)是在构建定义中配置,并自动从资源仓库下载

非托管依赖

大多数人使用托管依赖代替非托管依赖。但用非托管可以更简单地开始。
非托管依赖像这样工作:添加jar文件到lib,它们会放在项目的classpath中。
你也可以把测试jar包放在lib里,比如ScalaCheck,specs和ScalaTest。
在lib中的依赖会添加到所有classpath中(compile,test,run和console)。如果你想改变其中一个的classpath,你可以调整 dependencyClasspath in Compile或 dependencyClasspath in Runtime。你可以用~=来获得先前的classpath值,过滤掉其中一些,并返回一个新的classpath值。~=更多细节见 more about settings
非托管依赖不需要向build.sbt添加任何东西,但是如果你想用另一个文件夹而不是lib,那么可以修改unmanaged-base键。
用custom_lib代替lib:
unmanagedBase <<= baseDirectory { base => base / "custom_lib" }
baseDirectory是项目根目录,在这里修改后的unmanagedBase依赖于baseDirectory,<<=的用法more about settings

另外,还有一个unmanaged-jars任务用来列出unmanaged-base文件夹中的jar文件。如果你想使用多个文件夹或做一些更复杂的事情,你可能需要替换整个unmanaged-jars任务来做其他事情。

托管依赖

sbt使用Apache Ivy来实现托管依赖,所以如果你熟悉Maven或Ivy,就不会有太多麻烦。

The libraryDependencies key

大多数时间,你可以简单地在libraryDependencies设置中列出你的依赖包。写一个Maven POM文件或Ivy配置文件来配置你的依赖,让sbt使用这些外部配置文件也是可以的。

声明一个依赖看起来是这样的,其中groupId,artifactId和revision是字符串:
libraryDependencies += groupID % artifactID % revision
或这样,其中configuration也是字符串:
libraryDependencies += groupID % artifactID % revision % configuration
libraryDependencies在Keys中是这样声明的:
val libraryDependencies = SettingKey[Seq[ModuleID]]("library-dependencies","Declares managed dependencies.")
%方法字符串创建一个ModuleID对象,然后添加这个ModuleID到libraryDependencies。
当然,sbt(通过Ivy)必须知道去哪下载这些模块。如果你的模块在sbt的其中一个认资源仓库中,它就可以工作。例如,Apache Derby就在认资源仓库中:
libraryDependencies += "org.apache.derby" % "derby" % "10.4.1.3"
如果你在build.sbt中输入,然后update,sbt将Derby下载到~/.ivy2/cache/org.apache.derby/。(顺便说一下,update是compile的依赖,所以大部分时间不需要手动输入update。)

当然,你可以使用++=来一次性添加一个依赖列表:
libraryDependencies ++= Seq(
    groupID % artifactID % revision,groupID % otherID % otherRevision
)

在很少情况下,你也可能会找到理由来使用:=,<<=,<+=等。

用%%来获得正确的Scala版本(Getting the right Scala version with %%)

如果你使用groupID %% artifactID % revision(而不是groupID % artifactID % revision,区别在于groupID后有两个%%),sbt会将项目的Scala版本添加到artifact name。这是一个简单的例子,你可以不用%%:
libraryDependencies += "org.scala-tools" % "scala-stm_2.9.1" % "0.3"
假设你的构建的scalaVersion是2.9.1,那么用下面的表达式也是一样的:
libraryDependencies += "org.scala-tools" %% "scala-stm" % "0.3"
这个概念是由于很多依赖包被编译为多个Scala版本,并且你希望得到和你项目匹配的那个。
这个实践的复杂性在于,通常一个依赖包能够工作在有细微不同的Scala版本中;但%%不太智能。所以如果依赖在2.9.0中有效,但你使用scalaVersion := "2.9.1",那么你将不能使用%%,即使2.9.0依赖很可能能够工作。如果%%停止工作,就检查一下这个依赖实际上是为哪个版本构建的,并硬编码那个你认为能够工作的(假设有这么一个)。

更多细节,查看Cross-building

Ivy revisions

groupID % artifactID % revision中的revision可以不是唯一固定的版本。Ivy可以选择模块的最后修订版本,来代替固定修订版本比如“1.6.1”,你需要指定"latest.integration""2.9.+""[1.0,)"。更多细节查看Ivy revisions文档。

Resolvers

不是所有包都在同一个服务器上,sbt认使用标准Maven2资源仓库。如果你的依赖不在任何一个认资源仓库中,你必须添加一个resolver来帮助Ivy找到它。

添加一个额外的资源仓库,使用

resolvers += name at location

例如:

resolvers += "Sonatype OSS Snapshots" at  "https://oss.sonatype.org/content/repositories/snapshots"

resolvers键在Keys中这样定义:

val resolvers = SettingKey[Seq[Resolver]]("resolvers","The user-defined additional resolvers for automatically managed dependencies.")
at方法从两个字符串创建一个Resolver对象。
sbt可以搜索本地Maven资源仓库(如果你添加它作为资源仓库):
resolvers += "Local Maven Repository" at "file://"+Path.userHome.absolutePath+"/.m2/repository"
查看 Resolvers获得更多关于定义其他资源仓库的类型的细节。

覆盖认resolvers

resolvers不包含认resolvers;只有在你的构建定义文件添加的额外内容
sbt联合resolvers与认资源仓库构成external-resolvers。

因此,想要改变或移除认resolvers,你需要重写external-resolvers(代替resolvers)。

Per-configuration dependencies

经常一个依赖被你的测试代码使用(在src/test/scala,被Test配置编译)而不是main代码
如果你想让一个依赖出现在Test配置的classpath中,而不在Compile配置中,添加% "test",像这样:
libraryDependencies += "org.apache.derby" % "derby" % "10.4.1.3" % "test"
现在,如果你在sbt交互提示符中输入show compile:dependency-classpath,不能看到derby。但如果你输入show test:dependency-classpath,你就能够在列表中看到derby的jar。

测试相关的依赖比如ScalaCheck,specs和ScalaTest需要用% "test"定义。

相关文章

迭代器模式(Iterator)迭代器模式(Iterator)[Cursor]意图...
高性能IO模型浅析服务器端编程经常需要构造高性能的IO模型,...
策略模式(Strategy)策略模式(Strategy)[Policy]意图:定...
访问者模式(Visitor)访问者模式(Visitor)意图:表示一个...
命令模式(Command)命令模式(Command)[Action/Transactio...
生成器模式(Builder)生成器模式(Builder)意图:将一个对...