This link -> ArtifactResolutionQuery discusses the ’ ArtifactResolutionQuery’. This link is resolving dependencies in the context of java, but I am trying to do the equivalent dependency resolution for a native builds using cpp-library plugin. I am able to get the name:group:version of a dependency using other means, but I need more information about the dependency such the absolute file path to a dependency where it resides in another project, or in gradle cache dir. So, in the spirit of the link above, and trying to get more details about my dependencies, I have the following DSL.
task resolveCompileSources {
doLast {
//configuration.'api'
def componentIds = configurations.api.incoming.resolutionResult.allDependencies.collect { it.selected.id }
def result = dependencies.createArtifactResolutionQuery()
.forComponents(componentIds)
.withArtifacts(CppComponent)
.execute()
for (component in result.resolvedComponents) {
component.getArtifacts(SourcesArtifact).each { println "Source artifact for ${component.id}: ${it.file}" }
}
}
}
Apparently, this may work for java configuration, but apparently not in my native ‘api’ config, because I get the following error message:
* What went wrong:
Execution failed for task ':utilities:resolveCompileSources'.
> Resolving configuration 'api' directly is not allowed
Is there a way I can get file level details for my native dependencies? I’ve seem to have exhausted all ends.
Can we get a comment from the native team on this please. How to get the path in cache for a native api/implementation dependency? How to do it AFTER the dependency has been resolved?
Thanks for this answer, the obvious caveat I can see is the api configuration is both not consumable and not resolvable. It’s like a lifecycle configuration. It’s there as a placeholder to declare dependencies. What you want instead is use one of the more specific dependencies such as cppCompile*, nativeLink*, and nativeRuntime*. Would it be possible to provide a sample of what you are trying to achieve? It seems you are using one of the gradle/native-sample and it would be helpful to have a complete sample to work with.
However, in this build sample, we have an ‘implementation’ configuration where we have applied the ‘cpp-application’, instead of an ‘api’ configuration applying ‘cpp-library’. It to gives a similar error.
FAILURE: Build failed with an exception.
* What went wrong:
Could not determine the dependencies of task ':iterateResolvedArtifacts'.
> Resolving configuration 'implementation' directly is not allowed
Here is the build.gradle in it entirety (with the new task) for native-samples/cpp/binary-dependencies
Given your explanation, this tells me that the implementation configuration like the ‘api’ configuration is just a placeholder, and it isn’t consumable and nor resolvable. This is difficult to understand because this leads me to ask you how does gradle consume and resolve it internally? Because somehow, the dependency has to resolve to some file for successful compilation I would imagine. Also, it sound like you are saying we need to declare the dependency differently, i.e., as “cppCompile*”, “nativeLink*”, or “nativeRuntime*”? But if so, how is that done? I don’t see any samples using such a declaration. Ultimately, the motivation behind this post as I expressed in the slack channel is to solve the messy headers issue.
@Daniel_L This was an attempt to work around the “Messy Headers” issue reported here 869. The issue comments has some additional information on what we are trying to do. In short, we want to add subdirectories of the resolved cppHeaders dependency to the compile task’s include directories list.
For e.g. for a resolved headers dependency for say, boost library, gradle adds this path among the list of include directories -
Let’s go through some of the basic of the Gradle’s dependency engine. Each configuration declared can be either consumable, resolvable, or neither. For each project, you can list the dependency configuration with ./gradlew dependencies and you would get something like:
> Task :dependencies
------------------------------------------------------------
Root project
------------------------------------------------------------
api (n)
No dependencies
cppApiElements (n)
No dependencies
cppCompileDebug
\--- project :foo
cppCompileRelease
\--- project :foo
debugLinkElements (n)
No dependencies
debugRuntimeElements (n)
No dependencies
implementation (n)
\--- project foo (n)
mainDebugImplementation (n)
No dependencies
mainReleaseImplementation (n)
No dependencies
nativeLinkDebug
\--- project :foo
nativeLinkRelease
\--- project :foo
nativeRuntimeDebug
\--- project :foo
nativeRuntimeRelease
\--- project :foo
releaseLinkElements (n)
No dependencies
releaseRuntimeElements (n)
No dependencies
The configuration ending with Elements are by convention consumable. This is where you declared the artifact to be exported out of the project. The other ones nativeLink*, nativeRuntime*, and cppCompile* are the configuration that you can resolve for each of the compilation stages. This is what Gradle resolve when it’s building. The *implementation* and api are the configurations that act as lifecycles. All the other configurations extend from those lifecycles so any dependencies added to the lifecycle are being also added the other configuration as they are extending it. The selection of the artifact is done through the attributes.
In this case, what is required is iterating over the right cppCompile* configuration. This will gives only the include paths.
Depending on how this issue is planned to be solved, there may be an alternative as it’s not recommended to reference configuration by name since those changes depending on which dimension participate to the variant building (e.g. build type, operating system, architecture).