aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordkhalanskyjb <52952525+dkhalanskyjb@users.noreply.github.com>2020-10-09 12:01:05 +0300
committerGitHub <noreply@github.com>2020-10-09 12:01:05 +0300
commitb82439e6b570249cfbd25622dc06cb0ec156c006 (patch)
tree9f53172b2dc5dcb03d2778227b96898dc1e92ad8
parent20ca97ad47adc249c6211ad9d12e31f1074984d7 (diff)
downloadkotlinx.coroutines-b82439e6b570249cfbd25622dc06cb0ec156c006.tar.gz
Document problems with building coroutines-using Android projects (#2288)
Added instructions to work around #2023 Also, the answer to #2274 is now documented. Co-authored-by: Vsevolod Tolstopyatov <qwwdfsad@gmail.com>
-rw-r--r--README.md11
-rw-r--r--kotlinx-coroutines-debug/README.md92
2 files changed, 103 insertions, 0 deletions
diff --git a/README.md b/README.md
index 4b6f99be..7f71d288 100644
--- a/README.md
+++ b/README.md
@@ -176,6 +176,17 @@ threads are handled by Android runtime.
R8 and ProGuard rules are bundled into the [`kotlinx-coroutines-android`](ui/kotlinx-coroutines-android) module.
For more details see ["Optimization" section for Android](ui/kotlinx-coroutines-android/README.md#optimization).
+#### Avoiding including the debug infrastructure in the resulting APK
+
+The `kotlinx-coroutines-core` artifact contains a resource file that is not required for the coroutines to operate
+normally and is only used by the debugger. To exclude it at no loss of functionality, add the following snippet to the
+`android` block in your gradle file for the application subproject:
+```groovy
+packagingOptions {
+ exclude "DebugProbesKt.bin"
+}
+```
+
### JS
[Kotlin/JS](https://kotlinlang.org/docs/reference/js-overview.html) version of `kotlinx.coroutines` is published as
diff --git a/kotlinx-coroutines-debug/README.md b/kotlinx-coroutines-debug/README.md
index 7c4501ab..1278ed13 100644
--- a/kotlinx-coroutines-debug/README.md
+++ b/kotlinx-coroutines-debug/README.md
@@ -170,6 +170,98 @@ java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/Mana
at kotlinx.coroutines.debug.DebugProbes.install(DebugProbes.kt:49)
-->
+#### Build failures due to duplicate resource files
+
+Building an Android project that depends on `kotlinx-coroutines-debug` (usually introduced by being a transitive
+dependency of `kotlinx-coroutines-test`) may fail with `DuplicateRelativeFileException` for `META-INF/AL2.0`,
+`META-INF/LGPL2.1`, or `win32-x86/attach_hotspot_windows.dll` when trying to merge the Android resource.
+
+The problem is that Android merges the resources of all its dependencies into a single directory and complains about
+conflicts, but:
+* `kotlinx-coroutines-debug` transitively depends on JNA and JNA-platform, both of which include license files in their
+ META-INF directories. Trying to merge these files leads to conflicts, which means that any Android project that
+ depends on JNA and JNA-platform will experience build failures.
+* Additionally, `kotlinx-coroutines-debug` embeds `byte-buddy-agent` and `byte-buddy`, along with their resource files.
+ Then, if the project separately depends on `byte-buddy`, merging the resources of `kotlinx-coroutines-debug` with ones
+ from `byte-buddy` and `byte-buddy-agent` will lead to conflicts as the resource files are duplicated.
+
+One possible workaround for these issues is to add the following to the `android` block in your gradle file for the
+application subproject:
+```groovy
+ packagingOptions {
+ // for JNA and JNA-platform
+ exclude "META-INF/AL2.0"
+ exclude "META-INF/LGPL2.1"
+ // for byte-buddy
+ exclude "META-INF/licenses/ASM"
+ pickFirst "win32-x86-64/attach_hotspot_windows.dll"
+ pickFirst "win32-x86/attach_hotspot_windows.dll"
+ }
+```
+This will cause the resource merge algorithm to exclude the problematic license files altogether and only leave a single
+copy of the files needed for `byte-buddy-agent` to work.
+
+Alternatively, avoid depending on `kotlinx-coroutines-debug`. In particular, if the only reason why this library a
+dependency of your project is that `kotlinx-coroutines-test` in turn depends on it, you may change your dependency on
+`kotlinx.coroutines.test` to exclude `kotlinx-coroutines-debug`. For example, you could replace
+```kotlin
+androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version")
+```
+with
+```groovy
+androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version") {
+ exclude group: "org.jetbrains.kotlinx", module: "kotlinx-coroutines-debug"
+}
+```
+<!---
+Snippets of stacktraces for googling:
+
+org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:mergeDebugAndroidTestJavaResource'.
+ ...
+Caused by: org.gradle.workers.intelrnal.DefaultWorkerExecutor$WorkExecutionException: A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
+ ...
+Caused by: com.android.builder.merge.DuplicateRelativeFileException: More than one file was found with OS independent path 'META-INF/AL2.0'.
+ at com.android.builder.merge.StreamMergeAlgorithms.lambda$acceptOnlyOne$2(StreamMergeAlgorithms.java:85)
+ at com.android.builder.merge.StreamMergeAlgorithms.lambda$select$3(StreamMergeAlgorithms.java:106)
+ at com.android.builder.merge.IncrementalFileMergerOutputs$1.create(IncrementalFileMergerOutputs.java:88)
+ at com.android.builder.merge.DelegateIncrementalFileMergerOutput.create(DelegateIncrementalFileMergerOutput.java:64)
+ at com.android.build.gradle.internal.tasks.MergeJavaResourcesDelegate$run$output$1.create(MergeJavaResourcesDelegate.kt:230)
+ at com.android.builder.merge.IncrementalFileMerger.updateChangedFile(IncrementalFileMerger.java:242)
+ at com.android.builder.merge.IncrementalFileMerger.mergeChangedInputs(IncrementalFileMerger.java:203)
+ at com.android.builder.merge.IncrementalFileMerger.merge(IncrementalFileMerger.java:80)
+ at com.android.build.gradle.internal.tasks.MergeJavaResourcesDelegate.run(MergeJavaResourcesDelegate.kt:276)
+ at com.android.build.gradle.internal.tasks.MergeJavaResRunnable.run(MergeJavaResRunnable.kt:81)
+ at com.android.build.gradle.internal.tasks.Workers$ActionFacade.run(Workers.kt:242)
+ at org.gradle.workers.internal.AdapterWorkAction.execute(AdapterWorkAction.java:50)
+ at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:50)
+ at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:63)
+ at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:59)
+ at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:98)
+ at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:59)
+ at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
+ at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
+ at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416)
+ at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406)
+ at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
+ at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
+ at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
+ at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102)
+ at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
+ at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
+ at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:53)
+ at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$2(DefaultWorkerExecutor.java:200)
+ at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:215)
+ at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
+ at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:131)
+
+Execution failed for task ':app:mergeStagingDebugAndroidTestJavaResource'.
+Execution failed for task ':app:mergeDebugAndroidTestJavaResource'.
+Execution failed for task ':app:mergeDebugTestJavaResource'
+
+More than one file was found with OS independent path 'META-INF/LGPL2.1'
+More than one file was found with OS independent path 'win32-x86/attach_hotspot_windows.dll'
+More than one file was found with OS independent path 'win32-x86-64/attach_hotspot_windows.dll'
+-->
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html