1/* 2 * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5apply plugin: 'org.jetbrains.kotlin.multiplatform' 6apply plugin: 'org.jetbrains.dokka' 7apply from: rootProject.file("gradle/compile-jvm-multiplatform.gradle") 8apply from: rootProject.file("gradle/compile-common.gradle") 9 10if (rootProject.ext.native_targets_enabled) { 11 apply from: rootProject.file("gradle/compile-native-multiplatform.gradle") 12} 13 14apply from: rootProject.file("gradle/compile-js-multiplatform.gradle") 15apply from: rootProject.file('gradle/publish-npm-js.gradle') 16 17apply from: rootProject.file('gradle/dokka.gradle.kts') 18apply from: rootProject.file('gradle/publish.gradle') 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 40project.ext.sourceSetSuffixes = ["Main", "Test"] 41 42void 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 58static boolean isNativeDarwin(String name) { return ["ios", "macos", "tvos", "watchos"].any { name.startsWith(it) } } 59static boolean isNativeOther(String name) { return ["linux", "mingw"].any { name.startsWith(it) } } 60 61defineSourceSet("concurrent", ["common"]) { it in ["jvm", "native"] } 62 63if (rootProject.ext.native_targets_enabled) { 64 defineSourceSet("nativeDarwin", ["native"]) { isNativeDarwin(it) } 65 defineSourceSet("nativeOther", ["native"]) { isNativeOther(it) } 66} 67 68/* ========================================================================== */ 69 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 */ 74kotlin { 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"] 92 } 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 } 124 } 125 } 126 127 jvm { 128 // For animal sniffer 129 withJava() 130 } 131} 132 133 134configurations { 135 configureKotlinJvmPlatform(kotlinCompilerPluginClasspath) 136} 137 138// Update module name for metadata artifact to avoid conflicts 139// see https://github.com/Kotlin/kotlinx.coroutines/issues/1797 140compileKotlinMetadata { 141 kotlinOptions { 142 freeCompilerArgs += ["-module-name", "kotlinx-coroutines-core-common"] 143 } 144} 145 146// :KLUDGE: Idea.active: This is needed to workaround resolve problems after importing this project to IDEA 147def 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 168if (Idea.active && rootProject.ext.native_targets_enabled) { 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 182kotlin.sourceSets { 183 jvmMain.dependencies { 184 compileOnly "com.google.android:annotations:4.1.1.4" 185 } 186 187 jvmTest.dependencies { 188 api "org.jetbrains.kotlinx:lincheck:$lincheck_version" 189 api "org.jetbrains.kotlinx:kotlinx-knit-test:$knit_version" 190 implementation project(":android-unit-tests") 191 } 192} 193 194jvmTest { 195 minHeapSize = '1g' 196 maxHeapSize = '1g' 197 enableAssertions = true 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 } 205 // 'stress' is required to be able to run all subpackage tests like ":jvmTests --tests "*channels*" -Pstress=true" 206 if (!Idea.active && rootProject.properties['stress'] == null) { 207 exclude '**/*LincheckTest.*' 208 exclude '**/*StressTest.*' 209 } 210 if (Idea.active) { 211 // Configure the IDEA runner for Lincheck 212 configureJvmForLincheck(jvmTest) 213 } 214} 215 216// Setup manifest for kotlinx-coroutines-core-jvm.jar 217jvmJar { 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 */ 226metadataJar { setupManifest(it) } 227 228static def setupManifest(Jar jar) { 229 jar.manifest { 230 attributes "Premain-Class": "kotlinx.coroutines.debug.AgentPremain" 231 attributes "Can-Retransform-Classes": "true" 232 } 233} 234 235task jvmStressTest(type: Test, dependsOn: compileTestKotlinJvm) { 236 classpath = files { jvmTest.classpath } 237 testClassesDirs = files { jvmTest.testClassesDirs } 238 minHeapSize = '1g' 239 maxHeapSize = '1g' 240 include '**/*StressTest.*' 241 enableAssertions = true 242 testLogging.showStandardStreams = true 243 systemProperty 'kotlinx.coroutines.scheduler.keep.alive.sec', '100000' // any unpark problem hangs test 244 systemProperty 'kotlinx.coroutines.semaphore.segmentSize', '2' 245 systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '10' 246} 247 248task 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 257static void configureJvmForLincheck(task) { 258 task.minHeapSize = '1g' 259 task.maxHeapSize = '4g' // we may need more space for building an interleaving tree in the model checking mode 260 task.jvmArgs = ['--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED', // required for transformation 261 '--add-exports', 'java.base/jdk.internal.util=ALL-UNNAMED'] // in the model checking mode 262 task.systemProperty 'kotlinx.coroutines.semaphore.segmentSize', '2' 263 task.systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '1' // better for the model checking mode 264} 265 266// Always check additional test sets 267task moreTest(dependsOn: [jvmStressTest, jvmLincheckTest]) 268check.dependsOn moreTest 269 270tasks.jvmLincheckTest { 271 kover { 272 enabled = false // Always disabled, lincheck doesn't really support coverage 273 } 274} 275 276def 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 ] 282 283tasks.koverHtmlReport { 284 excludes = commonKoverExcludes 285} 286 287tasks.koverVerify { 288 excludes = commonKoverExcludes 289} 290 291task testsJar(type: Jar, dependsOn: jvmTestClasses) { 292 classifier = 'tests' 293 from compileTestKotlinJvm.destinationDir 294} 295 296artifacts { 297 archives testsJar 298} 299