Revision 5 as of 2011-10-29 09:30:59

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ファイルはその兄弟プロジェクトディレクトリにマージされる。 先のプロジェクトレイアウトに戻ろう。

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

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

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

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

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

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.

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

build.sbtのBuild.scalへの関連付け

ビルド定義中で、.sbtと.scalaファイルをミックスするには、まずそれらがどのように関連付けられるかを知っておく必要がある。 二つのファイルで示そう。 第一に、君のプロジェクトがhelloにあり、hello/project/Build.scalaというファイルを次のように作成したとする。

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"))
}

そして、hello.build.sbtを次のように記述する。

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

sampleKeyD := "D: in build.sbt"

sbt対話モードを開始しよう。「inspect sample-a」とタイプすると、以下が表示されるだろう。

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

今度は「inspect sample-c」の結果だ。

[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.

次に「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.

いつ.scalaファイルを使うか

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.)

対話モードでのビルド定義

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

次はプラグインの使用