Copy task implicit dependency

My Android project fails to build after updating Gradle to 9.6.0.

A problem was found with the configuration of task ‘:processReleaseJavaRes’ (type ‘ProcessJavaResTask’).
Property has implicit dependency
Gradle detected a problem with the following location: ‘C:\0\a8\recoil\git\android\build\generated\resources’
Task ‘:processReleaseJavaRes’ uses this output of task ‘:copyJavaResources’ without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed
For more information, please refer to 
 in the Gradle documentation.
Possible solutions:
1. Declare task ‘:copyJavaResources’ as an input of ‘:processReleaseJavaRes’.
2. Declare an explicit dependency on ‘:copyJavaResources’ from ‘:processReleaseJavaRes’ using Task#dependsOn.
3. Declare an explicit dependency on ‘:copyJavaResources’ from ‘:processReleaseJavaRes’ using Task#mustRunAfter.

The relevent part of build.gradle:

final FUT_RESOURCES = [ ‘altirrantsc.pal’, ‘altirrapal.pal’, ‘atari8.fnt’, ‘c16.pal’, ‘c64.fnt’, ‘zx81.fnt’ ]
final JAVA_RESOURCES_DIR = file ‘build/generated/resources’
tasks.register(‘copyJavaResources’, Copy) {
    from ‘..’
    into new File(JAVA_RESOURCES_DIR, ‘net/sf/recoil’)
    include FUT_RESOURCES
}
preBuild.dependsOn generateIcon, generateRoundIcon, copyJavaResources

How to fix this?

There are quite some problems in that snippet.

For example you use new File(...) with a relative path which is almost never what you want in no JVM application whatsoever, as it resolves paths relative to the user working directory.
In Gradle builds that often is the root project directory, but this is not guaranteed and not always the case.

The actual error you get says, that the task copyJavaResources has build/generated/resources as output and processReleaseJavaRes uses those files as input but without any dependency or ordering constraint between those tasks.

The suggested solutions are actually usually not what you want to do, but are only symptom treatment.
In almost all cases it means that you either have overlapping outputs of tasks (for example having multiple tasks that have build/generated/resources as output directory), which is a big build bug and should never happen, or that you manually configured paths to use instead of properly wiring task outputs to task inputs.

How to fix it in your build is hard to say with only that small snippet.
But usually, each task should have unique outputs that do not overlap and tasks that generate sources or resource are registered as source directory for the respective source directory set, so that every consumer of those files automatically get those files and also automatically get the necessary task dependencies without needing to configure it manually.

Practically any explicit dependsOn that does not have lifecycle task on the left-hand side is a code-smell and usually a sign of task outputs not being wired to task inputs properly.

But how to do it properly in an Android build no idea, because Android builds are always a bit “special” and I don’t do Android.

Thank you for a quick response!

This is the complete script:

The project is cross-platform and the Copy task copies Git-versioned binary files to be embedded in the APK and used with Foo.class.getResourceAsStream().

If the files are versioned, why do you need to copy them anywhere at all?
Just check them in at the correct place and you are done, no need to waste time with copying something somewhere.
And if you do need, then as I said, do not configure literal paths, but register the actual task as srcDir of the source directory set like sourcesSet.main.resources or however you do it in an Android build.

The important part is that in addition to Android (built by Gradle), my project works natively on Windows, macOS, Linux and in web browsers.
I don’t like the idea of checking into Git copies in the Android subdirectory, hence the copy.
The TOTAL size of these six files is four kilobytes and I have a 2 TB NVMe disk. :slight_smile:

register the actual task as srcDir of the source directory set like sourcesSet.main.resources or however you do it in an Android build

Wouldn’t that put the whole directory in the APK? I only need these six files.

Ok, this works:

android {
    sourceSets {
        main {
            resources {
                srcDir '..'
                include FUT_RESOURCES
            }
        }
    }
}

If ‘..' is no good, what should I use instead?

Edit:

I posted too fast - it doesn’t work. This packages the files into the root directory of APK. They need to be in a specific directory in APK to work.

Please explain how to copy files.

Ah, well, if you need them in multiple places then not, yeah.
But still, then have a separate fully-owned output directory for your copy task (which should usually be a sync task) and declare the task as source directory.

Something like

val prepareJavaResources = tasks.register<Sync>("prepareJavaResources") {
    from("..")
    into(layout.buildDirectory.dir("java-resources"))
    include(...)
}
android {
    sourceSets {
        main {
            resources {
                srcDir(prepareJavaResources)
            }
        }
    }
}