Reputation:
I want to work on multiple sbt-projects at the same time in intellij. The projects are "one way dependent", meaning that one is the (reusable) core and the other is an actual application built upon that core. Both are currently in development.
I want the core to reside in another base/root-directory than the application, so:
- /core
-- build.sbt
- /application
-- build.sbt
I want to be able to
What I've tried and which problems I've found so far:
setups like
lazy val core = project.in(file("../core"))
lazy val application = project.in(file(".")).dependsOn(core)
are not working, because an sbt asserts that the directory of each project in a multi-project-setup are contained in the same build root:
sbt java.lang.AssertionError: assertion failed: Directory /core is not contained in build root /application
setups like
lazy val core = RootProject(file("../core"))
lazy val application = project.in(file(".")).dependsOn(core)
are not a solution because:
Now I am a sbt-newbie and I guess (and hope) that there must be a solution for this problem. I can't be the only one wanting to separate my projects without a wrapper-layer and still be able to modify them in the IDE of my choice.
edit:
@OlegRudenko´s solution is semi-working for me. As core
has some dependencies as well, I cannot compile or work with it in application
.
core
pulls in some dependencies like e.g. a Logger and when I'm in application
and try to use a component of core
the compiler screams at me, because it can't find the dependencies in core
(e.g. the logger).
Also, core
pulls in e.g. lwjgl and I want to use some components of it in application
, no chance, because it can't find the packages for that dependency of core
.
For now what I do is a hacky non-solution. I just develop both core
and application
in the same intellij-project and keep the git-repo private.
This is not a solution at all, as I want to open source core
while application
is closed source for now and I still want to work on both at the same time, refine the core
etc.
Upvotes: 9
Views: 4617
Reputation: 6139
You could use ProjectRef:
lazy val my_application = (project in file ("."))
.aggregate(my_core)
.dependsOn(my_core)
lazy val my_core = ProjectRef(file("../my_core"), "my_core")
Then, regarding the directory structure, my_application
and my_core
are siblings.
Upvotes: 3
Reputation: 698
If some framework does not allow me something, I prefer to not fight but to find a compromise.
SBT does not allow to have a sub-project outside of project root. So my solution would be to create a symbolic link inside my project to the sub-project, which is located outside:
common/
common/core/ - I want this as a sub-project inside of my project
application/
application/ui/ - This is my project
application/ui/core/ -> ../../common/core/ - This is my goal
It has to
Solution is to add following lines into the SBT file:
val __createLinkToCore = {
import java.nio.file.{FileSystemException, Files, Paths}
import scala.util.Try
val corePath = Paths.get("..", "..", "common", "core")
if(!Files.exists(corePath)) throw new IllegalStateException("Target path does not exist")
val linkPath = Paths.get("core")
if(Files.exists(linkPath)) Files.delete(linkPath)
Try {Files.createSymbolicLink(linkPath, corePath)}.recover {
case cause: FileSystemException if System.getProperty("os.name").toLowerCase.contains("windows") =>
val junctionCommand = Array("cmd", "/c", "mklink", "/J", linkPath.toAbsolutePath.normalize().toString, corePath.toAbsolutePath.normalize().toString)
val junctionResult = new java.lang.ProcessBuilder(junctionCommand: _*).inheritIO().start().waitFor()
if(junctionResult != 0) throw new Exception("mklink failed", cause)
linkPath
}.get
}
It is executed every time when SBT is started but before any action on your code - before compilation and so on. It does NOT recreate the link on every compilation - only once per SBT start.
The code does following:
mklink /J
Limits of this solution:
Upvotes: 6
Reputation: 15464
I don't think this is possible in SBT (but I'd love to hear otherwise).
Here's what I'm doing in IntelliJ to work around this issue:
Upvotes: 3