Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 1 | /* |
Vsevolod Tolstopyatov | 41a2e30 | 2021-02-04 07:16:48 -0800 | [diff] [blame] | 2 | * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 3 | */ |
| 4 | |
Victor Turansky | fe2fedc | 2020-08-27 15:47:50 +0300 | [diff] [blame] | 5 | apply plugin: 'org.jetbrains.kotlin.multiplatform' |
Vsevolod Tolstopyatov | bcbcd16 | 2021-07-06 14:29:27 +0300 | [diff] [blame] | 6 | apply plugin: 'org.jetbrains.dokka' |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 7 | apply from: rootProject.file("gradle/compile-jvm-multiplatform.gradle") |
| 8 | apply from: rootProject.file("gradle/compile-common.gradle") |
Alexander Likhachev | 179f142 | 2020-11-18 17:54:33 +0300 | [diff] [blame] | 9 | |
| 10 | if (rootProject.ext.native_targets_enabled) { |
| 11 | apply from: rootProject.file("gradle/compile-native-multiplatform.gradle") |
| 12 | } |
| 13 | |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 14 | apply from: rootProject.file("gradle/compile-js-multiplatform.gradle") |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 15 | apply from: rootProject.file('gradle/publish-npm-js.gradle') |
| 16 | |
Steve Elliott | ca095be | 2022-07-25 14:26:10 +0000 | [diff] [blame] | 17 | apply from: rootProject.file('gradle/dokka.gradle.kts') |
| 18 | apply from: rootProject.file('gradle/publish.gradle') |
Roman Elizarov | 738f5a2 | 2020-10-12 19:03:46 +0300 | [diff] [blame] | 19 | /* ========================================================================== |
| 20 | Configure source sets structure for kotlinx-coroutines-core: |
| 21 | |
| 22 | TARGETS SOURCE SETS |
| 23 | ------- ---------------------------------------------- |
| 24 | |
| 25 | js -----------------------------------------------------+ |
| 26 | | |
| 27 | V |
| 28 | jvm -------------------------------> concurrent ---> common |
| 29 | ^ |
| 30 | ios \ | |
| 31 | macos | ---> nativeDarwin ---> native --+ |
| 32 | tvos | ^ |
| 33 | watchos / | |
| 34 | | |
| 35 | linux \ ---> nativeOther -------+ |
| 36 | mingw / |
| 37 | |
| 38 | ========================================================================== */ |
| 39 | |
| 40 | project.ext.sourceSetSuffixes = ["Main", "Test"] |
| 41 | |
| 42 | void defineSourceSet(newName, dependsOn, includedInPred) { |
| 43 | for (suffix in project.ext.sourceSetSuffixes) { |
| 44 | def newSS = kotlin.sourceSets.maybeCreate(newName + suffix) |
| 45 | for (dep in dependsOn) { |
| 46 | newSS.dependsOn(kotlin.sourceSets[dep + suffix]) |
| 47 | } |
| 48 | for (curSS in kotlin.sourceSets) { |
| 49 | def curName = curSS.name |
| 50 | if (curName.endsWith(suffix)) { |
| 51 | def prefix = curName.substring(0, curName.length() - suffix.length()) |
| 52 | if (includedInPred(prefix)) curSS.dependsOn(newSS) |
| 53 | } |
| 54 | } |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | static boolean isNativeDarwin(String name) { return ["ios", "macos", "tvos", "watchos"].any { name.startsWith(it) } } |
| 59 | static boolean isNativeOther(String name) { return ["linux", "mingw"].any { name.startsWith(it) } } |
| 60 | |
| 61 | defineSourceSet("concurrent", ["common"]) { it in ["jvm", "native"] } |
Alexander Likhachev | 179f142 | 2020-11-18 17:54:33 +0300 | [diff] [blame] | 62 | |
| 63 | if (rootProject.ext.native_targets_enabled) { |
| 64 | defineSourceSet("nativeDarwin", ["native"]) { isNativeDarwin(it) } |
| 65 | defineSourceSet("nativeOther", ["native"]) { isNativeOther(it) } |
| 66 | } |
Roman Elizarov | 738f5a2 | 2020-10-12 19:03:46 +0300 | [diff] [blame] | 67 | |
| 68 | /* ========================================================================== */ |
| 69 | |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 70 | /* |
| 71 | * All platform plugins and configuration magic happens here instead of build.gradle |
| 72 | * because JMV-only projects depend on core, thus core should always be initialized before configuration. |
| 73 | */ |
| 74 | kotlin { |
Steve Elliott | ca095be | 2022-07-25 14:26:10 +0000 | [diff] [blame] | 75 | sourceSets.forEach { |
| 76 | SourceSetsKt.configureMultiplatform(it) |
| 77 | } |
| 78 | |
| 79 | /* |
| 80 | * Configure four test runs: |
| 81 | * 1) Old memory model, Main thread |
| 82 | * 2) New memory model, Main thread |
| 83 | * 3) Old memory model, BG thread |
| 84 | * 4) New memory model, BG thread (required for Dispatchers.Main tests on Darwin) |
| 85 | * |
| 86 | * All new MM targets are build with optimize = true to have stress tests properly run. |
| 87 | */ |
| 88 | targets.withType(org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithTests.class).configureEach { |
| 89 | binaries { |
| 90 | // Test for memory leaks using a special entry point that does not exit but returns from main |
| 91 | binaries.getTest("DEBUG").freeCompilerArgs += ["-e", "kotlinx.coroutines.mainNoExit"] |
Vsevolod Tolstopyatov | 8273a75 | 2019-03-15 19:24:41 +0300 | [diff] [blame] | 92 | } |
Steve Elliott | ca095be | 2022-07-25 14:26:10 +0000 | [diff] [blame] | 93 | |
| 94 | binaries.test("newMM", [DEBUG]) { |
| 95 | def thisTest = it |
| 96 | freeCompilerArgs += ["-e", "kotlinx.coroutines.mainNoExit"] |
| 97 | optimized = true |
| 98 | binaryOptions["memoryModel"] = "experimental" |
| 99 | testRuns.create("newMM") { |
| 100 | setExecutionSourceFrom(thisTest) |
| 101 | // A hack to get different suffixes in the aggregated report. |
| 102 | executionTask.configure { targetName = "$targetName new MM" } |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | binaries.test("worker", [DEBUG]) { |
| 107 | def thisTest = it |
| 108 | freeCompilerArgs += ["-e", "kotlinx.coroutines.mainBackground"] |
| 109 | testRuns.create("worker") { |
| 110 | setExecutionSourceFrom(thisTest) |
| 111 | executionTask.configure { targetName = "$targetName worker" } |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | binaries.test("workerWithNewMM", [DEBUG]) { |
| 116 | def thisTest = it |
| 117 | optimized = true |
| 118 | freeCompilerArgs += ["-e", "kotlinx.coroutines.mainBackground"] |
| 119 | binaryOptions["memoryModel"] = "experimental" |
| 120 | testRuns.create("workerWithNewMM") { |
| 121 | setExecutionSourceFrom(thisTest) |
| 122 | executionTask.configure { targetName = "$targetName worker with new MM" } |
| 123 | } |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 124 | } |
| 125 | } |
| 126 | |
Steve Elliott | ca095be | 2022-07-25 14:26:10 +0000 | [diff] [blame] | 127 | jvm { |
| 128 | // For animal sniffer |
| 129 | withJava() |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 130 | } |
| 131 | } |
| 132 | |
Steve Elliott | ca095be | 2022-07-25 14:26:10 +0000 | [diff] [blame] | 133 | |
Roman Elizarov | d2f4b2b | 2019-09-02 17:22:39 +0300 | [diff] [blame] | 134 | configurations { |
| 135 | configureKotlinJvmPlatform(kotlinCompilerPluginClasspath) |
| 136 | } |
| 137 | |
Roman Elizarov | 90a9faf | 2020-02-12 16:38:26 +0300 | [diff] [blame] | 138 | // Update module name for metadata artifact to avoid conflicts |
| 139 | // see https://github.com/Kotlin/kotlinx.coroutines/issues/1797 |
| 140 | compileKotlinMetadata { |
| 141 | kotlinOptions { |
| 142 | freeCompilerArgs += ["-module-name", "kotlinx-coroutines-core-common"] |
| 143 | } |
| 144 | } |
| 145 | |
Roman Elizarov | 738f5a2 | 2020-10-12 19:03:46 +0300 | [diff] [blame] | 146 | // :KLUDGE: Idea.active: This is needed to workaround resolve problems after importing this project to IDEA |
| 147 | def configureNativeSourceSetPreset(name, preset) { |
| 148 | def hostMainCompilation = project.kotlin.targetFromPreset(preset).compilations.main |
| 149 | // Look for platform libraries in "implementation" for default source set |
| 150 | def implementationConfiguration = configurations[hostMainCompilation.defaultSourceSet.implementationMetadataConfigurationName] |
| 151 | // Now find the libraries: Finds platform libs & stdlib, but platform declarations are still not resolved due to IDE bugs |
| 152 | def hostNativePlatformLibs = files( |
| 153 | provider { |
| 154 | implementationConfiguration.findAll { |
| 155 | it.path.endsWith(".klib") || it.absolutePath.contains("klib${File.separator}platform") || it.absolutePath.contains("stdlib") |
| 156 | } |
| 157 | } |
| 158 | ) |
| 159 | // Add all those dependencies |
| 160 | for (suffix in sourceSetSuffixes) { |
| 161 | configure(kotlin.sourceSets[name + suffix]) { |
| 162 | dependencies.add(implementationMetadataConfigurationName, hostNativePlatformLibs) |
| 163 | } |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | // :KLUDGE: Idea.active: Configure platform libraries for native source sets when working in IDEA |
Alexander Likhachev | 179f142 | 2020-11-18 17:54:33 +0300 | [diff] [blame] | 168 | if (Idea.active && rootProject.ext.native_targets_enabled) { |
Roman Elizarov | 738f5a2 | 2020-10-12 19:03:46 +0300 | [diff] [blame] | 169 | def manager = project.ext.hostManager |
| 170 | def linuxPreset = kotlin.presets.linuxX64 |
| 171 | def macosPreset = kotlin.presets.macosX64 |
| 172 | // linux should be always available (cross-compilation capable) -- use it as default |
| 173 | assert manager.isEnabled(linuxPreset.konanTarget) |
| 174 | // use macOS libs for nativeDarwin if available |
| 175 | def macosAvailable = manager.isEnabled(macosPreset.konanTarget) |
| 176 | // configure source sets |
| 177 | configureNativeSourceSetPreset("native", linuxPreset) |
| 178 | configureNativeSourceSetPreset("nativeOther", linuxPreset) |
| 179 | configureNativeSourceSetPreset("nativeDarwin", macosAvailable ? macosPreset : linuxPreset) |
| 180 | } |
| 181 | |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 182 | kotlin.sourceSets { |
Roman Elizarov | 0bf172b | 2020-06-02 10:20:57 +0300 | [diff] [blame] | 183 | jvmMain.dependencies { |
Vsevolod Tolstopyatov | 559023d | 2020-05-14 16:24:18 +0300 | [diff] [blame] | 184 | compileOnly "com.google.android:annotations:4.1.1.4" |
| 185 | } |
| 186 | |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 187 | jvmTest.dependencies { |
Roman Elizarov | 738f5a2 | 2020-10-12 19:03:46 +0300 | [diff] [blame] | 188 | api "org.jetbrains.kotlinx:lincheck:$lincheck_version" |
Roman Elizarov | 660c2d7 | 2020-02-14 13:18:37 +0300 | [diff] [blame] | 189 | api "org.jetbrains.kotlinx:kotlinx-knit-test:$knit_version" |
Roman Elizarov | 738f5a2 | 2020-10-12 19:03:46 +0300 | [diff] [blame] | 190 | implementation project(":android-unit-tests") |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 191 | } |
| 192 | } |
| 193 | |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 194 | jvmTest { |
| 195 | minHeapSize = '1g' |
| 196 | maxHeapSize = '1g' |
| 197 | enableAssertions = true |
Nikita Koval | b13018d | 2020-11-28 15:02:58 +0300 | [diff] [blame] | 198 | if (!Idea.active) { |
| 199 | // We should not set this security manager when `jvmTest` |
| 200 | // is invoked by IntelliJ IDEA since we need to pass |
| 201 | // system properties for Lincheck and stress tests. |
| 202 | // TODO Remove once IDEA is smart enough to select between `jvmTest`/`jvmStressTest`/`jvmLincheckTest` #KTIJ-599 |
| 203 | systemProperty 'java.security.manager', 'kotlinx.coroutines.TestSecurityManager' |
| 204 | } |
Vsevolod Tolstopyatov | a64e4da | 2019-10-10 13:03:06 +0300 | [diff] [blame] | 205 | // 'stress' is required to be able to run all subpackage tests like ":jvmTests --tests "*channels*" -Pstress=true" |
Roman Elizarov | 738f5a2 | 2020-10-12 19:03:46 +0300 | [diff] [blame] | 206 | if (!Idea.active && rootProject.properties['stress'] == null) { |
Nikita Koval | b13018d | 2020-11-28 15:02:58 +0300 | [diff] [blame] | 207 | exclude '**/*LincheckTest.*' |
Vsevolod Tolstopyatov | a64e4da | 2019-10-10 13:03:06 +0300 | [diff] [blame] | 208 | exclude '**/*StressTest.*' |
| 209 | } |
Nikita Koval | b13018d | 2020-11-28 15:02:58 +0300 | [diff] [blame] | 210 | if (Idea.active) { |
| 211 | // Configure the IDEA runner for Lincheck |
| 212 | configureJvmForLincheck(jvmTest) |
| 213 | } |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 214 | } |
| 215 | |
Vsevolod Tolstopyatov | b400b02 | 2021-04-21 17:42:23 +0300 | [diff] [blame] | 216 | // Setup manifest for kotlinx-coroutines-core-jvm.jar |
| 217 | jvmJar { setupManifest(it) } |
| 218 | |
| 219 | /* |
| 220 | * Setup manifest for kotlinx-coroutines-core.jar |
| 221 | * This is convenient for users that pass -javaagent arg manually and also is a workaround #2619 and KTIJ-5659. |
| 222 | * This manifest contains reference to AgentPremain that belongs to |
| 223 | * kotlinx-coroutines-core-jvm, but our resolving machinery guarantees that |
| 224 | * any JVM project that depends on -core artifact also depends on -core-jvm one. |
| 225 | */ |
| 226 | metadataJar { setupManifest(it) } |
| 227 | |
| 228 | static def setupManifest(Jar jar) { |
| 229 | jar.manifest { |
Vsevolod Tolstopyatov | 70a7487 | 2020-04-24 14:59:28 +0300 | [diff] [blame] | 230 | attributes "Premain-Class": "kotlinx.coroutines.debug.AgentPremain" |
| 231 | attributes "Can-Retransform-Classes": "true" |
| 232 | } |
| 233 | } |
| 234 | |
Roman Elizarov | 216828a | 2019-09-28 00:42:51 +0300 | [diff] [blame] | 235 | task jvmStressTest(type: Test, dependsOn: compileTestKotlinJvm) { |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 236 | classpath = files { jvmTest.classpath } |
| 237 | testClassesDirs = files { jvmTest.testClassesDirs } |
Roman Elizarov | fd27d55 | 2019-09-25 23:49:34 +0300 | [diff] [blame] | 238 | minHeapSize = '1g' |
| 239 | maxHeapSize = '1g' |
| 240 | include '**/*StressTest.*' |
Roman Elizarov | 0b16abf | 2019-09-03 11:07:11 +0300 | [diff] [blame] | 241 | enableAssertions = true |
| 242 | testLogging.showStandardStreams = true |
Roman Elizarov | fd27d55 | 2019-09-25 23:49:34 +0300 | [diff] [blame] | 243 | systemProperty 'kotlinx.coroutines.scheduler.keep.alive.sec', '100000' // any unpark problem hangs test |
Nikita Koval | ac42be9 | 2020-04-23 20:01:05 +0300 | [diff] [blame] | 244 | systemProperty 'kotlinx.coroutines.semaphore.segmentSize', '2' |
| 245 | systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '10' |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 246 | } |
| 247 | |
Nikita Koval | b13018d | 2020-11-28 15:02:58 +0300 | [diff] [blame] | 248 | task jvmLincheckTest(type: Test, dependsOn: compileTestKotlinJvm) { |
| 249 | classpath = files { jvmTest.classpath } |
| 250 | testClassesDirs = files { jvmTest.testClassesDirs } |
| 251 | include '**/*LincheckTest.*' |
| 252 | enableAssertions = true |
| 253 | testLogging.showStandardStreams = true |
| 254 | configureJvmForLincheck(jvmLincheckTest) |
| 255 | } |
| 256 | |
| 257 | static void configureJvmForLincheck(task) { |
| 258 | task.minHeapSize = '1g' |
Steve Elliott | ca095be | 2022-07-25 14:26:10 +0000 | [diff] [blame] | 259 | task.maxHeapSize = '4g' // we may need more space for building an interleaving tree in the model checking mode |
Nikita Koval | b13018d | 2020-11-28 15:02:58 +0300 | [diff] [blame] | 260 | task.jvmArgs = ['--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED', // required for transformation |
Steve Elliott | ca095be | 2022-07-25 14:26:10 +0000 | [diff] [blame] | 261 | '--add-exports', 'java.base/jdk.internal.util=ALL-UNNAMED'] // in the model checking mode |
Nikita Koval | b13018d | 2020-11-28 15:02:58 +0300 | [diff] [blame] | 262 | task.systemProperty 'kotlinx.coroutines.semaphore.segmentSize', '2' |
| 263 | task.systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '1' // better for the model checking mode |
| 264 | } |
| 265 | |
Steve Elliott | ca095be | 2022-07-25 14:26:10 +0000 | [diff] [blame] | 266 | // Always check additional test sets |
| 267 | task moreTest(dependsOn: [jvmStressTest, jvmLincheckTest]) |
| 268 | check.dependsOn moreTest |
| 269 | |
| 270 | tasks.jvmLincheckTest { |
| 271 | kover { |
| 272 | enabled = false // Always disabled, lincheck doesn't really support coverage |
| 273 | } |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 274 | } |
| 275 | |
Steve Elliott | ca095be | 2022-07-25 14:26:10 +0000 | [diff] [blame] | 276 | def commonKoverExcludes = |
| 277 | ["kotlinx.coroutines.debug.*", // Tested by debug module |
| 278 | "kotlinx.coroutines.channels.ChannelsKt__DeprecatedKt.*", // Deprecated |
| 279 | "kotlinx.coroutines.scheduling.LimitingDispatcher", // Deprecated |
| 280 | "kotlinx.coroutines.scheduling.ExperimentalCoroutineDispatcher" // Deprecated |
| 281 | ] |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 282 | |
Steve Elliott | ca095be | 2022-07-25 14:26:10 +0000 | [diff] [blame] | 283 | tasks.koverHtmlReport { |
| 284 | excludes = commonKoverExcludes |
| 285 | } |
| 286 | |
| 287 | tasks.koverVerify { |
| 288 | excludes = commonKoverExcludes |
| 289 | } |
Vsevolod Tolstopyatov | e50a0fa | 2019-01-28 11:34:24 +0300 | [diff] [blame] | 290 | |
| 291 | task testsJar(type: Jar, dependsOn: jvmTestClasses) { |
| 292 | classifier = 'tests' |
| 293 | from compileTestKotlinJvm.destinationDir |
| 294 | } |
| 295 | |
| 296 | artifacts { |
| 297 | archives testsJar |
| 298 | } |