bazelbuild / rules_kotlin

Bazel rules for Kotlin

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Android rules not working properly with exported Java plugins

Kernald opened this issue · comments

Following Dagger's recommended Hilt integration, when using this android_library target with the following Java class, the code generation runs fine:

android_library(
    name = "app",
    srcs = ["SampleApplication.java"],
    manifest = "AndroidManifest.xml",
    deps = [
        ":res",
        "//third_party/dagger/hilt:hilt-android",
    ],
)
package fr.enoent.android.sample;

import android.app.Application;
import dagger.hilt.android.HiltAndroidApp;

@HiltAndroidApp(Application.class)
public class SampleApplication extends Sample_BurgApplication {
}

The exact same set-up with a kt_android_library, however, doesn't end up calling the plugins exported by //third_party/dagger/hilt:hilt-android at all. Even when only passing the same Java file to kt_android_library - the compilation fails because the generated superclass isn't generated.

From there, I tried passing the plugins explicitly to the kt_android_library's plugins attribute. With a Java file, they don't seem to run at all either (maybe expected?). With a Kotlin file, some seem to run, but either not all or not in the correct order, I'm really not familiar enough with annotation processors to understand what's going on there - one of the Hilt plugins fails because the superclass hasn't been generated.

I'm not sure how much of that is working as intended, but it's a strong behavioural difference from the native android_library (and I believe kt_jvm_library as well?).

Btw, I noticed, if kt_android_library has //:dagger dependency all corresponding _Factorys are generated. dagger target is java_library, while //:hilt-android is android_library.

It seems one can lose android_library.exported_plugins in:

elif ctx.rule.kind == "java_library":

So, I changed the line to:

elif ctx.rule.kind in ["java_library", "android_library"]:

Now I started to get compilation errors from Hilt:

