Gradle buildSrc produces unexpected results when implementation as a project

Gradle buildSrc produces unexpected results when implementation
as a project

hi, I use buildSrc to make a gradle plugin to generate some resource files at compile time for the project that uses it.

  1. This Plugin uses some java classes in buildSrc, and I hope that other projects can also access these classes at runtime.
  2. This Plugin uses some resource files in buildSrc.
|-- app
    |-- build.gradle
|--buildSrc
    |--src/main
        |-- java /*My java class is in this dir*/
        |-- groovy /*My plugin is in this dir*/
        |-- resources /*My resources is in this dir*/
|-- custom
    |-- build.gradle

custom/build.gradle
/* Some plugin declarations, DSLs about android that are useless for analysis are omitted.*/
// “my plugin” refers to the gradle plugin I coded

apply plugin: “my plugin”


dependencies {
    implementation project(":buildSrc")
}

buildSrc/build.gradle

apply plugin: "java"

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}

afterEvaluate { project ->
    def canProcessResources = false
    project.tasks.each{
        if (it.name == "compileGroovy"){
            canProcessResources = true
        }
    }
    project.tasks.processResources.enabled = canProcessResources
}

I found out that buildSrc includes the ‘compileGroovy’ task when it is automatically executed. When I use ''implementation project(":buildSrc")", because I declare “apply plugin: “java”” in “buildSrc/build.gradle”, there is no ‘compileGroovy’ task to execute. So I want to according to this phenomenon ti controls the “enabled” of the “processResources” task.

My question is:

When I generated the debug apk package, I observed the result of task execution and found that the processResources task was skipped, but the apk package still contains all the content under buildSrc/src/main/resources.

> Configure project :buildSrc

> Task :buildSrc:compileJava UP-TO-DATE
> Task :buildSrc:compileGroovy UP-TO-DATE
> Task :buildSrc:processResources UP-TO-DATE
> Task :buildSrc:classes UP-TO-DATE
> Task :buildSrc:jar UP-TO-DATE
> Task :buildSrc:assemble UP-TO-DATE
> Task :buildSrc:compileTestJava NO-SOURCE
> Task :buildSrc:compileTestGroovy NO-SOURCE
> Task :buildSrc:processTestResources NO-SOURCE
> Task :buildSrc:testClasses UP-TO-DATE
> Task :buildSrc:test NO-SOURCE
> Task :buildSrc:check UP-TO-DATE
> Task :buildSrc:build UP-TO-DATE

> Configure project :app

> Configure project :buildSrc

> Configure project :uicommon

> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :custom:preBuild UP-TO-DATE
> Task :custom:preDebugBuild UP-TO-DATE
> Task :custom:compileDebugAidl NO-SOURCE
> Task :app:compileDebugAidl NO-SOURCE
> Task :custom:packageDebugRenderscript NO-SOURCE
> Task :app:compileDebugRenderscript NO-SOURCE
> Task :app:checkDebugManifest
> Task :app:generateDebugBuildConfig
> Task :app:mainApkListPersistenceDebug
> Task :app:generateDebugResValues
> Task :app:generateDebugResources
> Task :custom:compileDebugRenderscript NO-SOURCE
> Task :custom:generateDebugResValues
> Task :custom:generateDebugResources
> Task :custom:packageDebugResources
> Task :app:createDebugCompatibleScreenManifests
> Task :custom:checkDebugManifest
> Task :buildSrc:compileJava UP-TO-DATE
> Task :buildSrc:processResources SKIPPED
> Task :buildSrc:classes UP-TO-DATE
> Task :buildSrc:jar
> Task :custom:generateDebugBuildConfig
> Task :app:mergeDebugShaders
> Task :app:compileDebugShaders
> Task :app:generateDebugAssets
> Task :custom:mergeDebugShaders
> Task :custom:compileDebugShaders
> Task :custom:generateDebugAssets
> Task :custom:packageDebugAssets
> Task :app:mergeDebugAssets
> Task :app:processDebugJavaRes NO-SOURCE
> Task :custom:processDebugJavaRes NO-SOURCE
> Task :app:checkDebugDuplicateClasses
> Task :app:desugarDebugFileDependencies
> Task :custom:parseDebugLibraryResources
> Task :app:validateSigningDebug
> Task :app:signingConfigWriterDebug
> Task :app:mergeDebugJniLibFolders
> Task :custom:mergeDebugJniLibFolders
> Task :custom:processDebugManifest
> Task :app:processDebugManifest
> Task :app:mergeDebugResources
> Task :custom:mergeDebugNativeLibs
> Task :custom:stripDebugDebugSymbols
> Task :custom:transformNativeLibsWithIntermediateJniLibsForDebug
> Task :custom:generateDebugRFile
> Task :app:processDebugResources
> Task :custom:compileDebugKotlin
> Task :app:mergeExtDexDebug
> Task :custom:javaPreCompileDebug
> Task :custom:compileDebugJavaWithJavac
> Task :custom:bundleLibResDebug
> Task :custom:bundleLibRuntimeDebug
> Task :custom:bundleLibCompileDebug
> Task :app:compileDebugKotlin
> Task :app:mergeDebugNativeLibs
> Task :app:stripDebugDebugSymbols
> Task :app:mergeLibDexDebug
> Task :app:javaPreCompileDebug
> Task :app:compileDebugJavaWithJavac
> Task :app:compileDebugSources
> Task :app:transformClassesWithDexBuilderForDebug
> Task :app:mergeProjectDexDebug
> Task :app:mergeDebugJavaResource
> Task :app:packageDebug
> Task :app:assembleDebug

