.scala构建定义(sbt 0.13.0 Snapshot)
当前页面假定你已经阅读了Getting Started Guide的前面章节,尤其是.sbt build definition和more about settings。
sbt是递归的
build.sbt非常简单,它隐藏了sbt实际是如何工作的。sbt构建是用Scala代码定义的。这些代码自身需要建立。还有比sbt更好的方式吗?
project文件夹是你项目中的另一个子项目,它知道如何构建你的项目。子项目(理论上)可以可以做任何其他项目能做的事情。你的构建定义就是一个sbt项目。
如果你喜欢,你可以通过创建一个project/project/文件夹,来调整构建定义项目的构建定义。
这有一个例证。
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
别担心!多数时候你并不需要全部。但理解原理是很有帮助的。
顺便说一下:任何时候,以.scala或.sbt结尾的文件都会被用上,把他们命名为build.sbt和Build.scala仅仅是惯例而已。这也意味着多个文件也是允许的。
构建定义项目中的.scala源文件
.sbt文件会合并入它们的兄弟项目文件夹。回顾一下项目布局:
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`` files in the base directory for a project become part of the ``project`` build definition project also located in that base directory.(绕晕了)
项目根目录下的`.sbt`文件如果成为构建定义项目的一部分,也要放在相应的根目录下(是这个意思吗?)。
.sbt文件格式是将设置添加到构建定义项目的方便的速记法。
关联build.sbt到Build.scala
为了混合你的构建定义中的.sbt和.scala文件,你需要了解如何关联他们。
以下面两个文件举例。首先,如果你的项目在hello文件夹中,如下方式创建hello/project/Build.scala:
(译注:0.12.x略有不同,见http://www.scala-sbt.org/0.12.3/docs/Getting-Started/Full-Def.html#relating-build-sbt-to-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 = Project.defaultSettings ++ Seq(sampleKeyB := "B: in the root project settings in Build.scala")) }
现在,如下方式创建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”显示了这两个值的相同范围。也就是,.sbt文件中的sampleKeyC in ThisBuild等价于将setting放在.scala文件的Build.settings列表中。sbt从这两个地方获取构建范围的设置来创建构建 定义。
现在,输入inspect 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)而不是整个构建({file:/home/hp/checkout/hello/})。
正如你可能已经猜到的,inspect sampleKeyB和sampleKeyD匹配。
[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中的设置,这意味着.sbt中的设置有优先权。 尝试修改Build.scala中的sampleC或sampleD,它们依然是build.sbt中的值。build.sbt中的设置将胜过 Build.scala中的。
另一个你需要注意的:sampleKeyC和sampleKeyD在build.sbt内部有效。这是因为sbt将你的Build对象的内容导入到.sbt文件。在这个例子中build.sbt文件的import HelloBuild._是隐式完成的。
概括起来就是:
- 在.scala文件中,你可以将设置添加到Build.settings,sbt可以找到它,而且它们自动是构建范围的。
- 在.scala文件中,你可以将设置添加到Project.settings,sbt可以找到它,而且它们自动是项目范围的。
- .scala文件中任何你写的Build对象,它们的内容将导入到.sbt文件并对它有效。
- .sbt文件中的设置会被追加到.scala文件的设置。
- .sbt文件中的任何设置都是项目范围的,除非你明确指定了另一个范围。
什么时候该使用.scala文件
在.scala文件中,你可以写任何Scala代码,包括值,对象和方法定义。
一种推荐的方式是,在.sbt文件中定义设置,只在实际需要一个值,对象或方法定义的时候使用.scala文件。
有一个构建定义,它是你主项目的嵌套项目。.sbt和.scala文件将一起被编译来创建单一的定义。
在单一构建中定义多个项目时.scala文件也是必需的。更多内容在Multi-Project Builds中讨论。
(在多项目构建中使用.sbt文件的一个缺点是,它们会在散布不同的文件夹中。因此,如果有子项目,很多人更喜欢把设置放在他们的.scala文件中。在你看完多项目构建是如何工作的之后将更加清晰。)
交互模式中的构建定义项目
你可以切换sbt交互命令行,使包含构建定义项目的project/作为当前项目。只需要这么做,输入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离开构建定义项目并返回你的常规项目。
提示:所有都是不可变的
如果你认为build.sbt中的设置是被添加到Build和Project对象的settings域,那就错了。相反,Build和 Project,以及build.sbt中的设置,会被串联入另一个不可变的列表,然后作用于sbt。Build和Project对象只是构成完整构建定 义的一部分。
事实上,还有其他来源的设置。它们按这个顺序来追加:
- .scala文件中来自Build.settings和Project.settings的设置。
- 你的用户全局设置;例如,在~/.sbt/build.sbt中你可以定义设置来影响所有的项目。
- 通过插件注入的设置,见后续使用插件章节。
- 来自项目.sbt文件的设置。
- 构建定义项目(也就是项目中的项目)拥有全局插件(~/.sbt/plugins)中添加的设置。使用插件章节有更详细的说明。
后面的设置会覆盖前面的。设置的完整列表构成了构建定义。
下一节
移到使用插件。