6

次のようなファイルを含む、3 つのサブプロジェクトを含む Scala プロジェクトがあるとします。

foo/src/main/scala/Foo.scala
foo/src/main/resources/foo.txt

bar/src/main/scala/Bar.scala
bar/src/main/resources/bar.txt

baz/src/main/scala/Baz.scala
baz/src/main/resources/baz.txt

Foo.scala特定のパスでリソースを読み取る単純なマクロが含まれています。

import scala.language.experimental.macros
import scala.reflect.macros.Context

object Foo {
  def countLines(path: String): Option[Int] = macro countLines_impl

  def countLines_impl(c: Context)(path: c.Expr[String]) = {
    import c.universe._

    path.tree match {
      case Literal(Constant(s: String)) => Option(
        this.getClass.getResourceAsStream(s)
      ).fold(reify(None: Option[Int])) { stream =>
        val count = c.literal(io.Source.fromInputStream(stream).getLines.size)
        reify(Some(count.splice))
      }
      case _ => c.abort(c.enclosingPosition, "Need a literal path!")
    }
  }
}

リソースを開くことができる場合はcountLines、行数を返します。それ以外の場合は空です。

他の 2 つの Scala ソース ファイルは、このマクロを呼び出すだけです。

object Bar extends App {
  println(Foo.countLines("/foo.txt"))
  println(Foo.countLines("/bar.txt"))
  println(Foo.countLines("/baz.txt"))
}

と:

object Baz extends App {
  println(Foo.countLines("/foo.txt"))
  println(Foo.countLines("/bar.txt"))
  println(Foo.countLines("/baz.txt"))
}

リソースの内容は、この質問の目的にはあまり関係ありません。

これが Maven プロジェクトの場合、ルート プロジェクトが 3 つのサブプロジェクトを集約し、 にbaz依存するように簡単に構成できます。詳細については、この Gistを参照してください。barfoo

Maven を使用すると、すべてが期待どおりに機能します。とBarのリソースを表示できます:foobar

Some(1)
Some(2)
None

そしてBazそれらすべてを見ることができます:

Some(1)
Some(2)
Some(3)

今、私はSBTで同じことを試しています:

import sbt._
import Keys._

object MyProject extends Build {
  lazy val root: Project = Project(
    id = "root", base = file("."),
    settings = commonSettings
  ).aggregate(foo, bar, baz)

  lazy val foo: Project = Project(
    id = "foo", base = file("foo"),
    settings = commonSettings
  )

  lazy val bar: Project = Project(
    id = "bar", base = file("bar"),
    settings = commonSettings,
    dependencies = Seq(foo)
  )

  lazy val baz: Project = Project(
    id = "baz", base = file("baz"),
    settings = commonSettings,
    dependencies = Seq(bar)
  )

  def commonSettings = Defaults.defaultSettings ++ Seq(
    scalaVersion := "2.10.2",
    libraryDependencies <+= scalaVersion("org.scala-lang" % "scala-compiler" % _)
  )
}

しかし、今Barでは以下のリソースしか見ることができませんfoo:

Some(1)
None
None

とのみをBaz見ることができます:foobar

Some(1)
Some(2)
None

何が起きてる?この SBT ビルド ファイルは、Maven 構成のかなり文字通りの翻訳のように思えます。たとえば、プロジェクトでコンソールを開いてbarを読むのに問題はないのに/bar.txt、マクロを呼び出すときにこれらのプロジェクトが独自のリソースを表示できないのはなぜですか?

4

1 に答える 1

6

SBT は、現在のプロジェクトのリソースをビルド クラスパスに追加しません。おそらく、ほとんど必要とされないためです。

一方 (リソース) をもう一方 (クラスパス) にパイプするだけです。

def commonSettings = Defaults.defaultSettings ++ Seq(
  scalaVersion := "2.10.2",
  libraryDependencies <+= scalaVersion("org.scala-lang" % "scala-compiler" % _),
  // add resources of the current project into the build classpath
  unmanagedClasspath in Compile <++= unmanagedResources in Compile
)

barそのプロジェクトでは、とに対してのみ必要ですbaz

更新: sbt 0.13 以降、新しいマクロベースの構文のおかげで<+=andは不要です (そしてドキュメント化されていません):<++=

libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value
unmanagedClasspath in Compile ++= (unmanagedResources in Compile).value
于 2013-07-28T22:32:14.063 に答える