build.sbt 是非常簡單的,其隱藏了sbt真正工作的一些細節(jié),sbt 是由Scala語言編寫的,其自身也需要構(gòu)建,那么由什么好的辦法來實現(xiàn)呢?
project目錄是在構(gòu)建項目中的另一個項目,它負責(zé)整個項目的構(gòu)建定義,理論上在project目錄下還可以有另一個project項目(遞歸),其構(gòu)建的是sbt項目本身用來支撐上級項目的構(gòu)建。
例如,你可以在構(gòu)建項目下再次創(chuàng)建一個項目,以下是目錄層級結(jié)構(gòu):
hello/ # your project's base directory
Hello.scala # a source file in your project (could be in
# src/main/scala too)
build.sbt # build.sbt is part of the source code for the
# build definition project inside project/
project/ # base directory of the build definition project
Build.scala # a source file in the project/ project,
# that is, a source file in the build definition
build.sbt # this is part of a build definition for a project
# in project/project ; build definition's build
# definition
project/ # base directory of the build definition project
# for the build definition
Build.scala # source file in the project/project/ project
不用擔(dān)心,大部分情況下是不需要創(chuàng)建這個的,但是理解這個概念對運用sbt很有幫助。
順便說一下,任何以 .sbt或.scala后綴的定義文件都會被用到,經(jīng)常說的build.sbt或Build.scala命名只是為了方便而已,也就是說sbt配置支持多文件配置。
.sbt文件定義將被合并到子目錄project中,例如如下項目目錄結(jié)構(gòu):
hello/ # your project's base directory
build.sbt # build.sbt is part of the source code for the
# build definition project inside project/
project/ # base directory of the build definition project
Build.scala # a source file in the project/ project,
# that is, a source file in the build definition
在build.sbt中的 Scala 配置表達式將會被編譯合并到Build.scala中(或者是在project目錄下的任何.scala文件中)。
在項目根目錄的*.sbt 文件將會變成在根目錄下project構(gòu)建項目定義的一部分。.sbt只是為了定義項目方便。
對于在構(gòu)建項目定義中混合的 .sbt和.scala定義,你需要理解它們之間的關(guān)系,以下是兩個文件的例子,首先,假設(shè)一個項目 hello, 創(chuàng)建hello/project/Build.scala如下:
import sbt._
import Keys._
object HelloBuild extends Build {
val sampleKeyA = settingKey[String]("demo key A")
val sampleKeyB = settingKey[String]("demo key B")
val sampleKeyC = settingKey[String]("demo key C")
val sampleKeyD = settingKey[String]("demo key D")
override lazy val settings = super.settings ++
Seq(
sampleKeyA := "A: in Build.settings in Build.scala",
resolvers := Seq()
)
lazy val root = Project(id = "hello",
base = file("."),
settings = Seq(
sampleKeyB := "B: in the root project settings in Build.scala"
))
}
創(chuàng)建hello/build.sbt如下:
sampleKeyC in ThisBuild := "C: in build.sbt scoped to ThisBuild"
sampleKeyD := "D: in build.sbt"
啟動sbt的交互模式,輸入inspect sampleKeyA將會看到:
[info] Setting: java.lang.String = A: in Build.settings in Build.scala
[info] Provided by:
[info] {file:/home/hp/checkout/hello/}/*:sampleKeyA
然后輸入inspect sampleKeyC 顯示如下:
[info] Setting: java.lang.String = C: in build.sbt scoped to ThisBuild
[info] Provided by:
[info] {file:/home/hp/checkout/hello/}/*:sampleKeyC
"Provided by" 顯示這兩個參數(shù)配置的作用域是相同的,在 .sbt文件中配置sampleKeyC in ThisBuild等同于在 .scala文件中的Build.settings 中配置的值,在上述兩個地方配置的值得作用域都是工程級別的作用域。
現(xiàn)在,在查看sampleKeyB:
[info] Setting: java.lang.String = B: in the root project settings in Build.scala
[info] Provided by:
[info] {file:/home/hp/checkout/hello/}hello/*:sampleKeyB
sampleKeyB 的作用域是項目維度的({file:/home/hp/checkout/hello/}hello)不再是工程級別的作用域。
你可能猜到inspect sampleKeyD 和sampleKeyB的一樣:
[info] Setting: java.lang.String = D: in build.sbt
[info] Provided by:
[info] {file:/home/hp/checkout/hello/}hello/*:sampleKeyD
sbt 在 .sbt 文件中追加配置Build.settings 和 Project.settings 配置的優(yōu)先級比.scala文件的高,所以配置在 .sbt 文件中的sampleC 或 sampleD會修改Build.scala的配置。
另一個需要注意的是:sampleKeyC 和 sampleKeyD 可以定義在build.sbt 中定義,這是因為sbt會將Build 對象自動隱式的導(dǎo)入到.sbt文件中,例如這個例子sbt 會將 HelloBuild._ 隱式的導(dǎo)入到build.sbt 文件中。
總結(jié):
.scala文件中,可以定義 Build.settings f配置項供sbt查找,其作用域自動為工程級別的作用域.scala文件中,可以定義 Project.settings配置項供sbt查找,其作用域自動為項目維度的作用域.scala文件中的任何Build對象,都會自動的導(dǎo)入到所有的.sbt文件中.sbt 文件中的配置將會被追加到.scala 文件中.sbt文件中的配置默認是項目維度的作用域,除非手動指定其他作用域.scala 配置文件可以用任何的Scala代碼編寫,包括頂級的類和對象,由于它是標準的Scala語法,所以也沒有必須添加空行來分割配置的限制
在配置參數(shù)配置推薦用.sbt配置文件,當(dāng)要實現(xiàn)一些任務(wù)配置或者要定義一些復(fù)用配置供多個.sbt文件使用的情況推薦使用.scala配置文件
你可以在交互模式下,切換到在project目錄下的構(gòu)建工程項目的項目中, 當(dāng)切換到該項目中后可以執(zhí)行一些操作,如reload plugins.等
> reload plugins
[info] Set current project to default-a0e8e4 (in build file:/home/hp/checkout/hello/project/)
> show sources
[info] ArrayBuffer(/home/hp/checkout/hello/project/Build.scala)
> reload return
[info] Loading project definition from /home/hp/checkout/hello/project
[info] Set current project to hello (in build file:/home/hp/checkout/hello/)
> show sources
[info] ArrayBuffer(/home/hp/checkout/hello/hw.scala)
>
正如上面的例子,你可以用reload return命令來退出當(dāng)前工程構(gòu)建項目的項目,回到常規(guī)的項目中。
sbt 配置可能被錯誤的理解為在build.sbt的配置將會被添加到Build 或Project 對象的settings 字段中,其實settings 是 Build 和 Project的列表,build.sbt中的配置將會被和一個不可變的配置列表連接起來生成一個新的列表供sbt使用的, Build 和 Project中的“不可變配置”列表僅僅是完成sbt配置的一部分。
事實上,還有其他的配置文件,它們將會按照如下順序添加:
.scala文件中的Build.settings和Project.settings配置項~/.sbt/0.13/global.sbt文件中可以配置影響所有工程構(gòu)建的配置項.sbt文件配置的配置項后面的配置將會重載前面的配置,最后生成一個配置列表。