-
Notifications
You must be signed in to change notification settings - Fork 67
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
Validate KLIB ABI compatibility on Multiplatform #149
Comments
Things that are worth keeping in mind (or maybe even split into a few subtasks): Dependency on the Kotlin compiler
Default behaviour and migration path
|
I would recommend to use |
https://github.com/Kotlin/binary-compatibility-validator This plugin dumps all API for JVM modules to files (in the future - for other targets). If API changed, we should call: ``` ./gradlew desktopApiDump ``` to commit a new API, otherwise CI will fail (``./gradlew desktopApiCheck` is called as part of `` command). If you see that some strings are deleted in the API dump, most probably it means an incompatible API change (the plugin doesn't check itself, unfortunately). For Desktop API is constructed from desktopMain + skikoMain + commonMain sourceSets For Android API is constructed from desktopMain + commonMain (but it is disabled for now, because Android is in a broke state). Jetpack Compose sources has own API generator (Metalava), but it won't be applicable to other Kotlin targets in the future, but this library [will](Kotlin/binary-compatibility-validator#149) [The workflow](https://github.com/Kotlin/binary-compatibility-validator#workflow) Example of error: ``` Execution failed for task ':compose:material3:material3:desktopApiCheck'. > API check failed for project material3. --- D:\Work\compose-multiplatform-core\compose\material3\material3\api\desktop\material3.api +++ D:\Work\compose-multiplatform-core\out\androidx\compose\material3\material3\build\api\desktop\material3.api @@ -552,6 +552,11 @@ public abstract interface annotation class androidx/compose/material3/ExperimentalMaterial3Api : java/lang/annotation/Annotation { } +public final class androidx/compose/material3/FF { + public static final field $stable I + public fun <init> ()V +} + public final class androidx/compose/material3/FabPosition { public static final field Companion Landroidx/compose/material3/FabPosition$Companion; public static final synthetic fun box-impl (I)Landroidx/compose/material3/FabPosition; You can run :material3:apiDump task to overwrite API declarations ``` One disadvantage that error shows `apiDump` instead of `desktopApiDump`. `apiDump` doesn't work because of the broken Android target, and to fix it properly we need to do a lot of changes. Just disabling the tasks doesn't work
https://github.com/Kotlin/binary-compatibility-validator This plugin dumps all API for JVM modules to files (in the future - for other targets). If API changed, we should call: ``` ./gradlew desktopApiDump ``` to commit a new API, otherwise CI will fail (`./gradlew desktopApiCheck` will be called on CI, and as part of `./gradlew check`). If you see that some strings are deleted in the API dump, most probably it means an incompatible API change (the plugin doesn't check itself, unfortunately). For Desktop API is constructed from desktopMain + skikoMain + commonMain sourceSets For Android API is constructed from desktopMain + commonMain (but it is disabled for now, because Android is in a broke state). The plan is to fix the Android target, and dump Android API as well. It will help us to track new API that we need to port more easily. [The workflow](https://github.com/Kotlin/binary-compatibility-validator#workflow) Example of error: ``` Execution failed for task ':compose:material3:material3:desktopApiCheck'. > API check failed for project material3. --- D:\Work\compose-multiplatform-core\compose\material3\material3\api\desktop\material3.api +++ D:\Work\compose-multiplatform-core\out\androidx\compose\material3\material3\build\api\desktop\material3.api @@ -552,6 +552,11 @@ public abstract interface annotation class androidx/compose/material3/ExperimentalMaterial3Api : java/lang/annotation/Annotation { } +public final class androidx/compose/material3/FF { + public static final field $stable I + public fun <init> ()V +} + public final class androidx/compose/material3/FabPosition { public static final field Companion Landroidx/compose/material3/FabPosition$Companion; public static final synthetic fun box-impl (I)Landroidx/compose/material3/FabPosition; You can run :material3:apiDump task to overwrite API declarations ``` One disadvantage that error shows `apiDump` instead of `desktopApiDump`. `apiDump` doesn't work because of the broken Android target, and to fix it properly we need to do a lot of changes. Just disabling the tasks doesn't work. P.S. Jetpack Compose sources has its own API generator (Metalava), but it won't be applicable to other Kotlin targets in the future, but binary-compatibility-validator [will](Kotlin/binary-compatibility-validator#149)
https://github.com/Kotlin/binary-compatibility-validator This plugin dumps all API for JVM modules to files (in the future - for other targets). If API changed, we should call: ``` ./gradlew desktopApiDump ``` to commit a new API, otherwise CI will fail (`./gradlew desktopCICheck` will be called on CI`). If you see that some strings are deleted in the API dump, most probably it means an incompatible API change (the plugin doesn't check itself, unfortunately). - For Desktop API is constructed from desktopMain + skikoMain + commonMain sourceSets - For Android API is constructed from desktopMain + commonMain (but it is disabled for now, because Android is in a broke state). The plan is to fix the Android target, and dump Android API as well. It will help us to track new API that we need to port more easily. [The workflow](https://github.com/Kotlin/binary-compatibility-validator#workflow) Example of error: ``` Execution failed for task ':compose:material3:material3:desktopApiCheck'. > API check failed for project material3. --- D:\Work\compose-multiplatform-core\compose\material3\material3\api\desktop\material3.api +++ D:\Work\compose-multiplatform-core\out\androidx\compose\material3\material3\build\api\desktop\material3.api @@ -552,6 +552,11 @@ public abstract interface annotation class androidx/compose/material3/ExperimentalMaterial3Api : java/lang/annotation/Annotation { } +public final class androidx/compose/material3/FF { + public static final field $stable I + public fun <init> ()V +} + public final class androidx/compose/material3/FabPosition { public static final field Companion Landroidx/compose/material3/FabPosition$Companion; public static final synthetic fun box-impl (I)Landroidx/compose/material3/FabPosition; You can run :material3:apiDump task to overwrite API declarations ``` One disadvantage that error shows `apiDump` instead of `desktopApiDump`. `apiDump` doesn't work because of the broken Android target, and to fix it properly we need to do a lot of changes. Just disabling the tasks doesn't work. P.S. Jetpack Compose sources has its own API generator (Metalava), but it won't be applicable to other Kotlin targets in the future, but binary-compatibility-validator [will](Kotlin/binary-compatibility-validator#149) ## Test 1. call desktopCICheck - it succeeds 2. change/add API 3. call desktopCICheck - it fails
https://github.com/Kotlin/binary-compatibility-validator This plugin dumps all API for JVM modules to files (in the future - for other targets). If API changed, we should call: ``` ./gradlew desktopApiDump ``` to commit a new API, otherwise CI will fail (`./gradlew desktopCICheck` will be called on CI`). If you see that some strings are deleted in the API dump, most probably it means an incompatible API change (the plugin doesn't check itself, unfortunately). See [the official workflow guide](https://github.com/Kotlin/binary-compatibility-validator#workflow) to understand it more. Example of error: ``` Execution failed for task ':compose:material3:material3:desktopApiCheck'. > API check failed for project material3. --- D:\Work\compose-multiplatform-core\compose\material3\material3\api\desktop\material3.api +++ D:\Work\compose-multiplatform-core\out\androidx\compose\material3\material3\build\api\desktop\material3.api @@ -552,6 +552,11 @@ public abstract interface annotation class androidx/compose/material3/ExperimentalMaterial3Api : java/lang/annotation/Annotation { } +public final class androidx/compose/material3/FF { + public static final field $stable I + public fun <init> ()V +} + public final class androidx/compose/material3/FabPosition { public static final field Companion Landroidx/compose/material3/FabPosition$Companion; public static final synthetic fun box-impl (I)Landroidx/compose/material3/FabPosition; You can run :material3:apiDump task to overwrite API declarations ``` One disadvantage that error shows `apiDump` instead of `desktopApiDump`. `apiDump` doesn't work because of the broken Android target, and to fix it properly we need to do a lot of changes. Just disabling the tasks doesn't work. - Desktop API is constructed from desktopMain + skikoMain + commonMain sourceSets - Android API is constructed from desktopMain + commonMain. It is disabled for now, because Android build is broken. The plan is to fix the Android target, and dump Android API as well. It will help us to track new API that we need to port more easily. P.S. Jetpack Compose sources has its own API generator (Metalava), but it won't be applicable to other Kotlin targets in the future, but binary-compatibility-validator [will](Kotlin/binary-compatibility-validator#149) ## Test 1. call desktopCICheck - it succeeds 2. change/add API 3. call desktopCICheck - it fails --------- Co-authored-by: Ivan Matkov <[email protected]>
I see a few options here:
It's also unclear if there's anything we should do about identical KLIB ABI dumps across different native targets. |
My vote is for option #1, hidden under the flag initially (because this functionality is going to be wildly unstable).
Probably we'll need to dump ABI for configured source-sets, not targets, implying that different targets in the same source-sets are identical |
A downside of such an approach is that a logic of searching for a source set dominating multiple targets tends to be fragile (it could work fine for default hierarchies, but I'm afraid that for non-default hierarchies we may end up with a bunch of unique source sets tied to targets). |
So far, here's how it going to work:
Right now, dumps will be generated (and verified) for each configured target that is supported by the host. |
In the future we might implement v3 of signatures. Do I get it right that no changes will be required in the compatibility validator, it will support new version of signatures just out of box and all that will be actually needed is that the user should specify |
@ddolovov You got it right: once v3 of signatures is available, users need only specify |
After trying klib validation on several projects I came up with a solution for the problem with multiple identical files generated for each native target (described at the end of #149 (comment)). Instead of simply saving all text dumps for native targets, BCV will merge them into a single file. If a declaration was presented in all original dumps, it will be written to the merged dump without any changes. If a declaration is specific to a subset of native targets, in the merged dump it will be annotated with all the targets it is specific to. Here's how the merged dump will look like: https://raw.githubusercontent.com/Kotlin/binary-compatibility-validator/merge-klib-dumps/src/functionalTest/resources/examples/classes/AnotherBuildConfigLinuxArm64Extra.klib.dump Such format amplifies the problem existing before, but that was not discussed yet: at the moment, only Apple hosts (well, only macOS) supports compilation for all target platforms supported by Kotlin/Native, if a developer is using Klib validation on the Linux or Windows workstation, they won't be able to neither dump, not verify ABI for all the targets.
It's crucial that latter two tasks will not be executed along with
Please let me know if you see any issues with the update described above or share you suggestions if you know how to tackle aforementioned issues better. |
https://github.com/Kotlin/binary-compatibility-validator This plugin dumps all API for JVM modules to files (in the future - for other targets). If API changed, we should call: ``` ./gradlew desktopApiDump ``` to commit a new API, otherwise CI will fail (`./gradlew desktopCICheck` will be called on CI`). If you see that some strings are deleted in the API dump, most probably it means an incompatible API change (the plugin doesn't check itself, unfortunately). See [the official workflow guide](https://github.com/Kotlin/binary-compatibility-validator#workflow) to understand it more. Example of error: ``` Execution failed for task ':compose:material3:material3:desktopApiCheck'. > API check failed for project material3. --- D:\Work\compose-multiplatform-core\compose\material3\material3\api\desktop\material3.api +++ D:\Work\compose-multiplatform-core\out\androidx\compose\material3\material3\build\api\desktop\material3.api @@ -552,6 +552,11 @@ public abstract interface annotation class androidx/compose/material3/ExperimentalMaterial3Api : java/lang/annotation/Annotation { } +public final class androidx/compose/material3/FF { + public static final field $stable I + public fun <init> ()V +} + public final class androidx/compose/material3/FabPosition { public static final field Companion Landroidx/compose/material3/FabPosition$Companion; public static final synthetic fun box-impl (I)Landroidx/compose/material3/FabPosition; You can run :material3:apiDump task to overwrite API declarations ``` One disadvantage that error shows `apiDump` instead of `desktopApiDump`. `apiDump` doesn't work because of the broken Android target, and to fix it properly we need to do a lot of changes. Just disabling the tasks doesn't work. - Desktop API is constructed from desktopMain + skikoMain + commonMain sourceSets - Android API is constructed from desktopMain + commonMain. It is disabled for now, because Android build is broken. The plan is to fix the Android target, and dump Android API as well. It will help us to track new API that we need to port more easily. P.S. Jetpack Compose sources has its own API generator (Metalava), but it won't be applicable to other Kotlin targets in the future, but binary-compatibility-validator [will](Kotlin/binary-compatibility-validator#149) ## Test 1. call desktopCICheck - it succeeds 2. change/add API 3. call desktopCICheck - it fails --------- Co-authored-by: Ivan Matkov <[email protected]>
I'm such a developer, and I very much need to generate ABI dumps when committing source changes (my CI will check all targets). So those heuristic-based tasks would indeed be very welcome. But something bugs me here. Why can't we generate actual ABI dumps for Apple targets on Windows (not heuristic-based)? My IDE can compile fine the Apple-specific code thanks to the CompleteKotlin Gradle plugin (which downloads Kotlin bindings for the Foundation framework and other platform-specific stuff). The current KGP doesn't download those bindings by default, but it could, and it seems compilation could work properly too. I'm not expecting to run any Apple target tests on my windows machine, but the CompleteKotlin plugin sort of proves that there is no technical reason for this limitation (the Kotlin bindings are provided by JetBrains and don't require a mac). |
At this moment, Apple targets are not supported by the Kotlin compiler on host platforms other than MacOs, so there's no way to emit klibs for these targets (thus there are no klibs to extract dumps from). I didn't had a chance to check the CompleteKotlin plugin yet, but it seems like it only solves an issue with Idea autocompletion, as one still has to compile final binaries on a proper host. And BCV needs a klib. |
Thanks for your prompt answer, that clarifies things a bit. Indeed CompleteKotlin is about IDE completion, but I thought this implied we were able to run the embedded compiler from the Kotlin IDE plugin so it can highlight things in the editor. I'm probably missing a bit too much context for this. But in any case thanks for this issue. |
TBH, I don't have an answer right now. Need to investigate how the things work there. |
There's an API to verify KLIB's binary compatibility that'll be released soon:
https://youtrack.jetbrains.com/Issue/KT-54402
https://github.com/JetBrains/kotlin/blob/master/compiler/util-klib-abi/ReadMe.md
BCV should use it to support KLIBs validation in addition to JVM bytecode validation.
The text was updated successfully, but these errors were encountered: