Revision 3 as of 2011-10-29 06:27:05

Clear message
Locked History Actions

sbt/Getting-Started-Full-Def

.scalaビルド定義

https://github.com/harrah/xsbt/wiki/Getting-Started-Full-Defの訳(2011/10/28時点)

This page assumes you've read previous pages in the Getting Started Guide, especially .sbt build definition and more about settings.

sbtは再帰的である

build.sbtはとても単純だ。sbtが実際にどのように動作するかは隠されている。 sbtのビルドはScalaコードで定義される。 このコードは、それ自体がビルドされる必要があるのだが、それを行うのにsbt以外の適任者があるだろうか?

君自身のプロジェクトの中にはprojectというディレクトリがあるはずだが、これがもう一つのプロジェクトであり、それが君のプロジェクトのビルドの仕方を決めている。プロジェクト中のプロジェクトは(理屈の上では)、他のプロジェクトが可能な、いかなることも可能だ。 君のビルド定義はsbtプロジェクトなのだ。

そして、これを更に掘り下げることもできる。望むなら、project/projectディレクトリを作って、ビルド定義プロジェクトのビルド定義を記述することもできる。以下に示そう。

 hello/                  # 君のプロジェクトのベースディレクトリ

     Hello.scala         # 君のプロジェクトのソースファイル (src/main/scalaに
                         #   あってもよい)

     build.sbt           # build.sbtはproject/下にあるビルド定義プロジェクトのソースコードの一つ
                         # 

     project/            # ビルド定義プロジェクトのベースディレクトリ

         Build.scala     # project/プロジェクトのソースファイルの一つ
                         #   つまり、ビルド定義のソースファイルの一つ

         build.sbt       # これはproject/projectというプロジェクトのビルド定義の一部
                         #   つまり、ビルド定義のビルド定義
                         #


         project/        # ビルド定義のビルド定義のベースディレクトリ
                         #

             Build.scala # project/project/プロジェクトのソースファイル

心配すんな!たいていは、こんなものは必要ないよ。 理屈を知ることは助けになるだろうという程度だ。

ところで、.scalaや.sbtで終わるいかなる名前のファイルでもいい。 build.sbtやBuild.scalaという名前は便宜的なものだ。 これはつまり、複数のファイルが存在しうるということだ。

ビルド定義プロジェクト中の.scalaソースファイル

.sbt files are merged into their sibling project directory. Looking back at the project layout:

 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

The Scala expressions in build.sbt are compiled alongside and merged with Build.scala (or any other .scala files in the project/ directory).

.sbt files in the base directory for a project become part of the project build definition project also located in that base directory.

The .sbt file format is a convenient shorthand for adding settings to the build definition project. Relating build.sbt to Build.scala

To mix .sbt and .scala files in your build definition, you need to understand how they relate.

The following two files illustrate. First, if your project is in hello, create hello/project/Build.scala as follows:

import sbt._
import Keys._

object HelloBuild extends Build {

    val sampleKeyA = SettingKey[String]("sample-a", "demo key A")
    val sampleKeyB = SettingKey[String]("sample-b", "demo key B")
    val sampleKeyC = SettingKey[String]("sample-c", "demo key C")
    val sampleKeyD = SettingKey[String]("sample-d", "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"))
}

Now, create hello/build.sbt as follows:

sampleKeyC in ThisBuild := "C: in build.sbt scoped to ThisBuild"

sampleKeyD := "D: in build.sbt"

Start up the sbt interactive prompt. Type inspect sample-a and you should see (among other things):

[info] Setting: java.lang.String = A: in Build.settings in Build.scala [info] Provided by: [info] {file:/home/hp/checkout/hello/}/*:sample-a

and then inspect sample-c and you should see:

[info] Setting: java.lang.String = C: in build.sbt scoped to ThisBuild [info] Provided by: [info] {file:/home/hp/checkout/hello/}/*:sample-c

Note that the "Provided by" shows the same scope for the two values. That is, sampleKeyC in ThisBuild in a .sbt file is equivalent to placing a setting in the Build.settings list in a .scala file. sbt takes build-scoped settings from both places to create the build definition.

Now, inspect sample-b:

[info] Setting: java.lang.String = B: in the root project settings in Build.scala [info] Provided by: [info] {file:/home/hp/checkout/hello/}hello/*:sample-b

Note that sample-b is scoped to the project ({file:/home/hp/checkout/hello/}hello) rather than the entire build ({file:/home/hp/checkout/hello/}).

As you've probably guessed, inspect sample-d matches sample-b:

[info] Setting: java.lang.String = D: in build.sbt [info] Provided by: [info] {file:/home/hp/checkout/hello/}hello/*:sample-d

sbt appends the settings from .sbt files to the settings from Build.settings and Project.settings which means .sbt settings take precedence. Try changing Build.scala so it sets key sample-c or sample-d, which are also set in build.sbt. The setting in build.sbt should "win" over the one in Build.scala.

One other thing you may have noticed: sampleKeyC and sampleKeyD were available inside build.sbt. That's because sbt imports the contents of your Build object into your .sbt files. In this case import HelloBuild._ was implicitly done for the build.sbt file.

In summary:

  • In .scala files, you can add settings to Build.settings for sbt to find, and they are automatically build-scoped. In .scala files, you can add settings to Project.settings for sbt to find, and they are automatically project-scoped. Any Build object you write in a .scala file will have its contents imported and available to .sbt files. The settings in .sbt files are appended to the settings in .scala files. The settings in .sbt files are project-scoped unless you explicitly specify another scope.

When to use .scala files

In .scala files, you are not limited to a series of settings expressions. You can write any Scala code including val, object, and method definitions.

One recommended approach is to define settings in .sbt files, using .scala files when you need to factor out a val or object or method definition.

Because the .sbt format allows only single expressions, it doesn't give you a way to share code among expressions. When you need to share code, you need a .scala file so you can set common variables or define methods.

There's one build definition, which is a nested project inside your main project. .sbt and .scala files are compiled together to create that single definition.

.scala files are also required to define multiple projects in a single build. More on that is coming up in Multi-Project Builds.

(A disadvantage of using .sbt files in a multi-project build is that they'll be spread around in different directories; for that reason, some people prefer to put settings in their .scala files if they have sub-projects. This will be clearer after you see how multi-project builds work.) The build definition project in interactive mode

You can switch the sbt interactive prompt to have the build definition project in project/ as the current project. To do so, type 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) >

As shown above, you use reload return to leave the build definition project and return to your regular project. Reminder: it's all immutable

It would be wrong to think that the settings in build.sbt are added to the settings fields in Build and Project objects. Instead, the settings list from Build and Project, and the settings from build.sbt, are concatenated into another immutable list which is then used by sbt. The Build and Project objects are "immutable configuration" forming only part of the complete build definition.

In fact, there are other sources of settings as well. They are appended in this order:

  • Settings from Build.settings and Project.settings in your .scala files. Your user-global settings; for example in ~/.sbt/build.sbt you can define settings affecting all your projects. Settings injected by plugins, see using plugins coming up next. Settings from .sbt files in the project. Build definition projects (i.e. projects inside project) have settings from global plugins (~/.sbt/plugins) added. Using plugins explains this more.

Later settings override earlier ones. The entire list of settings forms the build definition. Next

Move on to using plugins.