error: [Hilt]
public final class MyApplication {
             ^
  @HiltAndroidApp class expected to extend Hilt_MyApplication. Found: Object

But with no luck to resolve them yet. Looks like code generation still not working.

I've come upon the same issue when using dagger_android_rules. These also wrap a java_plugin in android_library, but unlike with Hilt there is only one processor class.

As @geaden wrote plugins.bzl quite clearly doesn't handle android_library rules. I was able to reproduce the issue here and make the tests pass again with the proposed fix. Not sure why Hilt is still failing, it might be a separate issue.

Here is a demo app to demonstrate that hilt annotation processors are not running.

@Kernald,

Btw, I noticed that you extended Sample_BurgApplication. Shouldn't it be Hilt_SampleApplication? Does the fix resolve the issue in your case?

@geaden Sorry I edited the code I posted to keep things at their simplest and made a typo there - the code in my initial comment is indeed incorrect, but what I have locally is correct. I'll give that fix a try asap.

@geaden I tried this fix and get a similar error as above about the app class extending Object. I'm not really sure what's running or not, or if Hilt is running on the wrong jar maybe...

@Kernald Thanks a lot for letting know! I thought I had wrong Hilt setup. I keep digging into the issue, but unsuccessfully so far.

This is a long-standing issue, it seems, related to how the rules collect plugin info - we special case java_library, and don't special case android_library. This is wrong, but it's been wrong for years. We should (and will) roll a fix, but it pre-exists, and we won't block 1.5 for it.

That said, it's awful and we should roll a fix. I'll try to get it in before release, but no promises. However, it should be in 1.6, now that we understand it.

Btw, with the latest rules_kotlin, Kotlin 1.5.21 and fix from #351 I'm getting:

error: wrong plugin option format: null, should be plugin:<pluginId>:<optionName>=<value>

Updated demo-app

Sorry, do we have any progress here?

Bumping up this thread again to see if there is any proper way to solve the issue.

TLDR; Hilt's library annotation processing doesn't work on kt_android_library's Kotlin files.

Are you still able to reproduce this on a newer version of Bazel where the JavaPluginInfo provider exists? When rules_kotlin has access to this new provider, it doesn't apply the kt_jvm_plugin_aspect and collects the JavaPluginInfo directly.

Haven't made a separate demo app, but I'm seeing this as well. However, it seems like the kt_android_library rule builds but the android_binary depending on that rule now has the issue.

Bazel version:

❯ bazel --version
bazel 6.0.0-pre.20220608.2

kt_android_library:

❯ bazel build //android/app/src/com/highgravitydays/android:highgravity
DEBUG: /private/var/tmp/_bazel_vple/f3403029ac4265720a1f6e63b005c1fd/external/io_bazel_rules_kotlin/kotlin/kotlin.bzl:104:10: kt_jvm_library should be loaded from //kotlin:jvm.bzl
INFO: Analyzed target //android/app/src/com/highgravitydays/android:highgravity (76 packages loaded, 1488 targets configured).
INFO: Found 1 target...
INFO: From Merging manifest for //android/app/src/com/highgravitydays/android:highgravity_base:
Warning: /private/var/tmp/_bazel_vple/f3403029ac4265720a1f6e63b005c1fd/sandbox/darwin-sandbox/784/execroot/__main__/android/app/src/com/highgravitydays/android/AndroidManifest.xml:32:9-35:35 Warning:
	provider#androidx.startup.InitializationProvider was tagged at AndroidManifest.xml:32 to remove other declarations but no other declaration present
INFO: From Merging compiled Android resources for //android/app/src/com/highgravitydays/android:highgravity_base:
Warning: /private/var/tmp/_bazel_vple/f3403029ac4265720a1f6e63b005c1fd/sandbox/darwin-sandbox/1024/execroot/__main__/bazel-out/darwin_arm64-fastbuild/bin/android/app/src/com/highgravitydays/android/_renamed/highgravity_base/AndroidManifest.xml:37:9-40:35 Warning:
	provider#androidx.startup.InitializationProvider was tagged at AndroidManifest.xml:37 to remove other declarations but no other declaration present
Target //android/app/src/com/highgravitydays/android:highgravity up-to-date:
  bazel-bin/android/app/src/com/highgravitydays/android/libhighgravity.jar
INFO: Elapsed time: 28.413s, Critical Path: 8.58s
INFO: 455 processes: 13 internal, 440 darwin-sandbox, 2 worker.
INFO: Build completed successfully, 455 total actions

android_binary:

❯ bazel build //android/app:app
INFO: Build option --fat_apk_cpu has changed, discarding analysis cache.
DEBUG: /private/var/tmp/_bazel_vple/f3403029ac4265720a1f6e63b005c1fd/external/io_bazel_rules_kotlin/kotlin/kotlin.bzl:104:10: kt_jvm_library should be loaded from //kotlin:jvm.bzl
INFO: Analyzed target //android/app:app (81 packages loaded, 1839 targets configured).
INFO: Found 1 target...
ERROR: /Users/vple/climb/android/app/src/com/highgravitydays/android/BUILD.bazel:5:19: KotlinKapt //android/app/src/com/highgravitydays/android:highgravity_kt { kt: 31, java: 0, srcjars: 0 } for armeabi-v7a failed: (Exit 1): build failed: error executing command (from target //android/app/src/com/highgravitydays/android:highgravity_kt) bazel-out/darwin_arm64-opt-exec-2B5CBBC6/bin/external/io_bazel_rules_kotlin/src/main/kotlin/build ... (remaining 1 argument skipped)
error: /var/folders/tc/qpt243215ss5h5x4qf_xl86w0000gn/T/pwd10869448029639228200/_kotlinc/android_app_src_com_highgravitydays_android-highgravity_kt_jvm/temp/stubs/com/highgravitydays/android/HighGravityApplication.java:7: error: [Hilt]
public final class HighGravityApplication {
             ^
  @HiltAndroidApp class expected to extend Hilt_HighGravityApplication. Found: Object
  [Hilt] Processing did not complete. See error above for details.
android/app/src/com/highgravitydays/android/HighGravityApplication.kt:7:32: error: unresolved reference: Hilt_HighGravityApplication
class HighGravityApplication : Hilt_HighGravityApplication() {
                               ^
Sep 29, 2022 11:06:50 PM worker request 0
SEVERE: Compilation failure: compile phase failed:Target //android/app:app failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 11.936s, Critical Path: 9.45s
INFO: 38 processes: 11 internal, 27 darwin-sandbox.
FAILED: Build did NOT complete successfully

The android_binary has the kt_android_rule as its only dep:

android_binary(
    name = "app",
    srcs = [],
    custom_package = "com.highgravitydays.android",
    dex_shards = 2,
    manifest = "//android/app/src/com/highgravitydays/android:AndroidManifest.xml",
    manifest_values = {
        "versionCode": "1",
        "minSdkVersion": "24",
        "targetSdkVersion": "31",
    },
    multidex = "native",
    deps = ["//android/app/src/com/highgravitydays/android:highgravity"],
)

Okay, I forked @geaden's demo and attempted to update all the build config to match my project. MyActivity and MyApplication were updated to extend the corresponding Hilt_* classes, otherwise I left the app as is. Hopefully I didn't miss something.

https://github.com/vple/bazel_hilt_demo

Building the kt_android_library and android_binary targets seems to have a similar result to my above post--the kt_android_library builds but the android_binary does not.

❯ bazel clean
INFO: Starting clean.
INFO: Multiplexer process for Javac has closed its output stream
❯ bazel build //kotlin/com/example/app:examplelib
INFO: Analyzed target //kotlin/com/example/app:examplelib (69 packages loaded, 1219 targets configured).
INFO: Found 1 target...
Target //kotlin/com/example/app:examplelib up-to-date:
  bazel-bin/kotlin/com/example/app/libexamplelib.jar
INFO: Elapsed time: 9.347s, Critical Path: 4.35s
INFO: 165 processes: 10 internal, 153 darwin-sandbox, 2 worker.
INFO: Build completed successfully, 165 total actions
❯ bazel build //:exampleapp
INFO: Analyzed target //:exampleapp (5 packages loaded, 449 targets configured).
INFO: Found 1 target...
INFO: From Dexing external/maven/_dx/androidx_viewpager_viewpager/classes_and_libs_merged.jar_desugared.jar with applicable dexopts []:
Info: Stripped invalid locals information from 1 method.
Info in bazel-out/android-armeabi-v7a-fastbuild/bin/external/maven/_dx/androidx_viewpager_viewpager/classes_and_libs_merged.jar_desugared.jar:androidx/viewpager/widget/PagerTitleStrip.class:
Methods with invalid locals information:
  void androidx.viewpager.widget.PagerTitleStrip.updateTextPositions(int, float, boolean)
  Information in locals-table is invalid with respect to the stack map table. Local refers to non-present stack map type for register: 37 with constraint INT.
Info: Some warnings are typically a sign of using an outdated Java toolchain. To fix, recompile the source with an updated toolchain.
INFO: From Dexing external/maven/_dx/androidx_compose_ui_ui/classes_and_libs_merged.jar_desugared.jar with applicable dexopts []:
Info: Stripped invalid locals information from 1 method.
Info in bazel-out/android-armeabi-v7a-fastbuild/bin/external/maven/_dx/androidx_compose_ui_ui/classes_and_libs_merged.jar_desugared.jar:androidx/compose/ui/input/pointer/util/VelocityTracker.class:
Methods with invalid locals information:
  long androidx.compose.ui.input.pointer.util.VelocityTracker.getImpulseVelocity-9UxMQ8M()
  Information in locals-table is invalid with respect to the stack map table. Local refers to non-present stack map type for register: 8 with constraint LONG.
Info: Some warnings are typically a sign of using an outdated Java toolchain. To fix, recompile the source with an updated toolchain.
ERROR: /Users/vple/bazel_hilt_demo/kotlin/com/example/app/BUILD:3:19: KotlinKapt //kotlin/com/example/app:examplelib_kt { kt: 4, java: 0, srcjars: 0 } for armeabi-v7a failed: (Exit 1): build failed: error executing command (from target //kotlin/com/example/app:examplelib_kt) 
  (cd /private/var/tmp/_bazel_vple/5076266c303c1ab027859b6e56989c6e/execroot/__main__ && \
  exec env - \
    LC_CTYPE=en_US.UTF-8 \
    REPOSITORY_NAME=io_bazel_rules_kotlin \
  bazel-out/darwin_arm64-opt-exec-2B5CBBC6/bin/external/io_bazel_rules_kotlin/src/main/kotlin/build '--flagfile=bazel-out/android-armeabi-v7a-fastbuild/bin/kotlin/com/example/app/examplelib_kt-kapt-gensrc.jar-0.params')
# Configuration: a38a52272c28682b0c767b8d11bd23502b8f8836f39cc636f916800bb17781dc
# Execution platform: @local_config_platform//:host
error: /var/folders/tc/qpt243215ss5h5x4qf_xl86w0000gn/T/pwd12205052944019787285/_kotlinc/kotlin_com_example_app-examplelib_kt_jvm/temp/stubs/com/example/app/MyActivity.java:7: error: [Hilt]
public final class MyActivity {
             ^
  @AndroidEntryPoint class expected to extend Hilt_MyActivity. Found: Object
  [Hilt] Processing did not complete. See error above for details.
error: /var/folders/tc/qpt243215ss5h5x4qf_xl86w0000gn/T/pwd12205052944019787285/_kotlinc/kotlin_com_example_app-examplelib_kt_jvm/temp/stubs/com/example/app/MyApplication.java:7: error: [Hilt]
public final class MyApplication {
             ^
  @HiltAndroidApp class expected to extend Hilt_MyApplication. Found: Object
  [Hilt] Processing did not complete. See error above for details.
kotlin/com/example/app/MyActivity.kt:10:20: error: unresolved reference: Hilt_MyActivity
class MyActivity : Hilt_MyActivity() {
                   ^
kotlin/com/example/app/MyActivity.kt:12:43: error: unresolved reference. None of the following candidates is applicable because of receiver type mismatch: 
public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(noinline extrasProducer: (() -> CreationExtras)? = ..., noinline factoryProducer: (() -> ViewModelProvider.Factory)? = ...): Lazy<TypeVariable(VM)> defined in androidx.activity
    private val viewModel: MyViewModel by viewModels()
                                          ^
kotlin/com/example/app/MyApplication.kt:7:23: error: unresolved reference: Hilt_MyApplication
class MyApplication : Hilt_MyApplication()
                      ^
Sep 30, 2022 12:18:56 AM worker request 0
SEVERE: Compilation failure: compile phase failed:Target //:exampleapp failed to build
INFO: Elapsed time: 50.154s, Critical Path: 26.76s
INFO: 633 processes: 36 internal, 533 darwin-sandbox, 64 worker.
FAILED: Build did NOT complete successfully

Circling back here - I looked into this issue some. From what I saw the plugins are in fact being picked up correctly. I haven't figured out why but I think there's something wrong with this particular plugin and Kapt that causes the annotation processors to not work correctly.

Any updates on this issue? I'm running into this error when I try to add exported_plugins to kt_android_library:

does not have mandatory providers: 'JavaPluginInfo'. Since this rule was created by the macro 'kt_android_library', the error might have been caused by the macro implementation

No immediate updates here at the moment, but I expect this to be resolved once we switch to the Starlark implementation of rules_android.

I don't have a solution here, but digging into this more, this does appear to be resolved from the rules_kotlin side, and instead this stems from the annotation processor itself. An example application class like:

@HiltAndroidApp(Application::class)
class DemoApplication : Hilt_DemoApplication()

Results in the annotation processor (this line) seeing Object as the application's superclass, rather than Hilt_DemoApplication.

I've opened this as google/dagger#4075. I have a work-around I can share if people would like (it's linked in the Dagger issue), but it's a bit of a hack.