Roland
Roland

Reputation: 23232

build.gradle.kts & multi-module-project: how to add other project so that transitive dependencies are available too

Having the following multi-module-setup:

multi
├── projA
│   └── build.gradle.kts
├── projB
│   └── build.gradle.kts
├── build.gradle.kts
└── settings.gradle.kts

with the following content (abbreviated):

Why don't I have access to that importantlibrary:1.0 from projB?

What works: if I have a class within projA that uses the library, it works perfectly even if that class is called from a class within projB (so indirect access works). Directly accessing any class from importantlibrary:1.0 within projB doesn't work (unresolved reference).

What am I missing here? Or what needs to be set up so that it works?

Gradle version: 5.6.1

Upvotes: 14

Views: 23984

Answers (3)

Braian Coronel
Braian Coronel

Reputation: 22867

There are 2 themes: transitivity of dependencies and /src as dependency

  • Dependency transitivity

We use api so that the dependency can be exported to the higher hierarchy of modules.

build.gradle.kts (:library_base)

dependencies {
    api("group", "name", "version")
}

build.gradle.kts (:common)

dependencies {
    implementation(project(":domain"))
    implementation(project(":library_base"))
}
  • Transitivity of /src as dependency

We pass "default" in the second parameter as configuration to be able to import the /src from the lower hierarchy of modules.

build.gradle.kts (:feature_a)

dependencies {
    implementation(project(":common", "default"))
}

To be able to access from :feature_a to /src of eg. :domain we use "default" as configuration and to be able to access the dependencies of :library_base we make sure that they are defined with api in that module so that they can be exported.

GL

Source

Upvotes: 8

gscaparrotti
gscaparrotti

Reputation: 740

I think a good way to achieve what you want would be to use api instead of implementation. implementation is meant to only keep the dependency inside the module, while api is meant to export them along with the module. The dependencies for projA would then become:

dependencies {
    api("important-library:1.0")
}

This is the link to the official documentation: https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation

Upvotes: 9

Roland
Roland

Reputation: 23232

I found lots of sources mentioning configuration to handle how transitive dependencies are dealt with. Digging deeper I found that the default configuration should make the runtime, runtimeOnly and implementation available to the referencing project.

Either I misinterpreted "default" here or you really need to call it using the "default"-configuration explicitly. Declaring the dependency as follows in projB, made the dependencies from projA available to projB as well:

implementation(project(":projA", "default"))
// or with named parameters:
implementation(project(path = ":projA", configuration = "default"))

Wondering whether this is/was really intended or whether that is rather an unfortunate default value for the configuration-parameter of the project-function.

Upvotes: 4

Related Questions