From 5e212539409e4ef85b8d9181edaa7e86a31ed6bd Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Fri, 21 Sep 2018 14:17:07 +0300 Subject: [PATCH] Provide matching strategy for attributes + fix tests --- .../internal/MatchingStrategies.kt | 67 +++++++++++++++++++ .../plugins/KotlinNativeBasePlugin.kt | 19 ++++++ .../test/kotlin/ExperimentalPluginTests.kt | 15 ++--- 3 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/internal/MatchingStrategies.kt diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/internal/MatchingStrategies.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/internal/MatchingStrategies.kt new file mode 100644 index 00000000000..4f594d010f4 --- /dev/null +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/internal/MatchingStrategies.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.gradle.plugin.experimental.internal + +import org.gradle.api.attributes.* + +open class Compatible: AttributeCompatibilityRule { + override fun execute(details: CompatibilityCheckDetails) = details.compatible() +} + +open class PreferValue(val defaultPreferred: Boolean): AttributeDisambiguationRule { + override fun execute(details: MultipleCandidatesDetails) = with(details) { + val preferredValue = consumerValue ?: defaultPreferred + + if (candidateValues.contains(preferredValue)) { + closestMatch(preferredValue) + } else { + closestMatch(!preferredValue) + } + } +} + +open class DebuggableDisambiguation: PreferValue(false) +open class OptimizedDisambiguation: PreferValue(false) + +open class UsageCompatibility: AttributeCompatibilityRule { + override fun execute(details: CompatibilityCheckDetails) = with(details) { + val requested = consumerValue?.name + val provided = producerValue?.name + + when { + requested == null -> compatible() + requested == Usage.JAVA_API && (provided == Usage.JAVA_API || provided == KotlinNativeUsage.KLIB) -> { + compatible() + } + requested == provided -> compatible() + } + } +} + +open class UsageDisambiguation: AttributeDisambiguationRule { + override fun execute(details: MultipleCandidatesDetails): Unit = with(details) { + val usagePriority = listOf(Usage.JAVA_API, KotlinNativeUsage.KLIB) + usagePriority.forEach { usage -> + val found = candidateValues.find { it.name == usage } + if (found != null) { + closestMatch(found) + return + } + } + } +} + diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/plugins/KotlinNativeBasePlugin.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/plugins/KotlinNativeBasePlugin.kt index a1fa28a089e..a3348dcf53a 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/plugins/KotlinNativeBasePlugin.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/plugins/KotlinNativeBasePlugin.kt @@ -20,6 +20,8 @@ import org.gradle.api.DefaultTask import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.Task +import org.gradle.api.attributes.AttributeCompatibilityRule +import org.gradle.api.attributes.Usage import org.gradle.api.file.RegularFileProperty import org.gradle.api.internal.FeaturePreviews import org.gradle.api.internal.project.ProjectInternal @@ -28,6 +30,7 @@ import org.gradle.api.plugins.BasePlugin import org.gradle.api.plugins.HelpTasksPlugin import org.gradle.api.tasks.TaskContainer import org.gradle.language.base.plugins.LifecycleBasePlugin +import org.gradle.language.cpp.CppBinary import org.gradle.language.plugins.NativeBasePlugin import org.gradle.nativeplatform.test.tasks.RunTestExecutable import org.gradle.util.GradleVersion @@ -279,6 +282,21 @@ class KotlinNativeBasePlugin: Plugin { return result } + private fun Project.setUpMatchingStrategy(): Unit = with(dependencies.attributesSchema) { + attribute(CppBinary.DEBUGGABLE_ATTRIBUTE).apply { + compatibilityRules.add(Compatible::class.java) + disambiguationRules.add(DebuggableDisambiguation::class.java) + } + attribute(CppBinary.OPTIMIZED_ATTRIBUTE).apply { + compatibilityRules.add(Compatible::class.java) + disambiguationRules.add(OptimizedDisambiguation::class.java) + } + attribute(Usage.USAGE_ATTRIBUTE).apply { + compatibilityRules.add(UsageCompatibility::class.java) + disambiguationRules.add(UsageDisambiguation::class.java) + } + } + override fun apply(project: ProjectInternal): Unit = with(project) { // TODO: Deal with compiler downloading. // Apply base plugins @@ -289,6 +307,7 @@ class KotlinNativeBasePlugin: Plugin { checkGradleVersion() addCompilerDownloadingTask() + setUpMatchingStrategy() addCompilationTasks() addInteropTasks() addTargetInfoTask() diff --git a/tools/kotlin-native-gradle-plugin/src/test/kotlin/ExperimentalPluginTests.kt b/tools/kotlin-native-gradle-plugin/src/test/kotlin/ExperimentalPluginTests.kt index d0e3a03d20d..e991def5595 100644 --- a/tools/kotlin-native-gradle-plugin/src/test/kotlin/ExperimentalPluginTests.kt +++ b/tools/kotlin-native-gradle-plugin/src/test/kotlin/ExperimentalPluginTests.kt @@ -106,9 +106,7 @@ class ExperimentalPluginTests { val compileReleaseResult = project.createRunner().withArguments("compileReleaseKotlinNative").build() assertEquals(TaskOutcome.SUCCESS, compileReleaseResult.task(":compileReleaseKotlinNative")?.outcome) - assertEquals(TaskOutcome.SUCCESS, compileReleaseResult.task(":library:compileReleaseKotlinNative")?.outcome) - assertTrue(projectDirectory.resolve("build/exe/main/release/test.$exeSuffix").exists()) - assertTrue(libraryDir.resolve("build/lib/main/release/library.klib").exists()) + assertEquals(TaskOutcome.UP_TO_DATE, compileReleaseResult.task(":library:compileDebugKotlinNative")?.outcome) } @Test @@ -451,7 +449,7 @@ class ExperimentalPluginTests { """.trimIndent()) } - val outputKinds = arrayOf(OutputKind.EXECUTABLE, OutputKind.KLIBRARY, OutputKind.FRAMEWORK) + val outputKinds = arrayOf(OutputKind.EXECUTABLE, OutputKind.FRAMEWORK) val buildTypes = arrayOf("Debug", "Release") val targets = arrayOf(HostManager.host, KonanTarget.WASM32) @@ -460,7 +458,7 @@ class ExperimentalPluginTests { buildTypes.map { type -> ":compile${type}${kind.name.toLowerCase().capitalize()}${target.name.capitalize()}KotlinNative" } - } + } + ":compileDebug${OutputKind.KLIBRARY.name.toLowerCase().capitalize()}${target.name.capitalize()}KotlinNative" } val result1 = project.createRunner().withArguments("assemble").build() @@ -695,7 +693,6 @@ class ExperimentalPluginTests { rootProject.createRunner().withArguments(":libFoo:publish", ":libBar:publish").build() assertFileExists("repo/test/libFoo_debug/1.0/libFoo_debug-1.0-interop-mystdio.klib") - assertFileExists("repo/test/libFoo_release/1.0/libFoo_release-1.0-interop-mystdio.klib") // A dependency on a published library rootProject.buildFile.writeText(""" @@ -809,13 +806,13 @@ class ExperimentalPluginTests { val nameToArtifact = model.artifacts.map { it.name to it }.toMap() - val buildTypes = listOf("debug", "release") val kinds = listOf(OutputKind.EXECUTABLE, OutputKind.KLIBRARY) val targets = listOf(HostManager.host, KonanTarget.WASM32) // Production binaries - buildTypes.forEach { buildType -> - kinds.forEach { kind -> + kinds.forEach { kind -> + val buildTypes = if (kind == OutputKind.KLIBRARY) listOf("debug") else listOf("debug", "release") + buildTypes.forEach { buildType -> targets.forEach { target -> val suffix = "${buildType.capitalize()}${kind.name.toLowerCase().capitalize()}${target.name.capitalize()}" val artifact = nameToArtifact.getValue("main$suffix")