问题
As of sbt 0.13, the recommended way to define all configuration is multi-project .sbt build definition. It is absolutely clear how to define settings for each project there; however, how one should define build-wide settings, for example, in ThisBuild
or Global
scopes?
With Scala build definitions it is clear: we have settings
key coming from Build
trait:
object MyBuild extends Build {
override lazy val settings = super.settings ++ Seq(
someKey := someValue
)
}
Now someKey
's value will be build-scoped by default. Alternatively, it can be defined directly in .sbt
file with ThisBuild
scope:
someKey in ThisBuild := someValue
However, there is no natural place to define these options in multi-project .sbt
builds. I suspect that they should be defined in one of the projects with ThisBuild
scope:
val someProject = project
.settings(someKey in ThisBuild := someValue)
but this is very counterintuitive and not really clear: are such settings really applied globally or do they really belong to the specific project? What if I define the same key in multiple projects?
val project1 = project.settings(someKey in ThisBuild := someValue1)
val project2 = project.settings(someKey in ThisBuild := someValue2)
The documentation does not give any answers on this, unfortunately.
Note that I explicitly do not ask how to share global settings between builds or projects. I ask specifically about defining build-scoped settings.
回答1:
Well, I've performed some experiments and found out the following. Here is an example build.sbt
:
val testKey = settingKey[String]("A key for test")
testKey := "value in build.sbt"
testKey in ThisBuild := "build-scoped value in build.sbt"
testKey in Global := "global value in build.sbt"
lazy val root = (project in file("."))
.settings(
testKey := "value in root project",
testKey in ThisBuild := "build-scoped value in root project",
testKey in Global := "global value in root project"
)
lazy val child = project
.settings(
testKey := "value in child",
testKey in ThisBuild := "build-scoped value in child project",
testKey in Global := "global value in child project"
)
and here's what I see in SBT console:
[info] Set current project to root (in build file:/private/tmp/sbtt/)
> inspect testKey
[info] Setting: java.lang.String = value in build.sbt
[info] Description:
[info] A key for test
[info] Provided by:
[info] {file:/private/tmp/sbtt/}root/*:testKey
[info] Defined at:
[info] /private/tmp/sbtt/build.sbt:4
[info] Delegates:
[info] root/*:testKey
[info] {.}/*:testKey
[info] */*:testKey
[info] Related:
[info] */*:testKey
[info] {.}/*:testKey
[info] child/*:testKey
> testKey
[info] value in build.sbt
> root/testKey
[info] value in build.sbt
> child/testKey
[info] value in child
> {.}/testKey
[info] global value in child
> reload
[info] Loading global plugins from /Users/netvl/.sbt/0.13/plugins
[info] Set current project to root (in build file:/private/tmp/sbtt/)
> testKey
[info] value in build.sbt
> root/testKey
[info] value in build.sbt
> child/testKey
[info] value in child
> {.}/testKey
[info] build-scoped value in child project
> */testKey
[info] global value in child project
So, the conclusion is as follows.
- Values defined at the topmost level in a multi-project SBT build seem to be scoped to the project
build.sbt
belongs to. That is, herebuild.sbt
resides in the root directory, and so definingtestKey
in the file directly is the same as defining it in(project in file(".")).settings(...)
clause. According to SBT output, they also take priority over those defined in.settings(...)
. - Keys in larger scopes like
ThisBuild
orGlobal
seem to be able to be defined in any project, but "later" projects will then take priority. This is probably related to the order the projects are processed. I have expected that the order of evaluation oflazy val
s would affect this, and I've tried adding.aggregate(child)
to the root project to force the child project to be evaluated first, but it didn't seem to have any effect: globally scoped values from child project still have priority.
Therefore, it seems fine to define build-scoped or globally scoped values inside the root project or inside common settings list which is then used in every project. However, assigning different values to a key in build or global scope in different projects will likely lead to a weird behavior - only one of these values will take effect, and which one I don't know.
It would be very nice if all this were explained in the documentation, but at the moment I can't find anything on this behavior there.
I'd gladly accept someone else's answer which would provide more insight on how SBT works in this regard.
来源:https://stackoverflow.com/questions/33417180/how-to-define-build-scoped-settings-in-multi-project-sbt-builds