• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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