9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

sbt を始めるためのまとめ -キーのインペクトとスコープ-

Last updated at Posted at 2016-12-17

アカウンティング・サース・ジャパン Advent Calendar の18日目!

はじめに

自分がsbtを使い始める上で、まず公式のGetting Startedを読んでみたのですが、なかなか理解しにくい部分や、今後のためにまとめておきたい部分などがあったので、一部についてまとめ直しや補足をしています。これからsbtを始める方は公式のGetting Startedの補足に見ていただけばと思います。前回はsbtのプロジェクト構成について書きました。今回はsbtのキーのスコープとインスペクトについてまとめていきます。

公式の Getting Started
http://www.scala-sbt.org/0.13/docs/Getting-Started.html

キーのスコープについて理解する

まずは前回のおさらいですが、sbtは各種ビルド定義情報から、ビルドに必要なMapを作成するのでした。そしてビルド定義をbuild.sbtに記述する際は、キー(SettingKey[T])に値を定義して、Setting[T]を作成していくことで、ビルド情報のMapに必要な元ネタを設定していくという流れでしたね。
このキーに対する値は、コンテキストに応じて変わることがあります。いきなりコンテキストと言われても何じゃそれという感じですが、例を見てみると案外わかりやすいです。例えば定義済みのキーとして sourceDirectories: SettingKey[Seq[File]]がありますが、これはコンパイル時とテスト時では別の値をとります。sbtのコンソールで見てみます。


> compile:sourceDirectories
[info] * /xxx/sbt_study/src/main/scala-2.10
[info] * /xxx/sbt_study/src/main/scala
[info] * /xxx/sbt_study/src/main/java
[info] * /xxx/sbt_study/target/scala-2.10/src_managed/main

> test:sourceDirectories
[info] * /xxx/sbt_study/src/test/scala-2.10
[info] * /xxx/sbt_study/src/test/scala
[info] * /xxx/sbt_study/src/test/java
[info] * /xxx/sbt_study/target/scala-2.10/src_managed/test

ここで、指定している compile: とか test: とかがキーのコンテキストを指定している部分になっています。sbtでは、このコンテキストのことをスコープ(Scope)といいます。あるキーに対しては、スコープを特定しなければ一意に値を取得できないということです。そして、このスコープを特定するための情報には3つの種類があり、sbtでは軸(Axis)とよばれます。

説明
Project マルチプロジェクト構成の場合に、プロジェクトごとにキーの値を変えられる
Configuration Compile,Test,Runtimeなどのコンフィギュレーション(Ivyから来ている概念らしい)ごとに、キーの値を変えられる
Task タスクごとにキーの値を変えられる。ex. packageSrcタスクとpackageBinタスク実行時で、artifactNameを変える

sbtのコマンドラインでキーを指定する時には、この3つの軸を以下のような形式で指定することで、スコープを限定することができます。

{<build-uri>}<project-id>/config:intask::key

またビルド定義で、キーのスコープを指定するには例えば以下のように記述します。

lazy val lib = (project in file("lib")).
  settings(
    unmanagedBase in (Compile, compile) := baseDirectory.value / "compilelib"
  )

上記の例では、unmanagedBaseキーのスコープが、Project=lib, Configuration=Compile, Task=compile で限定されていることになります。
(unmanagedBaseは、sbt定義済みのキーで、手動でjarを配置するパスを指します。)

実際に適用されるキーを調べてみる

ある特定のキーについて調べるにはinspectコマンドが便利です。例えば上記のunmanagedBaseについて、inspectを打ってみると

> inspect compile:compile::unmanagedBase
[info] Setting: java.io.File = /xxx/study/scala/sbt_study/compilelib
[info] Description:
[info]  The default directory for manually managed libraries.
[info] Provided by:
[info]  {file:/xxx/study/scala/sbt_study/}root/compile:compile::unmanagedBase
[info] Defined at:
[info]  /xxx/study/scala/sbt_study/build.sbt:4
[info] Dependencies:
[info]  root/*:baseDirectory
[info] Delegates:
[info]  root/compile:compile::unmanagedBase
[info]  root/compile:unmanagedBase
[info]  root/*:compile::unmanagedBase
[info]  root/*:unmanagedBase
[info]  {.}/compile:compile::unmanagedBase
[info]  {.}/compile:unmanagedBase
[info]  {.}/*:compile::unmanagedBase
[info]  {.}/*:unmanagedBase
[info]  */compile:compile::unmanagedBase
[info]  */compile:unmanagedBase
[info]  */*:compile::unmanagedBase
[info]  */*:unmanagedBase
[info] Related:

スコープの指定なしで打ってみると

> inspect unmanagedBase
[info] Setting: java.io.File = /xxx/study/scala/sbt_study/lib
[info] Description:
[info]  The default directory for manually managed libraries.
[info] Provided by:
[info]  {file:/xxx/study/scala/sbt_study/}root/*:unmanagedBase
[info] Defined at:
[info]  (sbt.Classpaths) Defaults.scala:1169
[info] Dependencies:
[info]  root/*:baseDirectory
[info] Delegates:
[info]  root/*:unmanagedBase
[info]  {.}/*:unmanagedBase
[info]  */*:unmanagedBase
[info] Related:

スコープを指定しない場合は、結果が変わっています。この理由はinspectの出力をみるとなんとなく想像できます。sbtは指定されたキーの値を、"Delegates"の順に見ていき、はじめに値が見つかったものを返します。実際に見つかったキーは "Provided by"で確認できます。ここで、* や {.}という記号ができていますが、

  • {.}はProject軸の値でビルド全体を表しています。build.sbtではThisBuildで指定できます。マルチプロジェクトの場合に使えそうですね。
  • *は各軸でのGlobal値を表してします。build.sbtではGlobalで軸を指定して値を定義すると、その軸の任意の値で適用されるデフォルト値になります。

タスクの依存関係を追いかけてみる

inspectコマンドの"Dependencies"をみると、キーの依存関係がわかります。例えば、testタスクを実行すると、テストコードを実行する前に、メインのソースがコンパイルされますが、これはどんな依存関係で行なわれているのでしょうか。実際にinspectを打ちながら、Dependenciesを遡っていくと以下のような感じになっていました。(関係ありそうな部分のみ記載しています。)

test -> root/test:executeTests -> root/test:fullClasspath -> root/test:exportedProducts

root/test:exportedProductsをコマンドラインから実行すると確かにソースがコンパイルされるのが確認できます。

おわりに

今回はキーのスコープについてまとめてみました。プロジェクトごと、コンフィグレーションごと、タスクごとにキーの値を変えることで、柔軟にビルドをカスタマイズできるようになっているんですね。
合わせて、inspectコマンド重要ですね〜。実際にどんなキーがあって、どんなカスタマイズができるかは、公式のドキュメントやその他情報を漁りながら少しずつ覚えていくしかないと思いますが。
そろそろ自前のタスクを作りたくなってきたので、次回はタスクの実装について書く予定です。

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?