blob: 9791b445bf5d2239fe1372f075b79d44a8231dbb [file] [log] [blame]
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
apply plugin: 'org.jetbrains.kotlin.multiplatform'
apply plugin: 'org.jetbrains.dokka'
apply from: rootProject.file("gradle/compile-jvm-multiplatform.gradle")
apply from: rootProject.file("gradle/compile-common.gradle")
if (rootProject.ext.native_targets_enabled) {
apply from: rootProject.file("gradle/compile-native-multiplatform.gradle")
}
apply from: rootProject.file("gradle/compile-js-multiplatform.gradle")
apply from: rootProject.file('gradle/publish-npm-js.gradle')
apply from: rootProject.file('gradle/dokka.gradle.kts')
apply from: rootProject.file('gradle/publish.gradle')
/* ==========================================================================
Configure source sets structure for kotlinx-coroutines-core:
TARGETS SOURCE SETS
------- ----------------------------------------------
js -----------------------------------------------------+
|
V
jvm -------------------------------> concurrent ---> common
^
ios \ |
macos | ---> nativeDarwin ---> native --+
tvos | ^
watchos / |
|
linux \ ---> nativeOther -------+
mingw /
========================================================================== */
project.ext.sourceSetSuffixes = ["Main", "Test"]
void defineSourceSet(newName, dependsOn, includedInPred) {
for (suffix in project.ext.sourceSetSuffixes) {
def newSS = kotlin.sourceSets.maybeCreate(newName + suffix)
for (dep in dependsOn) {
newSS.dependsOn(kotlin.sourceSets[dep + suffix])
}
for (curSS in kotlin.sourceSets) {
def curName = curSS.name
if (curName.endsWith(suffix)) {
def prefix = curName.substring(0, curName.length() - suffix.length())
if (includedInPred(prefix)) curSS.dependsOn(newSS)
}
}
}
}
static boolean isNativeDarwin(String name) { return ["ios", "macos", "tvos", "watchos"].any { name.startsWith(it) } }
static boolean isNativeOther(String name) { return ["linux", "mingw"].any { name.startsWith(it) } }
defineSourceSet("concurrent", ["common"]) { it in ["jvm", "native"] }
if (rootProject.ext.native_targets_enabled) {
defineSourceSet("nativeDarwin", ["native"]) { isNativeDarwin(it) }
defineSourceSet("nativeOther", ["native"]) { isNativeOther(it) }
}
/* ========================================================================== */
/*
* All platform plugins and configuration magic happens here instead of build.gradle
* because JMV-only projects depend on core, thus core should always be initialized before configuration.
*/
kotlin {
sourceSets.forEach {
SourceSetsKt.configureMultiplatform(it)
}
/*
* Configure four test runs:
* 1) Old memory model, Main thread
* 2) New memory model, Main thread
* 3) Old memory model, BG thread
* 4) New memory model, BG thread (required for Dispatchers.Main tests on Darwin)
*
* All new MM targets are build with optimize = true to have stress tests properly run.
*/
targets.withType(org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithTests.class).configureEach {
binaries {
// Test for memory leaks using a special entry point that does not exit but returns from main
binaries.getTest("DEBUG").freeCompilerArgs += ["-e", "kotlinx.coroutines.mainNoExit"]
}
binaries.test("newMM", [DEBUG]) {
def thisTest = it
freeCompilerArgs += ["-e", "kotlinx.coroutines.mainNoExit"]
optimized = true
binaryOptions["memoryModel"] = "experimental"
testRuns.create("newMM") {
setExecutionSourceFrom(thisTest)
// A hack to get different suffixes in the aggregated report.
executionTask.configure { targetName = "$targetName new MM" }
}
}
binaries.test("worker", [DEBUG]) {
def thisTest = it
freeCompilerArgs += ["-e", "kotlinx.coroutines.mainBackground"]
testRuns.create("worker") {
setExecutionSourceFrom(thisTest)
executionTask.configure { targetName = "$targetName worker" }
}
}
binaries.test("workerWithNewMM", [DEBUG]) {
def thisTest = it
optimized = true
freeCompilerArgs += ["-e", "kotlinx.coroutines.mainBackground"]
binaryOptions["memoryModel"] = "experimental"
testRuns.create("workerWithNewMM") {
setExecutionSourceFrom(thisTest)
executionTask.configure { targetName = "$targetName worker with new MM" }
}
}
}
jvm {
// For animal sniffer
withJava()
}
}
configurations {
configureKotlinJvmPlatform(kotlinCompilerPluginClasspath)
}
// Update module name for metadata artifact to avoid conflicts
// see https://github.com/Kotlin/kotlinx.coroutines/issues/1797
compileKotlinMetadata {
kotlinOptions {
freeCompilerArgs += ["-module-name", "kotlinx-coroutines-core-common"]
}
}
// :KLUDGE: Idea.active: This is needed to workaround resolve problems after importing this project to IDEA
def configureNativeSourceSetPreset(name, preset) {
def hostMainCompilation = project.kotlin.targetFromPreset(preset).compilations.main
// Look for platform libraries in "implementation" for default source set
def implementationConfiguration = configurations[hostMainCompilation.defaultSourceSet.implementationMetadataConfigurationName]
// Now find the libraries: Finds platform libs & stdlib, but platform declarations are still not resolved due to IDE bugs
def hostNativePlatformLibs = files(
provider {
implementationConfiguration.findAll {
it.path.endsWith(".klib") || it.absolutePath.contains("klib${File.separator}platform") || it.absolutePath.contains("stdlib")
}
}
)
// Add all those dependencies
for (suffix in sourceSetSuffixes) {
configure(kotlin.sourceSets[name + suffix]) {
dependencies.add(implementationMetadataConfigurationName, hostNativePlatformLibs)
}
}
}
// :KLUDGE: Idea.active: Configure platform libraries for native source sets when working in IDEA
if (Idea.active && rootProject.ext.native_targets_enabled) {
def manager = project.ext.hostManager
def linuxPreset = kotlin.presets.linuxX64
def macosPreset = kotlin.presets.macosX64
// linux should be always available (cross-compilation capable) -- use it as default
assert manager.isEnabled(linuxPreset.konanTarget)
// use macOS libs for nativeDarwin if available
def macosAvailable = manager.isEnabled(macosPreset.konanTarget)
// configure source sets
configureNativeSourceSetPreset("native", linuxPreset)
configureNativeSourceSetPreset("nativeOther", linuxPreset)
configureNativeSourceSetPreset("nativeDarwin", macosAvailable ? macosPreset : linuxPreset)
}
kotlin.sourceSets {
jvmMain.dependencies {
compileOnly "com.google.android:annotations:4.1.1.4"
}
jvmTest.dependencies {
api "org.jetbrains.kotlinx:lincheck:$lincheck_version"
api "org.jetbrains.kotlinx:kotlinx-knit-test:$knit_version"
implementation project(":android-unit-tests")
}
}
jvmTest {
minHeapSize = '1g'
maxHeapSize = '1g'
enableAssertions = true
if (!Idea.active) {
// We should not set this security manager when `jvmTest`
// is invoked by IntelliJ IDEA since we need to pass
// system properties for Lincheck and stress tests.
// TODO Remove once IDEA is smart enough to select between `jvmTest`/`jvmStressTest`/`jvmLincheckTest` #KTIJ-599
systemProperty 'java.security.manager', 'kotlinx.coroutines.TestSecurityManager'
}
// 'stress' is required to be able to run all subpackage tests like ":jvmTests --tests "*channels*" -Pstress=true"
if (!Idea.active && rootProject.properties['stress'] == null) {
exclude '**/*LincheckTest.*'
exclude '**/*StressTest.*'
}
if (Idea.active) {
// Configure the IDEA runner for Lincheck
configureJvmForLincheck(jvmTest)
}
}
// Setup manifest for kotlinx-coroutines-core-jvm.jar
jvmJar { setupManifest(it) }
/*
* Setup manifest for kotlinx-coroutines-core.jar
* This is convenient for users that pass -javaagent arg manually and also is a workaround #2619 and KTIJ-5659.
* This manifest contains reference to AgentPremain that belongs to
* kotlinx-coroutines-core-jvm, but our resolving machinery guarantees that
* any JVM project that depends on -core artifact also depends on -core-jvm one.
*/
metadataJar { setupManifest(it) }
static def setupManifest(Jar jar) {
jar.manifest {
attributes "Premain-Class": "kotlinx.coroutines.debug.AgentPremain"
attributes "Can-Retransform-Classes": "true"
}
}
task jvmStressTest(type: Test, dependsOn: compileTestKotlinJvm) {
classpath = files { jvmTest.classpath }
testClassesDirs = files { jvmTest.testClassesDirs }
minHeapSize = '1g'
maxHeapSize = '1g'
include '**/*StressTest.*'
enableAssertions = true
testLogging.showStandardStreams = true
systemProperty 'kotlinx.coroutines.scheduler.keep.alive.sec', '100000' // any unpark problem hangs test
systemProperty 'kotlinx.coroutines.semaphore.segmentSize', '2'
systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '10'
}
task jvmLincheckTest(type: Test, dependsOn: compileTestKotlinJvm) {
classpath = files { jvmTest.classpath }
testClassesDirs = files { jvmTest.testClassesDirs }
include '**/*LincheckTest.*'
enableAssertions = true
testLogging.showStandardStreams = true
configureJvmForLincheck(jvmLincheckTest)
}
static void configureJvmForLincheck(task) {
task.minHeapSize = '1g'
task.maxHeapSize = '4g' // we may need more space for building an interleaving tree in the model checking mode
task.jvmArgs = ['--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED', // required for transformation
'--add-exports', 'java.base/jdk.internal.util=ALL-UNNAMED'] // in the model checking mode
task.systemProperty 'kotlinx.coroutines.semaphore.segmentSize', '2'
task.systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '1' // better for the model checking mode
}
// Always check additional test sets
task moreTest(dependsOn: [jvmStressTest, jvmLincheckTest])
check.dependsOn moreTest
tasks.jvmLincheckTest {
kover {
enabled = false // Always disabled, lincheck doesn't really support coverage
}
}
def commonKoverExcludes =
["kotlinx.coroutines.debug.*", // Tested by debug module
"kotlinx.coroutines.channels.ChannelsKt__DeprecatedKt.*", // Deprecated
"kotlinx.coroutines.scheduling.LimitingDispatcher", // Deprecated
"kotlinx.coroutines.scheduling.ExperimentalCoroutineDispatcher" // Deprecated
]
tasks.koverHtmlReport {
excludes = commonKoverExcludes
}
tasks.koverVerify {
excludes = commonKoverExcludes
}
task testsJar(type: Jar, dependsOn: jvmTestClasses) {
classifier = 'tests'
from compileTestKotlinJvm.destinationDir
}
artifacts {
archives testsJar
}