sbt筆記四 .sbt構建定義

.sbt vs .scala

sbt構建定義包括項目根目錄下的sbt文件和project子目錄下的scala文件。 
能夠只用一種,也能夠兩種都用。一種比較好的方式是:大部分在.sbt中定義,若是.sbt處理不了,才用.scala,例如: 
    定製sbt(添加新的設置和任務) 
    定義嵌套項目(即子模塊) 

這裏只討論.sbt。 web

所謂構建定義 

** PLEASE READ THIS SECTION ** 
在檢查項目和處理構建定義文件以後,sbt最終以一個不可變映射(鍵值對的集合)來描述構建。 
好比,項目名的鍵名爲name,映射到一個字符串的值。 

構建定義文件並不直接(仍是當即?)影響sbt的映射。 
(Build definition files do not affect sbt's map directly.) 

相反,構建定義建立一個巨大的Setting[T]對象列表(T是map中值的類型)。Setting描述了一個到map的轉換,好比添加一個新的鍵值對或追加一個已存在的值。(本着函數式編程的精神,一個轉換返回一個新映射,而不是更新一箇舊的映射) 
在build.sbt中,用以下的方式建立一個Setting[String]來表示項目名稱: 
name := "hello"
這個Setting[String]將映射中的name鍵與"hello"關聯(添加或替換)。將轉換後的映射做爲新的sbt映射。 
爲了建立映射,sbt首先將settings列表排序以便將對同一鍵名所作的修改集中在一塊兒,而且若是值依賴於其餘的鍵,那麼會在依賴鍵以後處理。而後sbt利用排好序的Setting列表,依次應用到映射中。 

總結:構建定義定義了一個Setting[T]列表,Setting[T]是會影響sbt映射鍵值對的轉換,T是值得類型。 apache

build.sbt如何定義settings 

build.sbt定義了一個Seq[Setting[_]];它是一個Scala表達式列表,以空行間隔,每一行是序列的一個元素。若是在.sbt文件的開頭寫入"Seq("並在結尾寫入")"(不包含引號),並把空行換成逗號,就能夠看到等價的.scala代碼。 
例如: 
name := "hello"

version := "1.0"

scalaVersion := "2.9.2"


build.sbt中的表達式都是相互獨立的,並且他們是表達式而不是完整的scala語句。在build.sbt中不能定義頂級的val,object,class和方法。  編程

上例中,:=左邊的是鍵,鍵必須是SettingKey[T],TaskKey[T]或InputKey[T]類型的實例,T表示預期值的類型。 

Keys有一個:=方法,它返回一個Setting[T],能夠用Java語法風格來調用這個方法: 
name.:=("hello")

在Scala中用name := "hello"代替(Java風格好醜...) 

name這個鍵的:=方法返回一個Setting[String],而name鍵自身的類型爲SettingKey[String]。在本例中,返回值Setting[String]是一個轉換,它把sbt映射中name鍵的值設爲"hello"(添加或替換)。 

若是值的類型錯誤,構建定義將沒法編譯: 
scala name := 42  // will not compile ### Settings are separated by blank lines

也不能這麼寫: 
// 沒有空行,沒法工做
name := "hello"
version := "1.0"
scalaVersion := "2.9.2"

sbt須要某種定界符來代表表達式在哪結束,下一個在哪開始。 函數式編程

.sbt文件包含一個Scala表達式列表,它不是完整的Scala程序,這些表達式必須先切分,而後逐個傳給編譯器。 函數

若是想要一個完整的Scala程序,用.scala文件;.sbt文件是可選的。 ui

鍵在Keys對象中定義

內置的鍵都是Keys對象的字段。build.sbt隱式引入了sbt.Keys._。因此sbt.Keys.name能夠寫成name。 

自定義鍵能夠在.scala文件或插件中定義。 spa

改變settings的另外一個方式

:=是最簡單的轉換。還有其餘方式。例如能夠用+=向一個列表值添加內容。 插件

其餘的轉換須要scopes的知識,因此後面再介紹。 命令行

任務鍵

有三種風味的鍵:(紅燒,清蒸,還有油炸的) scala

SettingKey[T]:有一個值,並且只計算一次(只在項目加載的時候計算一次,並一直存在)。 
TaskKey[T]:有一個值,而且每次都要從新計算,可能產生反作用。 

InputKey[T]:是一個有命令行參數做爲輸入的任務鍵。入門指南中未涵蓋InputKey。

TaskKey[T]定義一個任務,像compile或package這樣的操做就是任務。任務能夠返回Unit(就是Scala中的void),或返回一個和任務相關聯的值,如package是一個TaskKey[File],它的值就是他建立的jar文件。

每次開始執行一個任務(好比在交互式sbt提示符後輸入compile),sbt都會從新運行一次涉及到的任務。

雖然sbt的映射描述一個項目時,能夠爲諸如name的setting保持一個固定的字符串,可是它必須爲諸如compile這樣的任務保持可執行的代碼——即便可執行代碼最終返回一個字符串,它每次都會從新運行。

一個給定的鍵必須引用一個任務或普通的setting。也就是說,"taskiness"(是否每次從新運行)是這個鍵的屬性,而不是值。

用:=能夠建立一個任務,任務的代碼每次調用時都會執行:

hello := {println("Hello!")}

從類型系統的觀點來看,task key建立的Setting與setting key建立的Setting稍有不一樣,taskKey := 42返回一個Setting[Task[T]],而settingKey := 42返回一個Setting[T]。在大多數狀況下這沒多大差異,當任務執行的時候task key依然建立一個類型爲T的值。(也就是說,當T是String,那麼不管是調用task key,仍是setting key,返回的值都是String類型的)

T和Task[T]隱含的區別是:一個setting key不能依賴一個task key,由於setting key的值只在項目加載的時候評估一次,並且不能重複執行。

sbt交互模式下的Keys

在sbt交互模式下,能夠輸入任務的名稱來執行這個任務。所以輸入compile就會運行compile任務,compile是一個task key。

若是輸入一個setting key的名稱,就會顯示setting key的值。輸入task key的名稱會執行任務但不會顯示結果值;要看任務的結果,能夠用show <task name>。

在構建定義文件中,keys以駝峯式命名(沿襲Scala慣例),但在sbt命令行中用 連字符-分隔-單詞 代替。這些在sbt中使用的 連字符-分隔 字符串是在Keys中定義的。例如,在Keys.scala,定義了一個鍵:

val scalacOptions = TaskKey[Seq[String]]("scalac-options", "Options for the Scala compiler.")

在sbt中要輸入scalac-options,但在構建定義中得用scalacOptions。

要了解更多的鍵,在sbt命令提示符後輸入inspect <keyname>。inspect顯示的有些信息沒什麼意義,可是在頂端展現了setting的值類型,以及它的簡短描述。

在build.sbt中引入

你能夠把引入語句放在build.sbt的頭部;而且不須要用空行分隔。
下面這些是隱式默認導入的:
import sbt._
import Process._
import Keys._

(此外,若有你有.scala文件,它們的內容(Build或Plugin對象)將會被導入。)

添加類庫依賴

有兩種方式來添加第三方類庫依賴。第一種是把jar包放到lib/(非託管依賴),第二種是添加託管依賴,放在build.sbt裏,像這樣:

libraryDependencies += "org.apache.derby" % "derby" % "10.4.1.3"
libraryDependencies涉及兩個複雜狀況:+=操做符,以及%方法。+=向原來的值中追加,而非替換它。%方法用來從字符串構造ivy模塊ID。
相關文章
相關標籤/搜索