sbt でわからないことがある場合、だいたい
wiki をみるsbtのドキュメントはgithubのwikiからscala-sbt.orgに移りました!- ソースを読む
- メーリングリストで質問する
- StackOverflowで検索 or 質問
というような選択肢になります。*1
それで、英語が微妙な自分の場合、結局ソースをみることが多いわけです。それで、今までそれなりにsbtのソースを読んでいるので、自分なりに思った
- sbtのソースのどこから読めばいいのか?
- 全体としてどういう構成になっているのか?
をちょっと書いてみようかと思います。
(そろそろsbt0.12が出るはずですが)このblog書いている時点の安定版であるsbt0.11.2を基準にして書きます。まぁこれから書くようなことは、sbt0.12になってもあまり変わらないはずです。
1. まず Keys.scala 読め
https://github.com/sbt/sbt/blob/v0.11.2/main/Keys.scala
とにかくひたすら読みましょう。自分でもこのページ何度読んだか数えきれないくらいです。
sbt *2では、ほぼすべての設定を、 SettingKey や TaskKey 、 InputKey などの型で定義するわけですが、*3 Keys.scala にそれらの定義がまとめて書いてあります。例えばよく使う以下のようなものも全部ここにあります
- libraryDependencies SettingKey[Seq[ModuleID] ] 依存ライブラリの指定
- scalaVersion SettingKey[String] 使用するscalaのversionの指定
- scalacOptions TaskKey[Seq[String] ] コンパイルオプションの指定
- name SettingKey[String] プロジェクトの名前
上記に上げたような一般的によくユーザー側で設定するようなものだけではなく、以下のようなコマンド*4 もすべてここに定義されています
- compile TaskKey[Analysis] ソースコードのコンパイル
- run InputKey[Unit] メインクラスを実行
- console TaskKey[Unit] (依存ライブラリや、ソースコードをコンパイルしてパスを通した状態で) ScalaのREPLを立ち上げ
- clean TaskKey[Unit] 生成したclassファイルなどを一度全部削除
- package TaskKey[File] Jar などを生成
- publish TaskKey[Unit] jarを生成してリポジトリに公開
そして、SettingKeysもTaskKeyもすべて、applyのメソッドの第二引数にその説明を記述できるようになっています。そしてほとんどのKeyについて説明がかいてあるのでとにかくまずこれを読みましょう。(wikiに説明が書いてないものでも、こっちにならば書いてある場合もありえるので)
勿論単に説明を読んだりするだけなら sbt のコンソール上から以下のようにhelp使えば
> help scala-version
The version of Scala used for building.
表示されます。が(自分で他のKeyに依存する独自のSettingを書いたり、pluginを書いたりする場合は特に) それぞれのKeyが実際にどういう型で、どのようにScalaのソースコード上で定義されているのかをある程度意識して理解しておいたほうがよいので、とにかくこのKeys.scalaを読むことをおすすめします。
2. Defaults.scala
https://github.com/sbt/sbt/blob/v0.11.2/main/Defaults.scala
Keys.scalaはKeyが定義されているだけですが、実際にそのKeyの設定のデフォルトが定義されているのがこのファイルです。たとえば、デフォルトではScalaのメインのソースは src/main/scala に置きますが、これも Defaults.scala で定義されていて以下のような仕組みで決まっています。
- sourceDirectory は baseDirectory の下の "src" というフォルダ
- compileの設定の場合(つまりtest用などではない、メインとなるソース) のディレクトリは sourceDirectory の下の "main" というフォルダ
- scalaのソースはsourceDirectoryの下の "scala" というフォルダ
こんな感じで、複数のKeyが依存して最終的に src/main/scala という値が決まってます。もちろん、この依存関係を全部完全に把握している必要はないですが、sbt plugin を読んだり書いたりする場合も、このような感じで、どうやって相互のKeyの依存の仕組みを定義するのか、されているのか、を理解する必要があるので。以下、例をいくつか上げておきます
- デフォルトのプロジェクトのversionは "0.1-SNAPSHOT"
- コンパイルされたclassファイルやその他色々生成されたものが置かれる target ディレクトリの位置
- 自動生成されたソースが置かれる位置 crossTargetとは、複数のscalaのversionをbuildするときのものななので、scala2.8.2用に自動生成されたものは target/scala-2.8.2/src_managed 、scala2.9.2用に自動生成されたものは target/scala-2.9.2/src_managed となったりする
- ~ を使ってファイル変更を検知する際にpollする間隔は 0.5 秒
- このprojectがsbtPluginかを表すsbtPluginというKeyはデフォルトではfalse
- publishする際にmavenの形式かどうかを設定する publishMavenStyle というKeyはデフォルトでは true
- sbtのコンソールで入力したコマンドの履歴を保存しておくファイルの位置と名前のデフォルト値
3. sbt 自体のプロジェクトのフォルダ構成が、デフォルト値と異なっている!
理由は知りませんが、なぜか変えてあります。デフォルトではメインのソースをそれぞれのディレクトリの下の src/main/scala に置くわけですが、sbt の場合はそれぞれのプロジェクトの直下がメインのソースのディレクトリを置く場所になっています!これ知らないで読むとわけわからないと思うので注意しましょう。sbt0.13から通常のsrc/main/scalaに置く構成に変わったようです(0.12はそのまま)
また、sbtの場合、 "src/test/scala" に置くような普通のtestもある程度ありますが、それ以外の scriptedPlugin を使ったテストのほうが圧倒的に大量にあります ( "src/sbt-test/" 以下に置く)
scriptedPluginについてはこれを読みましょう
(当たり前ですが)これもscriptedPluginのフォルダ構成や大まかな仕組みわかってないと、なんでこんなネストしたフォルダ構成になっているのか意味が分からないと思うので、もしsbtのテストコードを理解しようと思った場合には、まずscriptedPluginを最低限理解しないといけまん
まとめ?
他にも重要なファイルありますが、(たとえば、コアとなる色々なclassやメソッドが定義されているStructure.scala) Structure.scala はちょっと難易度高いので、まずは上記に書いた Keys.scala と Defaults.scala を読むといいのではないかと思います。