Locked History Actions

sbt/dt_Classpaths

クラスパス、ソース、リソース

https://github.com/harrah/xsbt/wiki/Classpathsの訳(2011/10/30時点)

ここでは、sbtがどのようにしてcompile,run,test等のアクションに必要なクラスパスを構築するかを説明し、 また、これらをオーバライドあるいは拡張の方法について説明する。

基本事項

sbt0.10以降では、classpathはScalaライブラリを含み、(依存で宣言されているならば)Scalaコンパイラをも含む。 Classpath関連のSettingは通常Classpathタイプの値を提供するが、これはSeq[Attributed[File]]の別名になっている。Attributedというのは、それぞれのクラスパスエントリのヘテロジニアスなマップを構成するものである(訳注:?)。 Currently, this allows sbt to associate the Analysis resulting from compilation with the corresponding classpath entry and for managed entries, the ModuleID and Artifact that defined the dependency.

明示的に生のSeq[File]を取得するには、Classpathに暗黙的に追加されたfilesメソッドを使用する。

val cp: Classpath = ...
val raw: Seq[File] = cp.files

Seq[File]からClasspathを作成するにはclasspathメソッドを使い、 FileからAttributed[File]を作成するには、Attributed.blankを使えばいい。

val raw: Seq[File] = ...
val cp: Classpath = raw.classpath

val rawFile: File = ..
val af: Attributed[File] = Attributed.blank(rawFile)

非管理下(Unmanaged)と管理下(managed)

クラスパス、ソース、リソースは、unmanagedとmanagedという二つのメインカテゴリに分割できる。 unmanagedファイルはマニュアルで作成されたファイルであり、ビルドのコントロール外にあり、それらはビルドの入力になる。 managedファイルはビルドのコントロール下にある。これには、生成されたソースやリソース、解決され取得された依存、コンパイル済classがある。

managedファイルを生成するタスクは以下のように追加することができる。

sourceGenerators in Compile <+= sourceManaged in Compile map { out =>
        generate(out / "some_directory")
}

この例においてgenerateとは「File => Seq[File]」型の何らかの関数であり、その仕事を実際に行うものだ。 <+=メソッドは+=のようなものだが、右辺に何らかの入力を許す(ちょうど:=と<<=の違いと同じ)。 このようにして、メインのソースジェネレータ(sourceGenerators in Compile)のリストに新たなタスクを追加することができる。

プラグインの場合には、名前付きのタスクを追加したほうがよいだろう。

sourceGenerators in Compile <+= (mySourceGenerator in Compile).task

mySourceGenerator in Compile <<= sourceManaged in Compile map { out =>
    generate(out / "some_directory")
}

mySourceGeneratorは以下のように定義されている。

val mySourceGenerator = TaskKey[Seq[File]](...)

taskメソッドを使えば、タスクの結果ではなく、タスクそのものを参照することができる。

リソースについて同様のresourceGenerators、resourceManagedというキーがある。

ソースファイルを名前で除外する

プロジェクトのベースディレクトリは、src/main/scalaと同様に、ソースディレクトリでもある。 そこから名前を指定してファイルを除外することができる(以下の例では、butler.scala)

excludeFilter in unmanagedSources := "butler.scala" 

これついては、How to exclude .scala source file in project folderを読んで欲しい。

外部と内部

クラスパスは、内部と外部依存に分割することもできる。 内部依存とは、プロジェクト間の依存ということだ。

These effectively put the outputs of one project on the classpath of another project.

External classpaths are the union of the unmanaged and managed classpaths.

キー

クラスパスに関連するキーとしては以下

  • unmanaged-classpath
  • managed-classpath
  • external-dependency-classpath
  • internal-dependency-classpath

ソースについては

  • unmanaged-sources These are by default built up from unmanaged-source-directories, which consists of scala-source and java-source.
  • managed-sources These are generated sources.
  • sources Combines managed-sources and unmanaged-sources.
  • source-generators These are tasks that generate source files. Typically, these tasks will put sources in the directory provided by source-managed.

リソースについては

  • unmanaged-resources These are by default built up from unmanaged-resource-directories, which by default is resource-directory, excluding files matched by default-excludes.
  • managed-resources By default, this is empty for standard projects. sbt plugins will have a generated descriptor file here.
  • resource-generators These are tasks that generate resource files. Typically, these tasks will put resources in the directory provided by resource-managed.

Use the inspect command for more details.

Example

You have a standalone project which uses a library that loads xxx.properties from classpath at run time. You put xxx.properties inside directory "config". When you run "sbt run", you want the directory to be in classpath.

unmanagedClasspath in Runtime <<= (unmanagedClasspath in Runtime, baseDirectory) map { (cp, bd) => cp :+ Attributed.blank(bd / "config") }

Or shorter:

unmanagedClasspath in Runtime <+= (baseDirectory) map { bd => Attributed.blank(bd / "config") }