Gradle: What Is The Default Configuration and How Do I Change It - gradle

When I run the "dependencies" task there are several sections: compile, runtime, testCompile ...
One of those sections is "default - Configuration for default artifacts." What is this section and what is it used for?
How do I change what is in the "default configuration"?
Details: Gradle 1.7

Unless your build is publishing Ivy modules, the default configuration is mainly relevant when dealing with project dependencies in a multi-project build. Given a multi-project build with projects A and B, if A declares a project dependency on B without explicitly naming a configuration (e.g. dependencies { compile project(":B") }, A (more precisely A's compile configuration) will depend on project B's default configuration. In other words, dependencies { compile project(":B") } is a shortcut for dependencies { compile project(path: ":B", configuration: "default") }.
The default configuration extends from the runtime configuration, which means that it contains all the dependencies and artifacts of the runtime configuration, and potentially more. You can add dependencies and artifacts in the usual way (using a dependencies/artifacts block in B's build script). Alternatively, B could declare a custom configuration, and A could depend on that by explicitly naming that configuration (e.g. dependencies { compile project(path: ":B", configuration: "myCustomConfig") }.

When using the gradle java plugin the 'default' configuration extendsFrom 'runtime', 'runtimeOnly', 'implementation'
If you do not use the java plugin then you can define it yourself like this
configurations {
"default"
}
The java plugin sets up the default configuration here: https://github.com/gradle/gradle/blob/85d30969f4672bb2739550b4de784910a6810b7a/subprojects/plugins/src/main/java/org/gradle/api/plugins/JavaPlugin.java#L437
The documentation is not that good in this area.
An example of "serving" a default artifact from a composite build.
The example creates a subproject that refers to a dependency in another project. This can be nessesary when working with composite builds, as only the "default" group can be depended upon.
We use this to take many jars from a single project and serve it as different dependencies when referencing the project as a composite build.
apply plugin: 'base'
configurations {
depend
}
dependencies {
depend project(path: ':', configuration: 'ConfWithArtifact')
}
artifacts {
"default" (file: configurations.depend.singleFile) {
builtBy(configurations.depend)
}
}

The default configuration is actually created by the base plugin, and so you don't need to define it yourself.
I've also had the problem with composite builds only compositing from the default configuration, but I solved it slightly differently:
plugins {
id 'base'
}
configurations {
bootstrap
it.'default'.extendsFrom bootstrap
}
dependencies {
bootstrap project(path: ':other', configuration: 'otherConfiguration')
}
This approach allows the artifact from the :other project to keep its transitive dependencies, assuming you're interested in keeping them.

Related

Which dependencies are added to a Gradle project which uses a 'project lib dependency' and is this configurable?

Gradle project lib dependencies are a means of defining a project as requiring, as one of its dependencies, the output from another project.
The documentation states:
A “lib” dependency is a special form of an execution dependency. It
causes the other project to be built first and adds the jar with the
classes of the other project to the classpath. It also adds the
dependencies of the other project to the classpath.
However, which dependencies of the project are added? Is it the compile, implementation or runtime dependencies, for instance? Is this configurable? i.e. how would I configure a project to require the output of another project and the dependencies from an arbitrary configuration of that other project?
For instance, in my root project, I can define project1 to depend on project2:
project(":project1") {
dependencies {
implementation project(':project2')
}
}
How do I add the dependencies of an arbitrary configuration of :project2 (let's say it's called myConfiguration) to project1?
The answer is contained within the DSL documentation for Dependencyhandler.
By default, when you declare dependency to projectA, you actually
declare dependency to the 'default' configuration of the projectA. If
you need to depend on a specific configuration of projectA, use map
notation for projects:
configurationName project(path: ':projectA', configuration: 'someOtherConfiguration')

Difference between depends and dependencies in gradle

What's the difference between depends keyword and dependencies keywords in a gradle build file? I encountered these keywords in the following contexts:
depends:
project(':tools:bnd-module-plugin') {
description = "bnd plugin to build moduleinfo with ${rootProject.description}"
sourceSets.main.java.srcDirs += project(':asm').sourceSets.main.java.srcDirs
depends = ['biz.aQute.bnd:biz.aQute.bnd:3.4.0']
}
dependencies:
subprojects {
apply plugin: 'com.github.sherter.google-java-format'
googleJavaFormat.toolVersion = '1.4'
compileTestJava {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
dependencies {
requires.each { projectName -> compile project(projectName) }
depends.each { artifactName -> compile artifactName }
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.1.0',
'org.junit.jupiter:junit-jupiter-params:5.1.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.1.0'
testCompile project(':asm-test')
}
}
The dependencies keyword is provided by a method of the Project instance, which the build.gradle file is evaluated against. It allows the configuration of multiple types of dependencies via a DependencyHandler. You can add file dependencies, project dependencies and module dependencies, which can be resolved from Maven and Ivy repositories.
Since it is provided by the Project instance directly, it is available in every Gradle project.
The depends keyword does not exist in the Gradle API. However, Gradle provides a lot of possibilities to extend and program your build scripts. Via so-called extra properties it is possible to define additional properties in the scope of Gradle objects, like tasks and projects. Then these additional properties can be used like regular Gradle properties as in your example.
I found the full build script from your examples online. In the beginning of the script a subprojects closure is used to define extra properties for all subprojects:
subprojects {
[...]
ext.provides = [] // The provided java packages, e.g. ['org.objectweb.asm']
ext.requires = [] // The required Gradle projects, e.g. [':asm-test']
ext.depends = [] // The external dependencies, e.g. ['junit:junit:4.12']
[...]
}
provides, required and depends are Groovy lists, which are then later used to store strings.
Your first code example sets a new list to the depends extra property of the :tools:bnd-module-plugin subproject.
Your second uses these lists to add module (depends) or project (requires) dependencies to all subprojects.
As you can see, depends is just part of a custom Gradle script and not part of the official Gradle API, unlike dependencies.

gradle how configurations is used

Example in the gradle war plugin: why need to define moreLibs like the following? please explain:
configurations {
moreLibs
}
dependencies {
moreLibs ":otherLib:1.0"
}
war {
classpath configurations.moreLibs
webXml = file('src/someWeb.xml')
}
Can we define anything inside configurations?
configurations {
foobar
}
I have seen these in many places. Can anyone explain?
Yes, you can write anything in the configurations block and it will create a new configuration with that name and you can also further configure it, e. g. by setting its transitive property to false and other stuff.
A custom configuration is just a name for which you can define dependencies that are then resolved transitively by Gradle automatically and can be used for various purposes where you need those resolved files.
In your example you define a moreLibs configuration, add a dependency to it that will be resolved transitively by Gradle and then added to the wars lib directory.
You don't have to do this if you don't have a need to. All libs in the runtime configuration (and thus also those in the compile configuration) are automatically added to the wars lib directory. But if you for some reason need additional libs in there that you don't want to add to compile or runtime, you can do it this way.
Another example of where a custom configuration can be useful is if you want to use a custom Ant task. You define a custom configuration, add the Ant tasks dependency to it, then you let Gradle transitively resolve it and can add the whole fileset as classpath to the taskdef for Ant.

Add dependencies via transitive dependencies of another configuration in Gradle

I would like Gradle to compute the dependencies for a configuration by adding dependencies from dependencies loaded via a second configuration.
Example with two Gradle projects:
dependency/build.gradle:
configurations {
other
}
dependencies {
other "bar:artifact1:0.4"
}
top/build.gradle:
configurations {
other
modules
}
dependencies {
modules "foo:dependency:1.0"
other "bar:artifact2:0.1"
}
So the top project depends on dependency via the modules configuration, but I want the other configuration in top to contain both "bar:artifact1:0.4" and "bar:artifact2:0.1".
In my concrete case, the other dependencies are listed in an Ivy file for each artifact. I want to collect the other dependencies of all the artifacts a project depends on.
This is not a multi-project build, but other projects' artifacts are loaded from a remote repository.
Is there a way to configure Gradle to include the configurations of all transitive dependencies?

Gradle multiproject gives "Could not find property 'sourceSets' on project" error

I had quite good gradle configuration, that built everything just fine. But one of the projects of my multi-project build derived from the rest of them so much, that I would gladly move it to another git repo and configure submodules to handle it.
First, I moved Project and its resources to subfolder Libraries/MovedProject. After altering some lines in gradle configurations it worked fine. But then I decided to write a new build.gradle just for this project, and move all configurations there from the main one.
And this is where everything stopped working. When I try to call any task it always ends
with Could not find property 'sourceSets' on project ':Libraries/MovedProject'. Line which is responsible for it is:
dependencies {
...
if (noEclipseTask) {
testCompile project(':Libraries/MovedLibrary').sourceSets.test.output
}
}
which I use for running tests in which I use classes from other projects. If I remove that line, the build fails only when it reaches compileTestJava task of projects that make use of MovedProject. If I remove that line and call gradle :Libraries/MovedLibrary:properties I can see :
...
sourceCompatibility: 1.7
sourceSets: [source set main, source set test]
standardOutputCapture: org.gradle.logging.internal.DefaultLoggingManager#1e263938
...
while gradle :Libraries/MovedLibrary:build builds correctly.
Currently I've got everything set up as following:
directories:
/SomeMainProject1
/SomeMainProject2
/SomeMainProject3
/Libraries
/MovedProject
build.gradle
dependencies.gradle
project.gradle
tasks.gradle
/Builder
dependencies.gradle
project.gradle
tasks.gradle
build.gradle
settings.gradle
settings.gradle
include Libraries/MovedProject,
SomeMainProject1,
SomeMainProject2,
SomeMainProject3
sourceSets for MovedProject are defined in Libraries/MovedProject/project.gradle:
sourceSets {
main {
java {
srcDir 'src'
srcDir 'resources'
}
resources { srcDir 'resources' }
}
test { java {
srcDir 'test/unit'
} }
}
dependencies that makes use of sourceSets.test.output are stored in Builder/dependancies.gradle, and set for each project that needs MovedProject to run tests:
project(':SomeMainProject1') {
dependencies {
...
if (noEclipseTask) {
testCompile project(':Libraries/net.jsdpu').sourceSets.test.output
}
}
}
What would be the easiest way to get rid of that error and make gradle build projects with current directory structure? I would like to understand why gradle cannot see that property.
The line in question is problematic because it makes the assumption that project :Libraries/MovedLibrary is evaluated (not executed) before the current project, which may not be the case. And if it's not, the source sets of the other project will not have been configured yet. (There won't even be a sourceSets property because the java-base plugin hasn't been applied yet.)
In general, it's best not to reach out into project models of other projects, especially if they aren't children of the current project. In the case of project A using project B's test code, the recommended solution is to have project B expose a test Jar (via an artifacts {} block) that is then consumed by project A.
If you want to keep things as they are, you may be able to work around the problem by using gradle.projectsEvaluated {} or project.evaluationDependsOn(). See the Gradle Build Language Reference for more information.
I had a similar error happen to me in a multimodule project, but for me the cause was as simple as I had forgotten to apply the java-library plugin within the configurations, I only had maven-publish plugin in use.
Once I added the plugin, sourceSets was found normally:
configure(subprojects) {
apply plugin: 'maven-publish'
apply plugin: 'java-library'
....

Resources