I'd like to create an SBT project with inheritance and shared dependencies.
With Maven's POM files, there is the idea of Project Inheritance where you can set a parent
project. I'd like to do the same thing with SBT.
The xchange-stream
library uses Maven's Project Inheritance to resolve subproject dependencies when compiled from the parent project.
Here is my idea of what the file structure would look like:
sbt-project/
project/
dependencies.scala # Contains dependencies common to all projects
build.sbt # Contains definition of parent project with references
# to subprojects
subproject1/
build.sbt # Contains `subproject3` as a dependency
subproject2/
build.sbt # Contains `subproject3` as a dependency
subproject3/
build.sbt # Is a dependency for `subproject1` and `subproject2`
Where project1
and project2
can include project3
in their dependencies lists like this:
libraryDependencies ++= "tld.organization" % "project3" % "1.0.0"
Such that when subproject1
or subproject2
are compiled by invoking sbt compile
from within their subdirectories, or when the parent: sbt-project
is compiled from the main sbt-project
directory, then subproject3
will be compiled and published locally with SBT, or otherwise be made available to the projects that need it.
Also, how would shared dependencies be specified in sbt-project/build.sbt
or anywhere in the sbt-project/project
directory, such that they are useable within subproject1
and subproject2
, when invoking sbt compile
within those subdirectories?
The following examples don't help answer either of the above points:
jbruggem/sbt-multiproject-example
:
Uses recursive build.sbt
files, but doesn't share dependencies among child projects.
Defining Multi-project Builds with sbt: pbassiner/sbt-multi-project-example
:
Uses a single build.sbt
file for the projects in their subdirectories.
sachabarber/SBT_MultiProject_Demo
:
Uses a single build.sbt
file.
If you have JAR files (unmanaged dependencies) that you want to use in your project, simply copy them to the lib folder in the root directory of your SBT project, and SBT will find them automatically.
The libraryDependencies key Most of the time, you can simply list your dependencies in the setting libraryDependencies . It's also possible to write a Maven POM file or Ivy configuration file to externally configure your dependencies, and have sbt use those external configuration files.
These tools support automatic dependency management for your project. Like in almost every build system, SBT allows you to define library dependencies which are resolved automatically, so you don't have to download and package required libraries by yourself.
A project is defined by declaring a lazy val of type Project. For example, : lazy val util = (project in file("util")) lazy val core = (project in file("core")) The name of the val is used as the subproject's ID, which is used to refer to the subproject at the sbt shell.
Such that when
subproject1
orsubproject2
are compiled by invokingsbt compile
from within their subdirectories...
Maybe Maven is meant to be used together with the shell environment and cd
command, but that's not how sbt works at least as of sbt 1.x in 2019.
The sbt way is to use sbt
as an interactive shell, and start it at the top level. You can then either invoke compilation as subproject1/compile
, or switch into it using project subproject1
, and call compile
in there.
A feature similar to parent POM would be achieved by creating a custom plugin.
package com.example
import sbt._
import Keys._
object FooProjectPlugin extends AutoPlugin {
override def requires = plugins.JvmPlugin
val commonsIo = "commons-io" % "commons-io" % "2.6"
override def buildSettings: Seq[Def.Setting[_]] = Seq(
organization := "com.example"
)
override def projectSettings: Seq[Def.Setting[_]] = Seq(
libraryDependencies += commonsIo
)
}
It's not exactly what you are asking for, but I have an experimental plugin that allows you to switch between source dependency and binary dependency. See hot source dependencies using sbt-sriracha.
Using that you could create three individual sbt builds for project1
, project2
, and project3
, all located inside $HOME/workspace
directory.
ThisBuild / scalaVersion := "2.12.8"
ThisBuild / version := "0.1.1-SNAPSHOT"
lazy val project3Ref = ProjectRef(workspaceDirectory / "project3", "project3")
lazy val project3Lib = "tld.organization" %% "project3" % "0.1.0"
lazy val project1 = (project in file("."))
.enablePlugins(FooProjectPlugin)
.sourceDependency(project3Ref, project3Lib)
.settings(
name := "project1"
)
With this setup, you can launch sbt -Dsbt.sourcemode=true
and it will pick up project3 as a subproject.
You can use Mecha super-repo concept. Take a look on the setup and docs here: https://github.com/storm-enroute/mecha
The basic idea is that you can combine dependent sbt projects (with their own build.sbt) under single root super-repo sbt project:
/root
/project/plugins.sbt
repos.conf
/project1
/src/..
/project/plugins.sbt
build.sbt
/project2
/src/..
/project/plugins.sbt
build.sbt
Please, note that there is no build.sbt
in the root folder!
Instead there is repos.conf
file. It contains definition of the sub-repos and looks like the folowing:
root {
dir = "."
origin = ""
mirrors = []
}
project1 {
dir = "project1"
origin = "[email protected]:some_user/project1.git"
mirrors = []
}
project2 {
dir = "project2"
origin = "[email protected]:some_user/project2.git"
mirrors = []
}
Then you can specify the Inter-Project, source-level Dependencies within individual projects.
There are two approaches:
dependencies.conf
fileFor more details, please, see the docs
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With