关于keys的完整故事
以前咱们假设,一个key(就像name)至关于sbt的键值对映射的一个条目。实际上是简化的。
事实上,每个key在多个上下文中分别有一个关联的值,称做“scope”(做用域)。
这是具体的例子:
- 若是构建定义中包含多个项目,key在每一个项目中能够有不一样的值。
- 针对main源码和测试源码,若是想用不一样的方式编译他们,compile键能够有不一样的值。
- 打包class文件(package-bin)或打包源码(package-src),package-options键(包含建立jar包的选项)能够有不一样的值。
对于给定的键名不会有惟一的值,由于值会根据做用域而改变。
然而,对于给定的scoped键,值是惟一的。
若是考虑sbt处理setting列表来生成键值映射来描述这个项目,如先前所述,这些在键值映射中的键就是scoped键。在构建定义(如在build.sbt中)中定义的setting也适用于scoped键。
一般做用域是隐含的或有一个默认值,但若是默认值有误,你须要在build.sbt中说明但愿的做用域。
Scope axes
scope axis是一种类型,这种类型的每个实例均可以定义自身的做用域(就是说,对于keys,每一个实例都拥有本身的惟一值)
有三个scope axes:
- Projects
- Configurations
- Tasks
project axis范围界定
若是把多个项目放到一个build中,每一个项目要有本身的settings。也就是说,keys能够根据项目划分做用域。
project axis也能够设为"entire build",这样setting应用于entire build而非单一项目。当一个项目没有定义特定项目setting,构建级别settings一般用做后备。
configuration axis范围界定
一个configuration定义了一个构建的味道,可能用它自身的classpath,sources,生成的包,或其余。configuration概念来自于ivy,sbt用来管理依赖(从MavenScopes)。
sbt中能够看到的一些configuration:
- Compile 定义了main构建(src/main/scala)
- Test 定义了如何构建测试(src/test/scala)
- Runtime 定义了run任务的classpath
默认状况下,全部与编译,打包,和运行相关联的key,都是局限于configuration的,所以在每一个configuration中能够作不一样的工做。最明显的例子是任务键compile,package和run;但全部对这些key产生影响的其余key(好比source-directories,scalac-options或full-classpath)也局限于configuration。
task axis范围界定
setting能够影响一个任务的执行。例如package-src任务受package-options设置的影响。
为了支持这个,一个任务key(好比package-src)能够做为另外一个key(好比package-options)的做用域。
各类各样的打包任务(package-src, package-bin, package-doc)能够共享与打包相关的key,好比artifact-name和package-options。这些key对于每一个打包任务能够有不一样的值。
全局范围
每一个scope axis能够被axis类型的实例填充(例如task axis能够被任务填充),或被特殊值Global填充。
Global意味着你所指望的:setting的值应用于全部axis的实例。例如若是task axis是Global,那么这个setting将应用于全部任务。
委托
若是在它的做用域内没有与之关联的值,那么一个限定了做用域的key多是未定义的。
对于每一个做用域,sbt有一个由其余做用域构成的回调搜索路径。典型的,若是一个key在更具体的做用域内没有关联的值,sbt将尝试从更通常的做用域内得到值,好比Global做用域,或完整构建做用域。
这个特性容许你为更通常的做用域设置一个值,容许许多更具体的做用域继承这个值。
你能够用inspect命令来查看一个key的回调搜索路径(fallback search path)或“delegates”,以下所述。
Referring to scoped keys when running sbt
在命令行和交互模式下,sbt这样展现(并解析)范围限定key:
{<build-uri>}<project-id>/config:intask::key
- {<build-uri>}<project-id> 标识project axis。若是project axis有“完整构建(entire build)”做用域,<project-id>部分将丢失。
- config 标识configuration axis。
- intask 标识task axis。
- key 标识key存在做用域(identifies the key being scoped)。
* 能够为每个axis显示,参考Global做用域。
若是省略部分范围限定key,它将按以下方式推断:
- 若是省略项目,将使用当前项目
- 若是省略configuration或task,一个依赖键configuration会被自动发现。
Examples of scoped key notation
- full-classpath: just a key, so the default scopes are used: current project, a key-dependent configuration, and global task scope.
- test:full-classpath: specifies the configuration, so this is full-classpath in the test configuration, with defaults for the other two scope axes.
- *:full-classpath: specifies Global for the configuration, rather than the default configuration.
- doc::full-classpath: specifies the full-classpath key scoped to the doc task, with the defaults for the project and configuration axes.
- {file:/home/hp/checkout/hello/}default-aea33a/test:full-classpath specifies a project, {file:/home/hp/checkout/hello/}default-aea33a, where the project is identified with the build {file:/home/hp/checkout/hello/} and then a project id inside that build default-aea33a. Also specifies configuration test, but leaves the default task axis.
- {file:/home/hp/checkout/hello/}/test:full-classpath sets the project axis to "entire build" where the build is {file:/home/hp/checkout/hello/}
- {.}/test:full-classpath sets the project axis to "entire build" where the build is {.}. {.} can be written ThisBuild in Scala code.
- {file:/home/hp/checkout/hello/}/compile:doc::full-classpath sets all three scope axes.
Inspecting scopes
In sbt's interactive mode, you can use the inspect command to understand keys and their scopes. Try inspect test:full-classpath:
$ sbt
> inspect test:full-classpath
[info] Task: scala.collection.Seq[sbt.Attributed[java.io.File]]
[info] Description:
[info] The exported classpath, consisting of build products and unmanaged and managed, internal and external dependencies.
[info] Provided by:
[info] {file:/home/hp/checkout/hello/}default-aea33a/test:full-classpath
[info] Dependencies:
[info] test:exported-products
[info] test:dependency-classpath
[info] Reverse dependencies:
[info] test:run-main
[info] test:run
[info] test:test-loader
[info] test:console
[info] Delegates:
[info] test:full-classpath
[info] runtime:full-classpath
[info] compile:full-classpath
[info] *:full-classpath
[info] {.}/test:full-classpath
[info] {.}/runtime:full-classpath
[info] {.}/compile:full-classpath
[info] {.}/*:full-classpath
[info] */test:full-classpath
[info] */runtime:full-classpath
[info] */compile:full-classpath
[info] */*:full-classpath
[info] Related:
[info] compile:full-classpath
[info] compile:full-classpath(for doc)
[info] test:full-classpath(for doc)
[info] runtime:full-classpath
On the first line, you can see this is a task (as opposed to a setting, as explained in .sbt build definition). The value resulting from the task will have type scala.collection.Seq[sbt.Attributed[java.io.File]].
"Provided by" points you to the scoped key that defines the value, in this case {file:/home/hp/checkout/hello/}default-aea33a/test:full-classpath (which is the full-classpath key scoped to the test configuration and the {file:/home/hp/checkout/hello/}default-aea33a project).
"Dependencies" may not make sense yet; stay tuned for the next page.
You can also see the delegates; if the value were not defined, sbt would search through:
- two other configurations (runtime:full-classpath, compile:full-classpath). In these scoped keys, the project is unspecified meaning "current project" and the task is unspecified meaning Global
- configuration set to Global (*:full-classpath), since project is still unspecified it's "current project" and task is still unspecified so Global
- project set to {.} or ThisBuild (meaning the entire build, no specific project)
- project axis set to Global (*/test:full-classpath) (remember, an unspecified project means current, so searching Global here is new; i.e. * and "no project shown" are different for the project axis; i.e. */test:full-classpath is not the same as test:full-classpath)
- both project and configuration set to Global (*/*:full-classpath) (remember that unspecified task means Global already, so */*:full-classpath uses Global for all three axes)
Try inspect full-classpath (as opposed to the above example, inspect test:full-classpath) to get a sense of the difference. Because the configuration is omitted, it is autodetected as compile. inspect compile:full-classpath should therefore look the same as inspect full-classpath.
Try inspect *:full-classpath for another contrast. full-classpath is not defined in the Global configuration by default.
Again, for more details, see Interacting with the Configuration System.
Referring to scopes in a build definition
若是你在build.sbt中用一个空键(a bare key)建立一个setting,他将适用于当前项目,Global配置(configuration Global)和Global任务(task Global):
build.sbt经常为单一项目定义setting,因此“当前项目”就是特定build.sbt中定义的那个项目。(对于多项目构建,每一个项目有本身的build.sbt。)
key有一个重载的方法in用于设置做用域。in的参数能够是任何一个scope axes的实例。例如,虽然你没有真正理由这么作,你能够设置Compile配置范围限定的name:
name in Compile := "hello"
或者你能够设置package-bin任务范围限定的name(没有意义,只是一个例子)
name in packageBin := "hello"
或者你可使用多个scope axes设置name,例如在packageBin任务和Compile配置中。
name in (Compile, packageBin) := "hello"
或者你能够用Global(对全部axes):
name in Global := "hello"
(name in Global implicitly converts the scope axis Global to a scope with all axes set to Global; the task and configuration are already Global by default, so here the effect is to make the project Global, that is, define */*:name rather than
{file:/home/hp/checkout/hello/}default-aea33a/*:name)
若是你不用Scala,一个提醒:理解in和:=仅仅是个方法是很重要的,这不是魔法。Scala容许你用更好的方式来写它们,可是你也能够用Java风格:
name.in(Compile).:=("hello")
没有理由用这种丑陋的语法,但它说明了它们实际上就是方法。
何时须要指定做用域
若是正在讨论的key一般被范围限定,那么你须要指定一个范围。例如,compile任务默认状况下限定于Compile和Test配置,而且不存在于这些做用域以外。
要改变compile键关联的值,你须要写compile in Compile或compile in Test。用普通的compile将定义一个新的compile任务,并范围限定于当前项目,而不是覆盖标准compile任务(范围限定于一个configuration的)。
若是你获得一个像“
Reference to undefined setting”这样的错误,一般是你指定做用域失败,或指定一个错误的做用域。你正在使用的key可能定义在其余做用域,sbt将尝试给出建议,做为错误消息的一部分(sbt will try to suggest what you meant as part of the error message);寻找“Did you mean compile:compile?”
一种记住它的方式是,name仅仅是一个键的一部分。实际上,全部的key既包含name,也有做用域(做用域有3个axes)。换句话说,完整的表达式packageOptions in (Compile, packageBin)是一个键名。简单的packageOptions也是一个键名,但却不是同一个(对于没有in的key,做用域隐式假定为:当前项目,全局配置,全局任务)。 html
2013-1-28
这篇怎么全是字啊,没几句代码,没咋看懂都,凑合这样吧。等啥时候我把这块理解了,再回头好好看看这些翻译。中间一大段懒得翻译,由于不知道它在说啥... java