In SBT is the use of aggregate following dependsOn redundant if they both contain the same sub-modules? According to the documentation it seems so, but I have seen this behavior used before and I don't understand what the benefit is. If a project is defined with dependencies, doesn't that already imply what aggregate does for those same dependencies? I notice that my project build is much slower with the use of this redundant aggregate than without and I'd like to know if I can safely remove it.
lazy val module = sbt.Project(...) dependsOn (foo, bar) aggregate (foo, bar)
OR just...
lazy val module = sbt.Project(...) dependsOn (foo, bar)
I am using SBT 0.13.6
clean – delete all generated sources, compiled artifacts, intermediate products, and generally all build-produced files. reload – reload the build, to take into account changes to the sbt plugin and its transitive dependencies.
The publish action is used to publish your project to a remote repository. To use publishing, you need to specify the repository to publish to and the credentials to use. Once these are set up, you can run publish .
The simple build tool (sbt) is used for building Java and Scala projects; its purpose is to allow users to skillfully perform the basics of building and to customize endlessly.
sbt is an open-source build tool for Scala and Java projects, similar to Apache's Maven and Ant. sbt. Original author(s) Mark Harrah. Developer(s)
tl;dr aggregate
causes the tasks to be executed in the aggregating module and all aggregate
d one while dependsOn
sets a CLASSPATH dependency so the libraries are visible to the aggregate
ing module (depending on the configuration that's compile
aka default
in the example).
A sample to demonstrate the differences.
I'm using the following build.sbt
(nothing really interesting):
lazy val a = project lazy val b = project lazy val c = project dependsOn b aggregate (a,b)
The build defines three modules a
, b
, and c
with the last c
project to be an aggregate for a
and b
. There's the fourth module - an implicit one - that aggregates all the modules a
, b
, and c
.
> projects [info] In file:/Users/jacek/sandbox/aggregate-dependsOn/ [info] a [info] * aggregate-dependson [info] b [info] c
When I execute a task in an aggreate
ing module, the task is going to be executed in the aggregate
d modules.
> compile [info] Updating {file:/Users/jacek/sandbox/aggregate-dependsOn/}b... [info] Updating {file:/Users/jacek/sandbox/aggregate-dependsOn/}a... [info] Updating {file:/Users/jacek/sandbox/aggregate-dependsOn/}aggregate-dependson... [info] Resolving org.fusesource.jansi#jansi;1.4 ... [info] Done updating. [info] Resolving org.fusesource.jansi#jansi;1.4 ... [info] Done updating. [info] Resolving org.fusesource.jansi#jansi;1.4 ... [info] Done updating. [info] Updating {file:/Users/jacek/sandbox/aggregate-dependsOn/}c... [info] Resolving org.fusesource.jansi#jansi;1.4 ... [info] Done updating. [success] Total time: 0 s, completed Oct 22, 2014 9:33:20 AM
The same happens when I execute a task in c
that will in turn execute it against a
and b
, but not in the top-level project.
> show c/clean [info] a/*:clean [info] () [info] b/*:clean [info] () [info] c/*:clean [info] () [success] Total time: 0 s, completed Oct 22, 2014 9:34:26 AM
When a task's executed in a
or b
, it runs only within the project.
> show a/clean [info] () [success] Total time: 0 s, completed Oct 22, 2014 9:34:43 AM
Whether or not a task is executed in aggregate
ing projects is controlled by aggregate
key scoped to a project and/or task.
> show aggregate [info] a/*:aggregate [info] true [info] b/*:aggregate [info] true [info] c/*:aggregate [info] true [info] aggregate-dependson/*:aggregate [info] true
Change it as described in Aggregation:
In the project doing the aggregating, the root project in this case, you can control aggregation per-task. (...)
aggregate in
update is the aggregate key scoped to the update task.
Below I'm changing the key for c
module and clean
task so clean
is no longer executed in aggregate
d modules a
and b
:
> set aggregate in (c, clean) := false [info] Defining c/*:clean::aggregate [info] The new value will be used by no settings or tasks. [info] Reapplying settings... [info] Set current project to aggregate-dependson (in build file:/Users/jacek/sandbox/aggregate-dependsOn/) > show c/clean [info] () [success] Total time: 0 s, completed Oct 22, 2014 9:39:13 AM
The other tasks for c
are unaffected and still executing a task in c
will run it in the aggregate
modules:
> show c/libraryDependencies [info] a/*:libraryDependencies [info] List(org.scala-lang:scala-library:2.10.4) [info] b/*:libraryDependencies [info] List(org.scala-lang:scala-library:2.10.4) [info] c/*:libraryDependencies [info] List(org.scala-lang:scala-library:2.10.4)
While aggregate
sets a dependency for sbt tasks so they get executed in the other aggregate
d modules, dependsOn
sets a CLASSPATH dependency, i.e. a code in dependsOn
ed module is visible in the dependsOn
ing one (sorry for the "new" words).
Let's assume b
has a main object as follows:
object Hello extends App { println("Hello from B") }
Save the Hello
object to b/hello.scala
, i.e. under b
module.
Since c
was defined to dependsOn b
(see build.sbt
above), the Hello
object is visible in b
(because it belongs to the module), but also in c
.
> b/run [info] Running Hello Hello from B [success] Total time: 0 s, completed Oct 22, 2014 9:46:44 AM > c/runMain Hello [info] Running Hello Hello from B [success] Total time: 0 s, completed Oct 22, 2014 9:46:58 AM
(I had to use runMain
in c
as run
alone couldn't see the class that I can't explain).
Trying to run the task in a
ends up with java.lang.ClassNotFoundException: Hello
since the class is not visible in the module.
> a/runMain Hello [info] Updating {file:/Users/jacek/sandbox/aggregate-dependsOn/}a... [info] Resolving org.fusesource.jansi#jansi;1.4 ... [info] Done updating. [info] Running Hello [error] (run-main-6) java.lang.ClassNotFoundException: Hello java.lang.ClassNotFoundException: Hello at java.lang.ClassLoader.findClass(ClassLoader.java:530) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) [trace] Stack trace suppressed: run last a/compile:runMain for the full output. java.lang.RuntimeException: Nonzero exit code: 1 at scala.sys.package$.error(package.scala:27) [trace] Stack trace suppressed: run last a/compile:runMain for the full output. [error] (a/compile:runMain) Nonzero exit code: 1 [error] Total time: 0 s, completed Oct 22, 2014 9:48:15 AM
Redefine a
to dependsOn b
in build.sbt
and the exception vanishes.
You should read Multi-project builds in the official documentation.
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