virtualeyes
virtualeyes

Reputation: 11245

SBT `CrossProject` build broken with custom compile target

Getting "Overlapping output directories" sbt error with custom compile target (ramdisk on /tmp/sbt/) defined for a Scala.js CrossProject based build.

FWIW, have used above compile target seamlessly in SBT projects for 3 years running. The error does not occur when using sbt default compile target (i.e. build project root). Kind of a show stopper since my tooling is geared around ramdisk setup.

Here's the actual error:

Overlapping output directories:/tmp/sbt/foo:
[error]     ProjectRef(file:/home/me/path/to/project/,fooJS)
[error]     ProjectRef(file:/home/me/path/to/project/,fooJVM)

Have tried subclassing CrossType as suggested in the docs, overriding projectDir and sharedSrcDir to no avail, same error. Here's SBT source location where overlapping targets are checked.

I'm wondering why this occurs with a custom compile target, but not the default target? More importantly, how can I get a custom compile target working with Scala.js' crossProject?

Upvotes: 1

Views: 386

Answers (1)

sjrd
sjrd

Reputation: 22105

From the comments, you're customizing the target directory like this:

target <<= (name) { (name) => file("/tmp/sbt") / name }

which, in 0.13 notation, means this:

target := file("/tmp/sbt") / name.value

This will cause problems with cross-projects because both the JVM and JS variants of a crossProject have the same name by default, and hence both projects will indeed end up with the same target directory, which causes your conflict.

You have two possibilities to fix this. Either you change the name settings so that they are not the same (but then you need to re-customize the normalizedNames so that they're the same again), or you change the way you compute the target so that it will be different.

First solution:

lazy val foo = crossProject.in(...).
  jvmSettings(name := name.value + "-jvm").
  jsSettings(name := name.value + "-js").
  settings(
    normalizedName := normalizedName.value.stripSuffix("-jvm").stripSuffix("-js")
  ).
  // other settings

That's not very elegant. I suggest the other approach, for example:

target := {
  /* Hacky way to detect whether this is a Scala.js project
   * without pulling the Scala.js sbt plugin on the classpath.
   */
  val isScalaJS = libraryDependencies.value.exists { dep =>
    dep.name.startsWith("scalajs-library") // not tested
  }
  file("/tmp/sbt") / (name.value + (if (isScalaJS) "-js" else ""))
}

Not very elegant either because of the hack, but at least you only need it once in your global config.

Upvotes: 2

Related Questions