Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KSP resolves dependencies too early #1568

Open
yigit opened this issue Oct 12, 2023 · 9 comments
Open

KSP resolves dependencies too early #1568

yigit opened this issue Oct 12, 2023 · 9 comments

Comments

@yigit
Copy link
Collaborator

yigit commented Oct 12, 2023

We are unable to use KSP in AndroidX Multiplatform project.

Here is the repro:

  • Checkout androidx, then apply this CL:

https://android-review.googlesource.com/c/platform/frameworks/support/+/2787012

  • Run:
ANDROIDX_PROJECTS=INFRAROGUE gw :room:integration-tests:room-nativetestapp:macOsArm64Test

Build scan

It will fail with an error which is caused by KSP resolving configurations early (my guess)

I think KSP should be configuring its tasks with a provider so that the configuration is only resolved when the task is needed, not when it is configured. The early resolution causes some other AndroidX code to fail so I'm not 100% sure if this is just a KSP issue or an integration problem. But it seems like KSP should avoid resolving these collections at configuration time as they may not necessarily have the files ready yet.

@ting-yuan
Copy link
Collaborator

I haven't been able to reduce the test case to confirm the root cause yet but commenting out the line you pointed out did make the error away.

The fix could be a bit tricky though because, unlike other platforms, KotlinNativeCompile doesn't have any execution time function intended for public override. That is why it is resolved at configuration time. I'll need to talk to upstream before applying workarounds.

@yigit
Copy link
Collaborator Author

yigit commented Oct 14, 2023

I played with this a bit, have a possible solution:
yigit@7af4fb5

This branch is off of v13 so it might be a bit different but there were 2 problems:

  • FilesSubpluginOption: Gets the files in the classpath. I'm not sure if this really resolves but rather it might be just out of date when task runs. Created a ClasspathFilesSubpluginOption that will resolve it when needed.
  • val kspOptions = kspTask.options.get().flatMap { listOf("-P", it.toArg()) }: You can "almost" never call .get on a property during configuration as you don't necessarily know that it is complete. The solution is rather easy, freeArgs is already a ListProperty which accepts provider so I'm passing a provider instead:
kspTask.compilerOptions.freeCompilerArgs.addAll(
                            kspTask.options.map {
                                it.flatMap { listOf("-P", it.toArg()) }
                            }
                        )

With these two changes, i can run ./gradlew tasks on a sample project w/o it being resolved. my test case is rather ugly, there must be a better way to test this but works for now:

listOf(
    "kspLinuxX64",
    "kspMacosArm64"
).forEach {
    configurations.named(it).configure {
        dependencies.add(
            project.dependencies.create(
                project.dependencies.create("does.not:exists:1.1.1")
            )
        )
    }
}

./gradlew tasks runs without error, ./gradlew kspKotlinMacosArm64 tries to resolve it and fails.
I also validated that if i add a real dependency, it resolves properly (can see in ksp logs).

I'm not sure if the ClasspathFilesSubpluginOption is the proper solution. Gradle has some first class support for understanding classpaths but idk if it is applicable here. We likely need an audit from AGP folks to fix other possible issues.

https://github.com/google/ksp/compare/main...yigit:ksp:yigit/early-classpath-resolution-fix?expand=1

@yigit
Copy link
Collaborator Author

yigit commented Oct 15, 2023

I added tests for it, seems like it would merge to the 1.0.14 branch but I'm not sure if that is where i should send the PR for.

1.0.14 is using kotlin 1.9.0 while 1.0.13 is using 1.9.20. Lmk where I should send the PR to and i'll prepare that.

https://github.com/google/ksp/compare/1.0.14-release...yigit:yigit/early-classpath-resolution-fix?expand=1

@yigit
Copy link
Collaborator Author

yigit commented Oct 15, 2023

Btw, I tried using it in AndroidX but it is hitting another problem with configuration cache:

https://ge.androidx.dev/s/qv4vctftkgrps

⚠️cannot serialize object of type org.gradle.api.internal.artifacts.configurations.DefaultUnlockedConfiguration📋, a subtype of org.gradle.api.artifacts.Configuration📋, as these are not supported with the configuration cache.[ ?](https://docs.gradle.org/8.4-rc-2/userguide/configuration_cache.html#config_cache:requirements:disallowed_types)
⌄fieldconfiguration📋 of com.google.devtools.ksp.gradle.ClasspathFilesSubpluginOption📋
⌄bean of type com.google.devtools.ksp.gradle.ClasspathFilesSubpluginOption📋
⌄field__options__📋 of com.google.devtools.ksp.gradle.KspTaskNative📋
■task:room:integration-tests:room-nativetestapp:kspKotlinMacosArm64📋 of type com.google.devtools.ksp.gradle.KspTaskNative📋
■task:room:integration-tests:room-nativetestapp:kspTestKotlinMacosArm64📋 of type com.google.devtools.ksp.gradle.KspTaskNative📋

So my solution is not good enough yet 😢

@yigit
Copy link
Collaborator Author

yigit commented Oct 15, 2023

ok, fixed that by using a file collection:

yigit@9338edc

https://ge.androidx.dev/s/ck4ay34o54rke

@ting-yuan
Copy link
Collaborator

Thanks for the patch! We usually create PRs to main branch, and let them cherry-picked to 1.0.14-release automatically if no conflict, or we cherry-pick it manually. Feel free to keep it with 1.0.14 though. I'll pick it to the main branch.

@yigit
Copy link
Collaborator Author

yigit commented Oct 16, 2023

👍 . I'm trying to validate this in AndroidX, after that, i'll send a PR.

Seems like kspKotlinMacosArm64 is being skipped, not sure yet why so will need to debug.

We also don't have a working processor so it is a bit hard to validate it works :)

https://ge.androidx.dev/s/6n4nwjnt34ure

@yigit
Copy link
Collaborator Author

yigit commented Oct 16, 2023

So that is a different problem.

this line is returning false for kspKotlinMacosArm64, on a mac arm machine:

kspTask.konanTarget.enabledOnCurrentHost.also {
    println(
        "only if check for ${kspTask.name}: $it"
    )
}
> Task :room:integration-tests:room-nativetestapp:kspKotlinMacosArm64 SKIPPED
only if check for kspKotlinMacosArm64: false

It seems like https://youtrack.jetbrains.com/issue/KT-61657.

Changing that line to:

val konanTarget = KonanTarget.predefinedTargets[kspTask.konanTarget.name]!!
konanTarget.enabledOnCurrentHost.also {
    println(
        "only if check for ${kspTask.name} / ${konanTarget.name}: $it"
    )
}

Fixes that issue. Now the processor runs and fails with a different error:

https://ge.androidx.dev/s/zg46diayiniug

That error might be still because of KSP, not sure yet. It fails to find java/sql/SQLException but this is running on JVM hence that class should be available.

https://docs.oracle.com/javase/8/docs/api/java/sql/SQLException.html

@yigit
Copy link
Collaborator Author

yigit commented Oct 16, 2023

Ok sent a PR for 1.0.14. Looks like the KonanTarget problem was already fixed there but i still kept mine since it is adding a test that reproduces the problem.

Note that this is still not enough for AndroidX, i've asked the team to take a look at the java.sql import problem as a followup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants