Hey guys - just jumped in here hoping to get some ...
# community-support
a
Hey guys - just jumped in here hoping to get some help on a gradle build-time issue that just started happening on an Android app. I've never been too familiar with gradle, I just used what was there... Hopefully some one here can help me out 🙏
It's been building fine for years - we had to update one dependency, and that snowballed into a whole lot of other things breaking that needed updating. We were on gradle 6.4.1. Now I'm on gradle 8.0, but am running into "implicit dependency" warnings.
v
Yeah, well, you always had these problems and at best they made your build potentially flaky, at worst silently produced unreliable or wrong or outdated results maybe without you ever noticing something is not working as expected. In the new version you upgraded to there are just a lot of improvements done that improved on detecting such bad situations, trying to prevent you from being bitten by unreliable, wrong, or flaky builds. Generally, when upgrading Gradle what I suggest is ‱ update to the latest patch version within the same major version ‱ update all plugins to latest version supporting that Gradle version ‱ fix all deprecation messages ‱ update to the latest patch version within the directly following major version, considering release notes and upgrade notes ‱ jump to point 2 and repeat until you reached your target version This usually caters for a smooth update experience as breaking changes are usually only done at a major version boundary, at least intentionally. The errors you get always point to bugs in your build (most often your build scripts, but potentially of course also in some plugin you apply). The recommended solution you get though is imho almost always bulls***. Because any explicit
dependsOn
you make that does not have a lifecycle task on the left-hand side is a code-smell and a sign that you are doing something wrong. Often these messages mean, you are not properly wiring task outputs to task inputs and thereby also implicitly getting the necessary task dependency. Another typical problem is, that you have tasks with overlapping outputs. So for example when you have a
Copy
task that copies a file to
layout.buildDirectory
, then suddenly the whole build directory is considered output of that task which makes up-to-date checks ineffective, task-output cache unusable (resp. storing non-sense), and such detections bail that you use outputs of that task without dependency while you actually use some other tasks output but just get complained because of that overlap which is disouraged bad practice. What it is concretely in your case is hard to guess wihtout any substantial information.
🔝 1
a
@Vampire thank you for that explanation! I will try to backtrack and go back to the last patch of the major version I was on rather than jumping up too much. The challenge I'm (now) learning is that in Android build.gradle files, there aren't any explicitly defined Tasks. It seems to be all Android-related blocks within the
android { ... }
block and so seeing the actual tasks and dependencies is virtually impossible.
v
I'm not really into Android development, but what you said sounds quite unlikely, unless I misunderstood what you tried to say.
Besides that, I highly recommend to use Kotlin DSL instead. By now it is the default DSL, you immediately get type-safe build scripts, actually helpful error messages if you mess up the syntax, and amazingly better IDE support if you use a good IDE like IntelliJ IDEA or Android Studio.
a
Hm its saying 7.5 is the minimum đŸ€”
Yup we're using Android Studio / IntelliJ
Wasn't aware of Kotlin DSL...I'll look into it. thanks
v
Hm its saying 7.5 is the minimum đŸ€”
Who for what?
a
Yea I'm not sure where that is coming from. Maybe the Gradle plugin in android studio?
Heres the basic structure of the gradle file. There's nothing defined explicitly as a "task" in the
android
block. The errors were saying to add an explicit dependency. (I never got it to build with it in there anyway...so I assumed I had the syntax wrong or something). But you're saying that having that explicit dependency is not good?
v
You usually never register own tasks for standard things but apply plugins (preferably using the
plugins { ... }
block, not the legacy way you showed) and the plugins register tasks. That was always like that. And most plugins register extensions like
android { ... }
where you do configuration for the plugin, but can also always configure the tasks the plugins added. And yes, having explicit task dependencies is bad practice unless the left-hand side is a lifecycle task. If you get those warnings about tasks that plugins added, it might well be that those plugins are simply too old and misbehaving for the Gradle version you are using.
a
Thanks @Vampire I got it all working finally yesterday. Dropping back down to gradle 7.5...making a couple other small adjustments, and doubling the RAM of the docker image. Man what a battle that was 😄
v
That does not actually fix the problem though. It just uses a Gradle version that does not detect and report the problem. The problem is still there and at best makes your build flaky, at worst makes it use stale stuff or somehow other sneakily misbehave.
a
Well then I'm not aware of what "the problem" is...
v
What the message told you. Task X has declared inputs that are declared outputs of task Y without a dependency or ordering constraint from X to Y. Which means that if Y happens to run before X, you might be lucky and get the result of Y used in X. But if Y happens to run after X, you might get a non-existent file as input to X when running on a clean worktree, or a stale output of Y used in X on a dirty worktree. And as I said, the most typical causes are either that X does not really use the output of Y, but Y has overlapping outputs with Z and X is actually using the outputs of Z, or X does use the outputs of Y but does not have the outputs of Y wired properly to X but for example just the path to the outputfile configured and thus missing the implicit task dependency that would be there if the outputs were properly wired to the inputs.
Gradle 8 just has some detection and failure when such situations are detected, while Gradle <7 just puts you at risk by not recognizing the situation and thus not complaining, leaving you with flaky or badly behaving builds.