构建配置
sbt
项目根目录下的build.sbt
定义了项目的构建配置。
project
目录下也可以添加*.scala
构建定义。
可以在build.sbt
文件中设定项目的名称、版本信息、构建规则、依赖等配置。
build.sbt
文件遵循Scala
语法。
一个简单的build.sbt
文件内容如下所示:
name := "项目名称"
version := "项目版本号"
scalaVersion := "Scala编译器版本号"
libraryDependencies ++= Seq(
"xx" % "xx" % "xx", //项目Java依赖
...
"xx" % "xx" %% "xx", //项目Scala依赖
...
)
scalacOptions ++= Seq(
"-xxx", //编译器选项
...
)
enablePlugins(Xxx) //启用插件
sbt shell
只在启动时读取一遍构建配置。
若在sbt shell
开启之后build.sbt
文件发生了修改,则已经开启的sbt shell
依旧使用之前的构建配置。
若需要已开启的sbt shell
使用新的构建配置,则应在sbt shell
中使用reload
指令重新加载构建配置。
自定义源码路径
sbt
项目默认源码路径为项目根目录/src
,若需要管理默认路径之外的源码,在build.sbt
中添加:
// 获取源码绝对路径,并构建 File 实例
def sourceDir(dir: String) = file(s"${file(".").getAbsolutePath}/$dir")
// 自定义源码路径需要修改 unmanagedSourceDirectories 配置项
unmanagedSourceDirectories in Compile ++= Seq(
sourceDir("子目录1"),
sourceDir("子目录2"),
...
)
多项目构建
sbt
支持多项目构建,一个项目中可包含多个子项目。
每个子项目均可包含独立、完整的构建配置。
使用sbt
环境中预定义的project
方法指定子项目的路径:
// 子项目的根路径为当前路径下的 xxx 子路径
// 子项目名称 ChildProject (变量名称)
lazy val ChildProject = project in file("xxx")
project
方法构建的实例类型为sbt.Project
,代表子项目的构建定义,实例名称会作为子项目的ID
。
若project in file("xxx")
中的路径信息xxx
为.
(项目当前路径)时,获取的实例代表默认项目的构建定义。
sbt.Project
类型定义了一系列控制构建配置的方法:
package sbt
sealed trait Project extends AnyRef with ProjectDefinition[ProjectReference] {
...
def in(dir : java.io.File): Project = ... //设置构建定义的对应路径
def configs(cs: librarymanagement.Configuration*): Project = ...
def dependsOn(deps: ClasspathDep[ProjectReference]*): Project = ... //设置项目依赖
def settings(ss: Def.SettingsDefinition*): Project = ... //设置项目通用配置
def enablePlugins(ns: Plugins*): Project = ... //启用SBT插件
def disablePlugins(ps: AutoPlugin*) : Project = ... //禁用SBT插件
...
}
使用settings()
方法向项目中添加通用定义:
childProject
.settings(
libraryDependencies ++= Seq(
...
),
scalacOptions ++= Seq(
...
),
...)
所有能在父级项目中设定的配置都可以添加在子项目的settings()
方法中。
使用enablePlugins()/disablePlugins()
方法启用/禁用sbt
插件。
使用dependsOn()
方法设定依赖项目,子项目能引用依赖项目的代码,并自动引入依赖项目的libraryDependencies
。
sbt.Project
类型的主要方法均返回自身实例,支持链式调用。
常见的配置结构,如下所示:
val root = project in file(".") //父项目配置
.settings(
...
)
...
val child = (project in file("xxx")) //子项目配置
.dependsOn(root) //设定依赖项目
.enablePlugins(xxx) //启用插件
.settings( //配置相
name := "xxx",
version := "xxx",
scalaVersion := "2.12.x"
libraryDependencies ++= Seq(
... //jar包依赖
),
scalacOptions ++= Seq(
... //编译器配置
),
...
)
访问构建信息
sbt
没有提供访问build.sbt
中项目构建信息的接口,使用sbt
插件sbt-buildinfo
可以让项目访问sbt
的构建信息。
在sbt
项目中的project/plugins.sbt
文件中引入该插件:
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "版本号")
在项目构建配置文件build.sbt
中启用sbt-buildinfo
插件:
enablePlugins(BuildInfoPlugin)
sbt-buildinfo
插件的原理是利用build.sbt
中的项目构建信息在项目构建时生成额外的源码,
并以单例对象的形式将构建信息提供给项目源码进行访问。
启用sbt-buildinfo
插件后会增加插件相关的配置项。
将build.sbt
中的name、version、scalaVersion、sbtVersion
等配置项传入sbt-buildinfo
插件的buildInfoKeys
配置项,
通过buildInfoPackage
配置项设定生成单例的包路径。
在build.sbt
文件中配置sbt-buildinfo
插件,实例如下:
// sbt项目构建信息
name := "xxx"
version := "xxx"
scalaVersion := "2.12.3"
sbtVersion := "0.13.16"
// 启用 sbt-buildinfo 插件
enablePlugins(BuildInfoPlugin)
// 设定构建信息
buildInfoKeys := Seq(name, version, scalaVersion, sbtVersion)
buildInfoPackage := "xxx.yyy.zzz" //将构建信息生成到 xxx.yyy.zzz 包路径中
sbt-buildinfo
插件生成的单例对象结构如下所示:
case object BuildInfo {
/** The value is "xxx". */
val name: String = "xxx"
/** The value is "xxx". */
val version: String = "xxx"
/** The value is "2.12.2". */
val scalaVersion: String = "2.12.2"
/** The value is "0.13.15". */
val sbtVersion: String = "0.13.15"
override val toString: String = {
"name: %s, version: %s, scalaVersion: %s, sbtVersion: %s" format (
name, version, scalaVersion, sbtVersion
)
}
}
处理构建冲突
jar
打包时将多个jar
包依赖引入同一个包时,若依赖的jar
包包含相对路径相同的目录、文件,则可能产生冲突。
如com.typesafe.slick:slick
和com.typesafe.akka:akka-actor
包中的根路径下均包含reference.conf
配置文件,
该配置记录了模块运行时必要的默认配置。
若打包时同时依赖这两个包,则生成的jar
包中reference.conf
文件只会保留一份。
运行时akka-actor
或slick
可能会因为缺少默认配置异常退出。
使用sbt-assembly
插件可处理构建流程中的文件冲突。
在build.sbt
中添加:
assemblyMergeStrategy in assembly := {
case PathList("reference.c·onf") => MergeStrategy.concat //合并冲突文件内容
}
若使用IDEA
提供的打包工具,则sbt-assembly
插件不会生效。
解决冲突文件的方案是在项目resource
路径下手动创建冲突文件,手动合并来自不同包的冲突文件内容。