6

In SBT I create a new config, called katebush, as follows:

lazy val KateBush: Configuration = config("katebush")

When I try to run katebush:compile I get an error. That's what I expect.

> katebush:compile
[error] No such setting/task
[error] katebush:compile
[error]                 ^

Now I extend Compile in my config definition, and I expect to pick up the compile from the inherited scope.

lazy val KateBush: Configuration = config("katebush") extend Compile

Except it doesn't work:

> katebush:compile
[error] No such setting/task
[error] katebush:compile
[error]                 ^

But if I add in the defaults to the config (in build.sbt) so it looks as follows:

lazy val KateBush: Configuration = config("katebush") extend Compile

inConfig(KateBush)(Defaults.compileSettings)

it works fine:

> katebush:compile
[info] Updating {file:/Users/jacek/sandbox/so-25596360/}so-25596360...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[success] Total time: 0 s, completed Aug 31, 2014 11:35:47 PM

So, my question is, what exactly does extend for a configuration do?

Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
sksamuel
  • 16,154
  • 8
  • 60
  • 108

2 Answers2

6

DISCLAIMER I've got a rather basic understanding of the config concept of sbt.

tl;dr Extending a configuration is solely to inherit the dependencies groups not settings.

From the sources of final case class Configuration:

def extend(configs: Configuration*) = Configuration(name, description, isPublic, configs.toList ::: extendsConfigs, transitive)

By default, extendsConfigs is Nil as can be seen in the sbt.Configurations object:

def config(name: String) = new Configuration(name)

that resolves to (note Nil)

def this(name: String) = this(name, "", true, Nil, true)

In sbt.IvySbt.toIvyConfiguration:

import org.apache.ivy.core.module.descriptor.{ Configuration => IvyConfig }

and that's where the support of the config concept ends in sbt and Ivy steps in. That's where you'd have to look at the documentation of Ivy.

But before that read Advanced configurations example where it says:

This is an example .scala build definition that demonstrates using Ivy configurations to group dependencies.

That's the beginning of the explanation. Ivy configurations are to group dependencies and extending a configuration is to extend the grouping.

From the official documentation of Ivy about the conf element:

a configuration is a way to use or construct a module.(...) a module may need some other modules and artifacts only at build time, and some others at runtime. All those differents ways to use or build a module are called in Ivy module configurations.

Reading along you can find the answer to your question (that I'm myself yet to digest, too):

A configuration can also extend one or several other ones of the same module. When a configuration extends another one, then all artifacts required in the extended configuration will also be required in the configuration that extends the other one. For instance, if configuration B extends configuration A, and if artifacts art1 and art2 are required in configuration A, then they will be automatically required in configuration B. On the other hand, artifacts required in configuration B are not necessarily required in configuration A.

This notion is very helpful to define configurations which are similar with some differences.

At the bottom of the page, there's the Examples section with an example with runtime config that has "runtime will be composed of all dependencies, all transitively, including the dependencies declared only in compile."

With this, you can now understand the config concept in sbt as a dependencies groups and what's grouped in Compile is available in Runtime as its definition looks as follows:

lazy val Runtime = config("runtime") extend (Compile)
Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
  • 2
    Fantastic reply thanks. Rather disappointed that's all extend does. – sksamuel Aug 31 '14 at 22:43
  • What else would you expect? Settings are sbt while configurations come from Ivy. Perhaps sbt would have done more, but they're different concepts - configurations (Ivy/dependencies) vs scopes (sbt/namespaces). – Jacek Laskowski Aug 31 '14 at 22:48
  • I would have expected a config to inherit tasks/settings from parent configs. This is SBT - I don't care what Ivy does under the hood, nor should I. – sksamuel Aug 31 '14 at 22:52
  • I can understand the stand. I'm more to follow the rules of sbt at the moment until I've finally grasped all the concepts thoroughly. – Jacek Laskowski Sep 01 '14 at 11:55
0

I have just had to figure this out, so I thought this was worth clarifying. The configuration has to be added to the project for delegation to the extended configuration to occur:

lazy val KateBush: Configuration = config("katebush") extend Compile

lazy val root = (project in file(".")).configs(KateBush)

will work fine. If you

inspect katebush:compile

then you can view the delegation chain:

...
[info] Delegates:
[info]  katebush:compile
[info]  compile:compile
[info]  *:compile
[info]  {.}/katebush:compile
[info]  {.}/compile:compile
[info]  {.}/*:compile
[info]  */katebush:compile
[info]  */compile:compile
[info]  */*:compile
...
Will
  • 231
  • 1
  • 6