一個(gè)項(xiàng)目的構(gòu)建定義可以是在項(xiàng)目根目錄中以 .sbt 后綴結(jié)尾的文件,也可以是一個(gè)在子目錄 project 下以 .scala 結(jié)尾的文件
這章主要討論 .sbt 文件定義,這種定義已經(jīng)適合大部分情況. .scala 定義方式典型的用在多個(gè) .sbt 文件分享共用的定義語(yǔ)句或者是復(fù)雜的項(xiàng)目構(gòu)建中。更多信息參考.scala 定義
通過(guò)驗(yàn)證和解析構(gòu)建語(yǔ)句文件, sbt 以一個(gè)不可變 Map(key-value 鍵值對(duì))來(lái)描述構(gòu)建過(guò)程結(jié)束
例如,一個(gè) key 為 name 并且它的 Map 值是字符串,這個(gè)配置項(xiàng)name代表這個(gè)項(xiàng)目的名稱
構(gòu)建語(yǔ)句定義不會(huì)直接修改影響 sbt 的Map
相反,構(gòu)建語(yǔ)句是一個(gè)由Setting[T]類(lèi)型的對(duì)象構(gòu)成大的列表構(gòu)成,T是 Setting Map 值的類(lèi)型, Setting可以通過(guò)以下幾種方式修改map:添加一個(gè)新的鍵值對(duì)、修改以存在的key的值(在函數(shù)式編程中一個(gè)不可變數(shù)據(jù)結(jié)構(gòu)和值,通過(guò)新賦值的方式來(lái)修改值,而不是在原值的基礎(chǔ)上修改)
在build.sbt 中你可能要?jiǎng)?chuàng)建一個(gè) Setting[String] 類(lèi)型的配置項(xiàng)申明項(xiàng)目名稱:
name := "hello"
這個(gè) Setting[String] 通過(guò)添加或替換原有key值來(lái)修改,并且賦值為"hello" ,這個(gè)修改的 map 變成一個(gè)新的map。 創(chuàng)建一個(gè) map,sbt 首先配置列表所有修改的配置放在一塊,并且如果有的配置值依賴某些配置項(xiàng)將在依賴的配置項(xiàng)后處理。然后 sbt 利用排序后的配置項(xiàng)構(gòu)建新的 map
總結(jié):構(gòu)建語(yǔ)句是一個(gè) Setting[T] 組成的列表, Setting[T]是一個(gè)可以通過(guò)修改的map key-value 鍵值對(duì)構(gòu)成, T是鍵值對(duì)值的類(lèi)型
build.sbt 是一個(gè) Seq[Setting[_]], 是一系列用空行分割 Scala 表達(dá)式,每行是這個(gè)序列的一個(gè)元素.
例如:
name := "hello"
version := "1.0"
scalaVersion := "2.10.3"
每個(gè)配置項(xiàng)都是一個(gè) scala 表達(dá)式,在 build.sbt 中的表達(dá)式都是獨(dú)立而不是一個(gè) scala 代碼塊. 這些表達(dá)式由 val、lazy val 和 def 構(gòu)成,對(duì)象和類(lèi)不允許定義在 build.sbt 中,應(yīng)該定義在子目錄 project 中的 .scala 源代碼文件中。
配置表達(dá)式的左值如 name, version 和 scalaVersion 是配置項(xiàng)的 key, key 是 SettingKey[T], TaskKey[T]或 InputKey[T] 的實(shí)例,其中 T 是期望值的類(lèi)型,具體key的類(lèi)型將在下面介紹。
Key 對(duì)象有一個(gè)方法 := 調(diào)用將返回 Setting[T], 你可以用 Java 語(yǔ)法風(fēng)格調(diào)用:
name.:=("hello")
在 Scala 中允許 name := "hello" 方式調(diào)用(在Scala中對(duì)于單個(gè)參數(shù)的方法允許這種形式調(diào)用)
name 的 := 方法返回一個(gè) Setting 對(duì)象,其中具體的類(lèi)型為Setting[String], 泛型類(lèi)型 String 在 name key 本身定義中也出現(xiàn)了,但是 name 類(lèi)型為 SettingKey[String]. 在這個(gè)例子中,將返回的 Setting[String] 對(duì)象通過(guò)添加或者替換得到一個(gè)新的 sbt 配置項(xiàng) map, 并給定值為"hello"
如果給定一個(gè)錯(cuò)誤類(lèi)型的配置值,將無(wú)法編譯通過(guò)
name := 42 // will not compile
不允許在budil.sbt將配置寫(xiě)成如下格式:
// will Not compile, not blank lines
name := "hello"
version := "1.0"
scalaVersion := "2.10.3"
sbt 需要一個(gè)分隔符用來(lái)判斷一個(gè)表達(dá)式結(jié)束和另一個(gè)表達(dá)式起始, .sbt 文件中包含一系列 Scala 表達(dá)式,不是單個(gè)一個(gè) Scala 項(xiàng)目,這些表達(dá)式必須分隔開(kāi)并且單獨(dú)進(jìn)行編譯.
內(nèi)建 Keys 是調(diào)用對(duì)象Keys的成員變量,對(duì)于 build.sbt 隱式包含 import sbt.Keys._, 所以sbt.Keys.name可以寫(xiě)作 name
自定義 keys 可以分別用 settingKey, taskKey和inputKey方法創(chuàng)建. 每個(gè)方法定義期望關(guān)聯(lián)值的類(lèi)型和該key的描述信息, 每個(gè)key 的名稱保存在 val 的常量中,例如, 定義一個(gè)名為 hello 的任務(wù)類(lèi)型的key
lazy val hello = taskKey[Unit]("an example task")
.sbt 可以包含 vals 和 defs 的定義,所有這類(lèi)型的定義將在解析配置項(xiàng)前執(zhí)行, vals 和 defs 定義必須和所有配置項(xiàng)配置用空行分割
注意: 一般情況下推薦用lazy val 替換用 val 可以避免初始化值得順序問(wèn)題
TaskKey[T] 被稱為一個(gè)任務(wù),任務(wù)操作如 compile 或 package, 它們可能返回一個(gè) Unit 類(lèi)型(Unit 在 Scala 中相當(dāng)于 void)或返回一個(gè)關(guān)聯(lián)的任務(wù),例如 package 這個(gè)任務(wù)將返回一個(gè) TaskKey[File] 創(chuàng)建jar包的任務(wù)
當(dāng)啟動(dòng)執(zhí)行一個(gè)任務(wù),例如執(zhí)行 compile 在交互模式下, sbt 將執(zhí)行和該任務(wù)相關(guān)的任務(wù), sbt 項(xiàng)目描述表(map)中可以保存一個(gè)字符串的配置項(xiàng)(例如name配置項(xiàng)),也可以是保存可執(zhí)行的代碼塊的任務(wù)(例如compile任務(wù)), 即使一個(gè)可執(zhí)行任務(wù)返回一個(gè)字符串,它也是在任何時(shí)候可重復(fù)執(zhí)行的
可以用 := 給一個(gè)配置項(xiàng)或任務(wù)賦值,對(duì)于配置項(xiàng)的值將在項(xiàng)目加載的時(shí)候一次性計(jì)算,對(duì)于任務(wù)在執(zhí)行的時(shí)候都會(huì)重新執(zhí)行計(jì)算
例如:
// task
hello := {println("Hello!")}
// settings
name := "hello"
Setting 通過(guò)一個(gè)任務(wù)key和一個(gè)配置項(xiàng)key創(chuàng)建出來(lái)的有細(xì)微的區(qū)別, taskKey := 42 結(jié)果是 Setting[Task[T]] 然而 settingKey := 42 結(jié)果是 Setting[T]. 對(duì)于大部分情況下基本看出來(lái)區(qū)別,因?yàn)槿蝿?wù)key依然創(chuàng)建一個(gè)類(lèi)型為T(mén)的值在任務(wù)執(zhí)行的時(shí)候
T 和 Task[T] 不同的另一個(gè)含義: 一個(gè)配置項(xiàng)不能依賴一個(gè)任務(wù),因?yàn)榕渲庙?xiàng)僅在項(xiàng)目初始化的時(shí)候計(jì)算一次.
在sbt交互模式下,你可以執(zhí)行任何任務(wù)key,當(dāng)輸入compile的時(shí)候?qū)?zhí)行 任務(wù)key為compile的任務(wù),如果給定的key類(lèi)型不是任務(wù)而是一個(gè)配置項(xiàng)時(shí)將輸出配置項(xiàng)的值,如果key為任務(wù)類(lèi)型的執(zhí)行結(jié)果將不會(huì)輸出到終端,要看任務(wù)的輸出結(jié)果需要執(zhí)行 show <task name> 而不是<task name> 。習(xí)慣性的定義 sbt 的key的時(shí)候使用和Scala命名風(fēng)格一樣的駝峰命名。
了解一個(gè)key的更多信息,可以在交互模式下使用 inspect <keyname> , 可以看到該key的值的類(lèi)型和摘要描述信息等
你可以再 build.sbt 頂部使用 import 語(yǔ)句, 它們不需要用空行分割。sbt 默認(rèn)情況下隱式的導(dǎo)入了以下包:
import sbt._
import Process._
import Keys._
要添加一個(gè)第三方庫(kù)的依賴有兩種方法,一種是直接將jar包放到 lib目錄下,另一種方法是在build.sbt中添加依賴配置,如以下的方法:
libraryDependencies += "org.apache.derby" % "derby" % "10.4.1.3"
以上這個(gè)配置將在項(xiàng)目中添加一個(gè) Apache Derby的庫(kù),并且版本為 10.4.1.3
libraryDependencies key 包含兩個(gè)方法:+=(不是:=)和%, += 是在原來(lái)值上追加新值而不是替換原值,更多的解釋可參考[配置配置項(xiàng)](). %方法作用是構(gòu)建一個(gè) Ivy 模塊ID在依賴庫(kù)中被解析。