In the previous post, I introduced how to use sbt for building Java projects. In response to this article my colleagues in Treasure Data asked me on how to build multi-module projects with sbt. So, today I will talk about this topic.
Configuring multi-module projects with sbt is simple. In Maven, we need to write a parent pom.xml and
child pom.xml files for all of the sub modules. In sbt you only need to prepare one project file (build.sbt or projecct/Build.scala).
Suppose we have the following folder structure with a parent module (root folder) and two sub modules core and util:
1234
project/Build.sbt
src
core/src
util/src
Here is a simple multi-module project setting example. Project core depends on fluent-logger library, while project util has no library dependency. Projects are defined by using variables: root, core and util. You can use these variable names to reference projects in the build file and sbt console.
For Scala newbies: object means a definition of a singleton class. lazy val is a variable defintion that will be evaluated when it is used for the first time.
You can specify module directories with project.in(file("...")) syntax. The default directory becomes the same with the variable name. A project with the root directory file(".") will be the root project, which will be selected by default when lauching sbt.
In the above example, the root project aggregates util and core projects. Enter the sbt console, and try test command. All test codes in three projects, including root, util and core, will be tested.
12345678
> test[info] Passed: Total 0, Failed 0, Errors 0, Passed 0
[info] Passed: Total 0, Failed 0, Errors 0, Passed 0
[info] Passed: Total 0, Failed 0, Errors 0, Passed 0
[info] No tests to run for root/test:test
[info] No tests to run for util/test:test
[info] No tests to run for core/test:test
[success] Total time: 0 s, completed 2014/03/27 11:52:12
To run the test cases in a specific module, select a project name in sbt:
123456
> project core
[info] Set current project to core (in build file:/Users/leo/work/tmp/mproj/)> test[info] Passed: Total 0, Failed 0, Errors 0, Passed 0
[info] No tests to run for core/test:test
[success] Total time: 0 s, completed 2014/03/27 11:53:50
You can see the project settings with show commands:
1234
> show version
[info] 0.1-SNAPSHOT
> show dependencyClasspath
[info] List(Attributed(/Users/leo/.sbt/boot/scala-2.10.3/lib/scala-library.jar), Attributed(/Users/leo/.ivy2/cache/org.fluentd/fluent-logger/jars/fluent-logger-0.2.10.jar), Attributed(/Users/leo/.ivy2/cache/org.msgpack/msgpack/bundles/msgpack-0.6.7.jar), Attributed(/Users/leo/.ivy2/cache/com.googlecode.json-simple/json-simple/bundles/json-simple-1.1.1.jar), Attributed(/Users/leo/.ivy2/cache/junit/junit/jars/junit-4.10.jar), Attributed(/Users/leo/.ivy2/cache/org.hamcrest/hamcrest-core/jars/hamcrest-core-1.1.jar), Attributed(/Users/leo/.ivy2/cache/org.javassist/javassist/jars/javassist-3.16.1-GA.jar))
If you are not sure names of settings keys, use <TAB> completion.
Building jar files
Now, let’s go back to the root project:
123456789
> project root
[info] Set current project to root (in build file:/Users/leo/work/tmp/mproj/)> show version
[info] core/*:version
[info] 0.1-SNAPSHOT
[info] util/*:version
[info] 0.1-SNAPSHOT
[info] root/*:version
[info] 0.1-SNAPSHOT
publishLocal command creates .jar, -source.jar and -javadoc.jar of your projects, then install them to your local ivy repository $HOME/.ivy2/local. While publishM2 commands install them to your local Maven repository $HOME/.m2/repository.
To deploy jars to a remote repository, use publish command. This is equivalent to mvn deploy command in Maven.
sbt-sontaype plugin A sbt plugin I developed for publishing projects to the Maven central repository.
Project dependencies
aggregate settings is just for convenience of running commands in multiple projects.
If some project actually depends on another project’s code, use dependsOn:
1
lazyvalcore=project.settings(...).dependsOn(util)
Now core project can use classes in util project and its dependent libraries. Try publishLocal:
1234
> publishLocal
...
[info] published core_2.10 to /Users/leo/.ivy2/local/core/core_2.10/0.1-SNAPSHOT/poms/core_2.10.pom
...
This creates .pom xml files under the target folder of each module. Looking at the generated pom.xml file, you can confirm the dependency to util package is properly set:
If you do not want include Scala library in the dependency, especially for building pure-java projects, set autoScalaLibrary to false in the project settings. And also to remove Scala versions appended to the artifactId, set crossPaths to false.