reikje
reikje

Reputation: 3064

How to share code between project and build definition project in SBT

If I have written some source code in my build definition project (in /project/src/main/scala) in SBT. Now I want to use these classes also in the project I am building. Is there a best practice? Currently I have created a custom Task that copies the .scala files over.

Upvotes: 7

Views: 1609

Answers (3)

Justin Kaeser
Justin Kaeser

Reputation: 5948

Sharing sourceDirectories as in extempore's answer is the simplest way to go about it, but unfortunately it won't work well with IntelliJ because the project model doesn't allow sharing source roots between multiple modules.

Seth Tisue's approach will work, but requires rebuilding to update sources.

To actually share the sources and have IntelliJ pick up on it directly, you can define a module within the build.

The following approach seems to only work in sbt 1.0+

Create a file project/metabuild.sbt:

val buildShared = project
val buildRoot = (project in file("."))
  .dependsOn(buildShared)

and in your build.sbt:

val buildShared = ProjectRef(file("project"), "buildShared")
val root = (project in file("."))
  .dependsOn(buildShared)

Then put your shared code in project/buildShared/src/main/scala/ and refresh. Your project will look something like this in IntelliJ:

enter image description here

Full example project: https://github.com/jastice/shared-build-sources

Upvotes: 5

psp
psp

Reputation: 12158

Those seem like unnecessarily indirect mechanisms.

unmanagedSourceDirectories in Compile += baseDirectory.value / "project/src/main"

Upvotes: 5

Seth Tisue
Seth Tisue

Reputation: 30508

Can you make the following work? Put the source code for the classes in question should be part of your project, not part of your build definition; the “task which serializes a graph of Scala objects using Kryo and writes them as files into the classpath of the project” part sounds like a perfect job for resourceGenerators (see http://www.scala-sbt.org/0.13.2/docs/Howto/generatefiles.html). Then the only remaining problem is how to reference the compiled classes from your resource generator. I'm not familiar with Kryo. In order to use it, do you need to have the compiled classes on the classpath at the time your generator is compiled, or do they just need to be on the classpath on runtime? If the latter is sufficient, that's easier. You can get a classloader from the testLoader in Test key, load the class and instantiate some objects via reflection, and then call Kryo.

If you really need the compiled classes to be on the classpath when your resource generator is compiled, then you have a chicken and egg problem where the build can't be compiled until the project has been compiled, but of course the project can't be compiled before the build definition has been compiled, either. In that case it seems to me you have no choices other than:

1) the workaround you're already doing ("best practice" in this case would consist of using sourceGenerators to copy the sources out of your build definition and into target/src_managed)

2) put the classes in question in a separate project and depend on it from both your build and your project. this is the cleanest solution overall, but you might consider it too heavyweight.

Hope this helps. Interested in seeing others' opinions on this, too.

Upvotes: 1

Related Questions