Extending both transitive and intransitive configurations

Consider the following setup:

configurations {
  compileTransitive {
    transitive = true
  }
  compileFlat {
    transitive = false
  }
  compile {
    extendsFrom compileTransitive
    extendsFrom compileFlat
  }
}

dependencies {
  compileTransitive 'top:trans:dep' // this depends on a.b.c
  compileFlat 'top.flat.dep' // this depends on x.y.z
}

Here I’ve created two configurations, one whose dependencies should be transitive, and one whose dependencies should not. I’ve then made the compile config extend both of those configurations.

My expectation was that I’d end up with the following set of libraries in the compile configuration:

top:trans:dep
a.b.c // because top:trans:dep depends on it, and compileTransitive allows transitive dependencies
top.flat.dep

Specifically, I did not expect to see x.y.z in my compile configuration, but that is not the case. Here’s what I actually see in my compile config:

top:trans:dep
a.b.c
top.flat.dep
x.y.z

It seems as though extendsFrom does not honor the transitivity of the configuration being extended. This is surprising. In order to achieve what I want here, I have to update each dependency in compileFlat to specify transitive: false, which seems to defeat the purpose of setting it on the configuration.

What am I missing? Is there some magic step I don’t know that would allow me to mark an entire configuration as intransitive and have that be honored when the config is extended?

Hi,

Did you find a solution for this issue? I have the same problem with the latest Gradle version (8.7). Is this a limitation of Gradle?

Wow… Sorry, @tdelhomenie. I have no idea. This was 7 years and two jobs ago. I have no idea how I fixed this or if I just worked around it.

Probably the latter.

Extending a configuration just means that it is like the dependencies you declared on the extended configuration are also declared on the extending configuration.

Things like attributes, transitivity, and so on, are not “inherited”.

Also usually you separate concerns of configurations. You have configurations on which you declare dependencies like api, implementation, compileOnly, runtimeOnly, … And then you have configurations that extend from those and are used for resolving that then might have transitivity set or attributes configured like runtimeClasspath or compileClasspath.