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