Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradle buildSrc and buildscript

We have a Gradle build that includes a buildSrc with some custom plugins. Those plugins apply yet other plugins. For example, our plugin applies com.android.tools.build:gradle. For annotation processing that library needs to be on Gradle's classpath during compilation. So, putting this in our main build.gradle works:

buildscript {
    repositories {
        google()
    }
    dependencies {
       classpath "com.android.tools.build:gradle:$gToolsVersion"
    }
}

However, that means that for a user to apply this plugin they must (1) apply our plugin and (2) add that buildscript boilerplate. It seems like that shouldn't be necessary. We can also add a project.buildscript block inside our plugin but that too seems unnecessary and, due to this bug is problematic: https://developer.android.com/studio/build/gradle-plugin-3-0-0.html?utm_source=android-studio#known_issues.

I added the com.android.tools.build:gradle dependency to buildSrc/build.gradle as a runtime dependency. It seems like that should work: I thought that tells Gradle that in order to run my plugin that library (and its dependencies) need to be on the classpath. However, gradle buildEnvironment (and the fact that our build fails) makes it clear that's not the case.

So, questions:

  1. What's the difference between a runtime dependency specified in buildSrc/build.gradle and a classpath dependency specified in a buildscript block in a regular build.gradle?
  2. How can I arrange things so that users can apply the plugin from buildSrc and not have to also add the buildscript block to their build.gradle?
like image 651
Oliver Dain Avatar asked Dec 05 '17 00:12

Oliver Dain


People also ask

What is buildSrc in Gradle?

buildSrc is a directory at the Gradle project root, which can contain our build logic. This allows us to use the Kotlin DSL to write our custom build code with very little configuration and share this logic across the whole project.

What is Gradle Buildscript?

Gradle builds a script file for handling two things; one is projects and other is tasks. Every Gradle build represents one or more projects. A project represents a library JAR or a web application or it might represent a ZIP that is assembled from the JARs produced by other projects.

What is the difference between Buildscript and allprojects?

The " buildscript " configuration section is for gradle itself (i.e. changes to how gradle is able to perform the build). So this section will usually include the Android Gradle plugin. The " allprojects " section is for the modules being built by Gradle.

Which are the two types of plugins in Gradle?

There are two general types of plugins in Gradle, binary plugins and script plugins.


2 Answers

Stumbled upon this while digging into a tangential problem.

I've been successfully using buildSrc/build.gradle as the place to define dependencies that would normally belong in the root-project's buildscript classpath for a few of my projects.

You can see a working example here: https://github.com/episode6/chop/blob/develop/buildSrc/build.gradle

I used to use compile dependencie but just switched to runtimeClasspath which feels more appropriate and also works. I don't think your classpath dependencies were working because they would be on the classpath of the buildSrc project, but not compiled into or run along side it.

If you decide to go this route, you may run into the problem I was just digging into which only came up because of this approach.

When I tried this approach with the dokka plugin, I got the following error

Could not resolve all files for configuration ':detachedConfiguration1'.
   > Cannot resolve external dependency org.jetbrains.dokka:dokka-fatjar:0.9.17 because no repositories are defined

I was able to workaround this by adding jcenter() to the root project's buildscript repositories: https://github.com/episode6/chop/blob/develop/build.gradle#L2

like image 109
Geoff Avatar answered Nov 02 '22 18:11

Geoff


I got a slightly different problem and found an acceptable solution that might help with for your second question: I wanted to apply the same repositories in the buildSrc/build.gradle and twice in the root build.gradle.

repositories.gradle in the project root:

repositories {
    if (project.hasProperty('nexus')) {
        maven {
            url 'http://localhost:8081/repository/JCenter/'
        }
        maven {
            url 'http://localhost:8081/repository/Maven_Google/'
        }
    } else {
        jcenter()
        google()
    }
}

ext {
    androidGradleBuildToolsDependency = 'com.android.tools.build:gradle:3.1.3'
}

buildSrc/build.gradle:

buildscript {
    apply from: '../repositories.gradle'
}

allprojects {
    apply from: '../repositories.gradle'
}

dependencies {
    // androidGradleBuildToolsDependency is defined in repositories.gradle
    implementation androidGradleBuildToolsDependency
}

Root build.gradle:

buildscript {
    apply from: 'repositories.gradle'
}

allprojects {
    // this line will also be executed from the build.gradles in subprojects, so the working
    // directory isn't always the same, so we use the absolute path here
    apply from: "${rootProject.projectDir}/repositories.gradle"
}

Note that you do not need the classpath dependency inside the buildscript block of the root build.gradle as you normally would. The implementation dependency in the repositories.gradle seems to auto apply it.

My solution probably doesn't work when the build.gradles are supplied via a dependency.

like image 29
stare.in.the.air Avatar answered Nov 02 '22 18:11

stare.in.the.air