Skip to content

Commit 79feaa0

Browse files
elizarovrecheej
authored andcommitted
Refactor mpp/native build, introduce "concurrent" source set, test launcher (Kotlin#2074)
New source sets: * "concurrent" source set is shared between "jvm" and "native" * "native" source set is subdivided into "nativeDarwin" (Apple) and "nativeOther" (Linux, etc) Native tests are launched in two variants: * A default "test" task runs tests with memory leak checker from "mainNoExit" entry point. * A special "backgroundTest" task runs tests in a background worker from "mainBackground" entry point. Other build improvement: * Modernize old-style IDEA-active hacks to kts helper. * Extract versions of JS test runner dependencies. * Remove redundant google repo reference from android tests.
1 parent dd83e0d commit 79feaa0

File tree

12 files changed

+206
-82
lines changed

12 files changed

+206
-82
lines changed

build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ buildscript {
8989

9090
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
9191

92-
// Hierarchical project structures are not fully supported in 1.3.7x MPP, enable conditionally for 1.4.x
93-
if (VersionNumber.parse(kotlin_version) > VersionNumber.parse("1.3.79")) {
92+
// todo:KLUDGE: Hierarchical project structures are not fully supported in IDEA, enable only for a regular built
93+
if (!Idea.active) {
9494
ext.set("kotlin.mpp.enableGranularSourceSetsMetadata", "true")
9595
}
9696

gradle.properties

+6-5
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ kotlin.js.compiler=both
3636
gradle_node_version=1.2.0
3737
node_version=8.9.3
3838
npm_version=5.7.1
39-
mocha_version=4.1.0
39+
mocha_version=6.2.2
4040
mocha_headless_chrome_version=1.8.2
41-
mocha_teamcity_reporter_version=2.2.2
42-
source_map_support_version=0.5.3
41+
mocha_teamcity_reporter_version=3.0.0
42+
source_map_support_version=0.5.16
43+
jsdom_version=15.2.1
44+
jsdom_global_version=3.0.2
4345

4446
# Settings
4547
kotlin.incremental.multiplatform=true
@@ -56,7 +58,6 @@ org.gradle.jvmargs=-Xmx2g
5658
# https://github.com/gradle/gradle/issues/11412
5759
systemProp.org.gradle.internal.publish.checksums.insecure=true
5860

59-
# This is commented out, and the property is set conditionally in build.gradle, because 1.3.71 doesn't work with it.
60-
# Once this property is set by default in new versions or 1.3.71 is dropped, either uncomment or remove this line.
61+
# todo:KLUDGE: This is commented out, and the property is set conditionally in build.gradle, because IDEA doesn't work with it.
6162
#kotlin.mpp.enableGranularSourceSetsMetadata=true
6263
kotlin.mpp.enableCompatibilityMetadataVariant=true

gradle/compile-native-multiplatform.gradle

+14-26
Original file line numberDiff line numberDiff line change
@@ -13,36 +13,24 @@ kotlin {
1313
}
1414

1515
targets {
16-
if (project.ext.ideaActive) {
17-
fromPreset(project.ext.ideaPreset, 'native')
18-
} else {
19-
addTarget(presets.linuxX64)
20-
addTarget(presets.iosArm64)
21-
addTarget(presets.iosArm32)
22-
addTarget(presets.iosX64)
23-
addTarget(presets.macosX64)
24-
addTarget(presets.mingwX64)
25-
addTarget(presets.tvosArm64)
26-
addTarget(presets.tvosX64)
27-
addTarget(presets.watchosArm32)
28-
addTarget(presets.watchosArm64)
29-
addTarget(presets.watchosX86)
30-
}
16+
addTarget(presets.linuxX64)
17+
addTarget(presets.iosArm64)
18+
addTarget(presets.iosArm32)
19+
addTarget(presets.iosX64)
20+
addTarget(presets.macosX64)
21+
addTarget(presets.mingwX64)
22+
addTarget(presets.tvosArm64)
23+
addTarget(presets.tvosX64)
24+
addTarget(presets.watchosArm32)
25+
addTarget(presets.watchosArm64)
26+
addTarget(presets.watchosX86)
3127
}
3228

3329
sourceSets {
3430
nativeMain { dependsOn commonMain }
35-
// Empty source set is required in order to have native tests task
36-
nativeTest {}
31+
nativeTest { dependsOn commonTest }
3732

38-
if (!project.ext.ideaActive) {
39-
configure(nativeMainSets) {
40-
dependsOn nativeMain
41-
}
42-
43-
configure(nativeTestSets) {
44-
dependsOn nativeTest
45-
}
46-
}
33+
configure(nativeMainSets) { dependsOn nativeMain }
34+
configure(nativeTestSets) { dependsOn nativeTest }
4735
}
4836
}

gradle/targets.gradle

-28
This file was deleted.

gradle/test-mocha-js.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ task testMochaChrome(type: NodeTask, dependsOn: prepareMochaChrome) {
8686
task installDependenciesMochaJsdom(type: NpmTask, dependsOn: [npmInstall]) {
8787
args = ['install',
8888
"mocha@$mocha_version",
89-
'jsdom@15.2.1',
90-
'jsdom-global@3.0.2',
89+
"jsdom@$jsdom_version",
90+
"jsdom-global@$jsdom_global_version",
9191
"source-map-support@$source_map_support_version",
9292
'--no-save']
9393
if (project.hasProperty("teamcity")) args += ["mocha-teamcity-reporter@$mocha_teamcity_reporter_version"]

kotlinx-coroutines-core/build.gradle

+100-18
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,60 @@
33
*/
44

55
apply plugin: 'org.jetbrains.kotlin.multiplatform'
6-
apply from: rootProject.file("gradle/targets.gradle")
76
apply from: rootProject.file("gradle/compile-jvm-multiplatform.gradle")
87
apply from: rootProject.file("gradle/compile-common.gradle")
98
apply from: rootProject.file("gradle/compile-js-multiplatform.gradle")
109
apply from: rootProject.file("gradle/compile-native-multiplatform.gradle")
1110
apply from: rootProject.file('gradle/publish-npm-js.gradle')
1211

12+
/* ==========================================================================
13+
Configure source sets structure for kotlinx-coroutines-core:
14+
15+
TARGETS SOURCE SETS
16+
------- ----------------------------------------------
17+
18+
js -----------------------------------------------------+
19+
|
20+
V
21+
jvm -------------------------------> concurrent ---> common
22+
^
23+
ios \ |
24+
macos | ---> nativeDarwin ---> native --+
25+
tvos | ^
26+
watchos / |
27+
|
28+
linux \ ---> nativeOther -------+
29+
mingw /
30+
31+
========================================================================== */
32+
33+
project.ext.sourceSetSuffixes = ["Main", "Test"]
34+
35+
void defineSourceSet(newName, dependsOn, includedInPred) {
36+
for (suffix in project.ext.sourceSetSuffixes) {
37+
def newSS = kotlin.sourceSets.maybeCreate(newName + suffix)
38+
for (dep in dependsOn) {
39+
newSS.dependsOn(kotlin.sourceSets[dep + suffix])
40+
}
41+
for (curSS in kotlin.sourceSets) {
42+
def curName = curSS.name
43+
if (curName.endsWith(suffix)) {
44+
def prefix = curName.substring(0, curName.length() - suffix.length())
45+
if (includedInPred(prefix)) curSS.dependsOn(newSS)
46+
}
47+
}
48+
}
49+
}
50+
51+
static boolean isNativeDarwin(String name) { return ["ios", "macos", "tvos", "watchos"].any { name.startsWith(it) } }
52+
static boolean isNativeOther(String name) { return ["linux", "mingw"].any { name.startsWith(it) } }
53+
54+
defineSourceSet("concurrent", ["common"]) { it in ["jvm", "native"] }
55+
defineSourceSet("nativeDarwin", ["native"]) { isNativeDarwin(it) }
56+
defineSourceSet("nativeOther", ["native"]) { isNativeOther(it) }
57+
58+
/* ========================================================================== */
59+
1360
/*
1461
* All platform plugins and configuration magic happens here instead of build.gradle
1562
* because JMV-only projects depend on core, thus core should always be initialized before configuration.
@@ -18,7 +65,7 @@ kotlin {
1865
configure(sourceSets) {
1966
def srcDir = name.endsWith('Main') ? 'src' : 'test'
2067
def platform = name[0..-5]
21-
kotlin.srcDir "$platform/$srcDir"
68+
kotlin.srcDirs = ["$platform/$srcDir"]
2269
if (name == "jvmMain") {
2370
resources.srcDirs = ["$platform/resources"]
2471
} else if (name == "jvmTest") {
@@ -31,12 +78,18 @@ kotlin {
3178
}
3279

3380
configure(targets) {
34-
def targetName = it.name
35-
compilations.all { compilation ->
36-
def compileTask = tasks.getByName(compilation.compileKotlinTaskName)
37-
// binary compatibility support
38-
if (targetName.contains("jvm") && compilation.compilationName == "main") {
39-
compileTask.kotlinOptions.freeCompilerArgs += ["-Xdump-declarations-to=${buildDir}/visibilities.json"]
81+
// Configure additional binaries and test runs -- one for each OS
82+
if (["macos", "linux", "mingw"].any { name.startsWith(it) }) {
83+
binaries {
84+
// Test for memory leaks using a special entry point that does not exit but returns from main
85+
binaries.getTest("DEBUG").freeCompilerArgs += ["-e", "kotlinx.coroutines.mainNoExit"]
86+
// Configure a separate test where code runs in background
87+
test("background", [org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType.DEBUG]) {
88+
freeCompilerArgs += ["-e", "kotlinx.coroutines.mainBackground"]
89+
}
90+
}
91+
testRuns {
92+
background { setExecutionSourceFrom(binaries.backgroundDebugTest) }
4093
}
4194
}
4295
}
@@ -54,23 +107,52 @@ compileKotlinMetadata {
54107
}
55108
}
56109

110+
// :KLUDGE: Idea.active: This is needed to workaround resolve problems after importing this project to IDEA
111+
def configureNativeSourceSetPreset(name, preset) {
112+
def hostMainCompilation = project.kotlin.targetFromPreset(preset).compilations.main
113+
// Look for platform libraries in "implementation" for default source set
114+
def implementationConfiguration = configurations[hostMainCompilation.defaultSourceSet.implementationMetadataConfigurationName]
115+
// Now find the libraries: Finds platform libs & stdlib, but platform declarations are still not resolved due to IDE bugs
116+
def hostNativePlatformLibs = files(
117+
provider {
118+
implementationConfiguration.findAll {
119+
it.path.endsWith(".klib") || it.absolutePath.contains("klib${File.separator}platform") || it.absolutePath.contains("stdlib")
120+
}
121+
}
122+
)
123+
// Add all those dependencies
124+
for (suffix in sourceSetSuffixes) {
125+
configure(kotlin.sourceSets[name + suffix]) {
126+
dependencies.add(implementationMetadataConfigurationName, hostNativePlatformLibs)
127+
}
128+
}
129+
}
130+
131+
// :KLUDGE: Idea.active: Configure platform libraries for native source sets when working in IDEA
132+
if (Idea.active) {
133+
def manager = project.ext.hostManager
134+
def linuxPreset = kotlin.presets.linuxX64
135+
def macosPreset = kotlin.presets.macosX64
136+
// linux should be always available (cross-compilation capable) -- use it as default
137+
assert manager.isEnabled(linuxPreset.konanTarget)
138+
// use macOS libs for nativeDarwin if available
139+
def macosAvailable = manager.isEnabled(macosPreset.konanTarget)
140+
// configure source sets
141+
configureNativeSourceSetPreset("native", linuxPreset)
142+
configureNativeSourceSetPreset("nativeOther", linuxPreset)
143+
configureNativeSourceSetPreset("nativeDarwin", macosAvailable ? macosPreset : linuxPreset)
144+
}
145+
57146
kotlin.sourceSets {
58147
jvmMain.dependencies {
59148
compileOnly "com.google.android:annotations:4.1.1.4"
60149
}
61150

62151
jvmTest.dependencies {
63-
// This is a workaround for https://youtrack.jetbrains.com/issue/KT-39037
64-
def excludingCurrentProject = { dependency ->
65-
def result = project.dependencies.create(dependency)
66-
result.exclude(module: project.name)
67-
return result
68-
}
69-
70-
api(excludingCurrentProject("org.jetbrains.kotlinx:lincheck:$lincheck_version"))
152+
api "org.jetbrains.kotlinx:lincheck:$lincheck_version"
71153
api "org.jetbrains.kotlinx:kotlinx-knit-test:$knit_version"
72154
api "com.esotericsoftware:kryo:4.0.0"
73-
implementation(excludingCurrentProject(project(":android-unit-tests")))
155+
implementation project(":android-unit-tests")
74156
}
75157
}
76158

@@ -97,7 +179,7 @@ jvmTest {
97179
enableAssertions = true
98180
systemProperty 'java.security.manager', 'kotlinx.coroutines.TestSecurityManager'
99181
// 'stress' is required to be able to run all subpackage tests like ":jvmTests --tests "*channels*" -Pstress=true"
100-
if (!project.ext.ideaActive && rootProject.properties['stress'] == null) {
182+
if (!Idea.active && rootProject.properties['stress'] == null) {
101183
exclude '**/*StressTest.*'
102184
}
103185
systemProperty 'kotlinx.coroutines.scheduler.keep.alive.sec', '100000' // any unpark problem hangs test
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/*
2+
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.coroutines
6+
7+
// It is used in the main sources of native-mt branch
8+
internal expect inline fun workerMain(block: () -> Unit)

kotlinx-coroutines-core/native/test/WorkerTest.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.coroutines
@@ -19,6 +19,7 @@ class WorkerTest : TestBase() {
1919
delay(1)
2020
}
2121
}.result
22+
worker.requestTermination()
2223
}
2324

2425
@Test
@@ -31,5 +32,6 @@ class WorkerTest : TestBase() {
3132
}.join()
3233
}
3334
}.result
35+
worker.requestTermination()
3436
}
3537
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.coroutines
6+
7+
import kotlinx.cinterop.*
8+
9+
internal actual inline fun workerMain(block: () -> Unit) {
10+
autoreleasepool {
11+
block()
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.coroutines
6+
7+
import platform.CoreFoundation.*
8+
import kotlin.native.concurrent.*
9+
import kotlin.native.internal.test.*
10+
import kotlin.system.*
11+
12+
// This is a separate entry point for tests in background
13+
fun mainBackground(args: Array<String>) {
14+
val worker = Worker.start(name = "main-background")
15+
worker.execute(TransferMode.SAFE, { args.freeze() }) {
16+
val result = testLauncherEntryPoint(it)
17+
exitProcess(result)
18+
}
19+
CFRunLoopRun()
20+
error("CFRunLoopRun should never return")
21+
}
22+
23+
// This is a separate entry point for tests with leak checker
24+
fun mainNoExit(args: Array<String>) {
25+
workerMain { // autoreleasepool to make sure interop objects are properly freed
26+
testLauncherEntryPoint(args)
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.coroutines
6+
7+
internal actual inline fun workerMain(block: () -> Unit) = block()

0 commit comments

Comments
 (0)