Javi
11/24/2025, 9:37 AMimplementation configuration and looking for the dependencies there.Martin
11/24/2025, 10:16 AMruntimeClasspathJavi
11/24/2025, 10:16 AMMartin
11/24/2025, 10:17 AMMartin
11/24/2025, 10:17 AM./gradle dependencies should show everythingMartin
11/24/2025, 10:18 AMconfigurations.getByName("debugRuntimeClasspath").resolvedConfiguration.resolvedArtifactsMartin
11/24/2025, 10:19 AMJavi
11/24/2025, 10:29 AMJavi
11/24/2025, 3:07 PMruntimeClasspath configuration, only runtimeOnly, which is not resolvable 🤔Javi
11/24/2025, 3:13 PMcruntimeClasspath 😕Martin
11/24/2025, 3:30 PMdebugRuntimeClasspath or soJavi
11/24/2025, 3:30 PMMartin
11/24/2025, 3:30 PMJavi
11/24/2025, 3:30 PMruntimeOnlyMartin
11/24/2025, 3:37 PMConfetti $ ./gradlew :androidApp:dependencies |grep -i runtimeclasspath
debugAndroidTestRuntimeClasspath - Runtime classpath of '/debugAndroidTest'.
debugRuntimeClasspath - Runtime classpath of '/debug'.Martin
11/24/2025, 3:38 PM./gradlew dependencies say?Javi
11/24/2025, 3:42 PMJavi
11/24/2025, 3:42 PMnamed { }, is it not lazy?Martin
11/24/2025, 3:43 PMnamed {} is not lazyMartin
11/24/2025, 3:44 PMMartin
11/24/2025, 3:45 PMconfigurations.configureEach {
if (name == "debugRuntimeClasspath") {
resolvedConfiguration.resolvedArtifacts.forEach { println(it.id) }
}
}Martin
11/24/2025, 3:45 PMJavi
11/24/2025, 3:49 PMJavi
11/24/2025, 3:50 PMconfigurations.configureEach {
if(...) this.resolvedConfiguration.resolvedArtifacts
}Javi
11/24/2025, 3:51 PMresolvedConfiguration?Martin
11/24/2025, 3:52 PMJavi
11/24/2025, 3:52 PMMartin
11/24/2025, 3:53 PMJavi
11/24/2025, 4:10 PMJavi
11/24/2025, 4:36 PMJavi
11/24/2025, 4:36 PMMartin
11/24/2025, 4:41 PMVampire
11/24/2025, 6:21 PMNah,Of course it isis not lazynamed {}
Vampire
11/24/2025, 6:21 PMmatching {}.
So unless you only call configureEach {} on the result, you are safe / lazyVampire
11/24/2025, 6:22 PMMartin
11/24/2025, 6:27 PMVampire
11/24/2025, 7:02 PMVampire
11/24/2025, 7:03 PMconfigurations.configureEach { }Vampire
11/24/2025, 7:03 PMVampire
11/24/2025, 7:05 PMconfigurations.named { it == "foo" }.configureEach { ... }
===
configurations.matching { it.name == "foo" }.configureEach { ... }
===
configurations.configureEach { if (name == "foo") { ... }Vampire
11/24/2025, 7:05 PMMartin
11/24/2025, 8:24 PMtasks.named("") {}?Laura Kassovic
11/24/2025, 10:51 PMdebugRuntimeClasspath and `releaseRuntimeClasspath`:
configurations.getByName("debugRuntimeClasspath").resolvedConfiguration.resolvedArtifactsLaura Kassovic
11/24/2025, 10:57 PMconfigurations.named("foo").configure { ... } // direct by name
configurations.named { it.name == "foo" }.configureEach { ... }
configurations.matching { ... }.configureEach { ... }
configurations.configureEach { if (name == "foo") { ... } }Laura Kassovic
11/24/2025, 10:58 PMresolvedConfiguration at the right time.Martin
11/24/2025, 11:04 PM// Configuration with name 'foo' not found
configurations.named("foo")
vs
// Hooray!
configurations.configureEach {
if (name == "foo") {
println("Hoorayy")
}
}
configurations.create("foo")Martin
11/24/2025, 11:05 PMMartin
11/24/2025, 11:06 PMLaura Kassovic
11/24/2025, 11:09 PM.named returns a ProviderLaura Kassovic
11/24/2025, 11:16 PMMartin
11/24/2025, 11:20 PM.named(String) vs .named(Spec<String>), etc...Martin
11/24/2025, 11:21 PMandroidComponents {
onVariants(selector().withName("debug")) {
val configuration = it.runtimeConfiguration
val provider = provider {
configuration.resolvedConfiguration.resolvedArtifacts.map { it.id }
}
tasks.register("dumpDependencies") {
doFirst {
println(provider.get().joinToString("\n"))
}
}
}
}Vampire
11/25/2025, 12:33 AMSo it's different fromYes,?tasks.named("") {}
tasks.named(...) requires that a task is already registered and you get a TaskProvider.
With tasks.named { ... } you get a lazy task collection with all matching tasks (which might be 0) and as long as you only use configureEach on it, it is also configuration-avoidance safe.Javi
11/25/2025, 8:39 AMimplementation configuration. Get the Jar files, and get a list of classes using a specific annotation with ClassGraph.Javi
11/25/2025, 8:42 AMimplementation(providerOfAListOfStrings). And I think you cannot pass a lazy object like provider to the BuildConfig 🤔Martin
11/25/2025, 9:28 AMAdd them as dependencies to theMmmm they should already be there?configurationimplementation
debugRuntimeClasspath should have everything from implementation, not the other way around. If you need more things in implementation you probably need to model your dependencies differently using extendsFrom or something similar. What is the use case?Martin
11/25/2025, 9:29 AMGet the Jar files, and get a list of classes using a specific annotation withThat part definitely needs to happen in a task, this is a lot of work that you don't want to do at configuration time..ClassGraph
Javi
11/25/2025, 9:29 AMMartin
11/25/2025, 3:01 PMBuildConfig doesn't allow providers, you can use https://github.com/gmazzo/gradle-buildconfig-plugin insteadMartin
11/25/2025, 3:01 PMJavi
11/25/2025, 3:43 PMVampire
11/25/2025, 6:34 PMConfiguration#withDependencies { ... }.
This hook es executed right before a configuration takes part in dependency resolution first and is the place to go to add last-minute dependencies, for example based on other dependencies in that configuration.Javi
11/26/2025, 11:32 AMwithDependencies, I get a circular dependency if I map the dependencies (project oens) from debugRuntimeClasspath to project paths and I trying to add them.
project
.configurations
.named { it == "implementation" }
.configureEach {
withDependencies {
val projectDependencies: Provider<List<ProjectDependency>> =
allModuleGradlePaths.map { paths -> paths.map { project.dependencies.project(it) } }
addAllLater(projectDependencies)
}
}
Circular evaluation detected: list(interface org.gradle.api.artifacts.Dependency, map(map(map(provider(?)))))
-> map(map(map(provider(?))))
-> map(map(provider(?)))
-> map(provider(?))
-> provider(?)
-> list(interface org.gradle.api.artifacts.Dependency, map(map(map(provider(?)))))Javi
11/26/2025, 11:33 AMapi in our project, so I need to add all transitive project dependencies to the implementation configuration automatically to ensure all symbols are resolved. In an ideal scenario, this wouldn't be necessary because any project that expose those relevant public symbols would be added as api, but... I cannot change this.Javi
11/26/2025, 11:38 AMproject.tasks.register("javi").configure {
doLast {
val projectDependencies: List<ProjectDependency> =
allModuleGradlePaths.get().map { project.dependencies.project(it) }
println("JAVI:")
println(projectDependencies.joinToString("\n") { " - ${it.path}" })
}
}
So, I think, the issue is trying to add inside withDependencies any dependency that is being got from another configuration that is extending to the one using withDependenciesVampire
11/26/2025, 12:00 PMimplementation that depends on what runtimeClasspath (or whatever) returns, and at the time the runtimeClasspath is resolved, the provider is resolved and you have the recursion.
What is allModuleGradlePaths?Javi
11/26/2025, 1:01 PMruntimeClasspath. So, it is not possible to do thisVampire
11/26/2025, 1:11 PMJavi
11/26/2025, 1:13 PMJavi
11/26/2025, 1:13 PMVampire
11/26/2025, 1:14 PMJavi
11/26/2025, 1:15 PMVampire
11/26/2025, 1:15 PMJavi
11/26/2025, 1:17 PMVampire
11/26/2025, 1:18 PMJavi
11/26/2025, 1:19 PMVampire
11/26/2025, 1:21 PMJavi
11/26/2025, 1:21 PMapi.
Additionally, ksp is a bull****, I hope compiler plugins get a standardized-stable API and most projects drop the usage of KSP. I got a compiler plugin working, fast and easily in a few days without having to fight with any Gradle thing, but ksp cannot work with the compiler plugin as it runs before any Kotlin compilation runs...Javi
12/01/2025, 10:46 AMproject-b (depends on project-a): uses the configuration to get the txt file and add the list of dependencies to its implementation configuration. Currently, I need to do a double build to first generate the file, and later being able to compile with the new dependencies. Same about syncing the IDE, the txt file must be first generated to be able to see the symbols.Vampire
12/01/2025, 12:08 PMproject-a already executes tasks, it is too late to reconfigure project-b with the content of what project-a generated.Javi
12/02/2025, 11:50 AMconfigureEach, but to get the provider? or I just need to use provider { } or similarVampire
12/02/2025, 1:30 PMJavi
12/02/2025, 1:49 PMVampire
12/02/2025, 2:40 PMmatching { ... } or named { ... }, you cannot get a single instance provider, because your closures could match between Zero and Infinity instances.Javi
12/02/2025, 2:41 PMprovider {} because there is no way to get a Provider by calling something similar to configureEach but that return a provider with a list of things I can map or something like thatVampire
12/02/2025, 3:06 PMconfigureEach configures things and does not provide a provider.
From the little information you provide it is hard to give substantial advice, but it sounds like you should not do what you try to doJavi
12/02/2025, 3:15 PMmap {} over named{} is not lazy. So I cannot get something lazy to consume it later