myResourses is a file under buildSrc/src/main/resources which should not be included in the apk because of “processResources skipped”.

Additional note: I’ve seen some answers saying that using “implementation project(”:buildSrc")" in a custom project will throw an error. But in my practice, after using “apply plugin: “java”” in buildSrc/build.gradle, it works and accesses the java class at runtime, it’s just that the resources file doesn’t behave correctly.

I don’t want to put the files in buildSrc/src/main/resources into the apk package, which may introduce extra security issues.

My gradle version is 5.6.4

Just don’t do what you try to do there, but do it the proper way please.
What you try to do is wrong in so many aspects and it also will not work in future Gradle versions which is what those “some answers” were referring to, as in recent Gradle versions include("buildSrc") is illegal as buildSrc is a reserved name.

Besides that, buildSrc is a “standalone” own multi-project build, so as with any other project that is part of a build, you should never include it in another build which is what you actually are doing. If you need a project of another build, includeBuild that build, creating a composite build and declare a normal dependency using the coordinates. With buildSrc this is not possible though, as it is a super-special case, but you can easily replace buildSrc by a composite build by renaming it and then do an includeBuild, then you can also properly depend on it if you really need to.

You then also don’t need dirty afterEvaluate tricks to disable some tasks or similar.

Also, disabling the processResources task is little helpful as the task already run before and by disabling the task, you just disable that it runs, but that does not mean that its - probably stale - output files are not used by tasks needing them.

You also should never iterate a task collection by each, as that will totally destroy task configuration avoidance as you force eager realization of each and every task.

And actually almost everytime you use afterEvaluate you just do symptom treatment and at the same time introduce race conditions. Most usages of afterEvaluate are inappropriate.

Oh and btw., applying plugins using apply is legacy and not recommended, you should use a plugins block instead. :slight_smile:

Thanks for your help.

I didn’t realize I was doing so many wrong things.
In fact, I’m a gradle noob.

I didn’t even know gradle could do something like this until you mentioned using composite build. I’ll try to use composite build for my purposes, I’d appreciate you pointing me in the right direction. Then, instead of using tricks cobbled together from Google, I thought I should read the gradle documentation in its entirety.

You said never iterate a task collection by each, so if I want to get a task in afterEvaluate, could I use TaskCollection.named(java.lang.String)?

I didn’t realize I was doing so many wrong things.
In fact, I’m a gradle noob.

Don’t worry, we all started at some point. :slight_smile:

I’ll try to use composite build for my purposes, I’d appreciate you pointing me in the right direction.

https://docs.gradle.org/current/userguide/composite_builds.html

Then, instead of using tricks cobbled together from Google, I thought I should read the gradle documentation in its entirety.

Sure, you can do that, and you will probably learn a lot about Gradle. :slight_smile:
It’s quite some text to read though by now.
Cobbling together tricks from Google or StackOverflow is not bad generally, but well, you also find many bad advice in the internet of course. :smiley:
Especially as Gradle is still rapidly developing in some parts, so some tricks that were perfectly fine a year ago can already be legacy and bad practice today.
The usual problem with snippets copied from people.

You said never iterate a task collection by each , so if I want to get a task in afterEvaluate , could I use TaskCollection.named(java.lang.String)?

If you are sure it is there, named is fine.
But actually everytime you use afterEvaluate you are usually just do symptom treatment and just introduce further race conditions, as you will for example miss all things happening in afterEvaluate blocks executed after your afterEvaluate block.
Which is one of the main reasons the lazy apis were introduced (Property, Provider, …).
Using afterEvaluate is most often like using SwingUtilities.invokeLater to “fix” a problem in the GUI.
It will temporarily work-around the problem but just make the real problem hit later and be much harder to diagnose. :smiley:
Do if you can better try to avoid ever using afterEvaluate.
In most situations there is a better option.