diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportFactory.kt index a153a8c75cd..7e639edab86 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportFactory.kt @@ -5,11 +5,14 @@ package org.jetbrains.kotlin.gradle.plugin.ide +import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.SourceSetConstraint import org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers.* import org.jetbrains.kotlin.gradle.plugin.ide.dependencyTransformers.IdePlatformStdlibCommonDependencyFilter +import org.jetbrains.kotlin.gradle.targets.native.internal.getCommonizerTarget +import org.jetbrains.kotlin.gradle.plugin.ide.dependencyTransformers.UnusedSourcesAndDocumentationFilter internal fun IdeMultiplatformImport(extension: KotlinProjectExtension): IdeMultiplatformImport { return IdeMultiplatformImportImpl(extension).apply { @@ -84,6 +87,27 @@ internal fun IdeMultiplatformImport(extension: KotlinProjectExtension): IdeMulti level = IdeMultiplatformImport.DependencyResolutionLevel.Default ) + registerDependencyResolver( + resolver = IdePlatformCinteropDependencyResolver, + constraint = { sourceSet -> SourceSetConstraint.isLeaf(sourceSet) && SourceSetConstraint.isNative(sourceSet) }, + phase = IdeMultiplatformImport.DependencyResolutionPhase.BinaryDependencyResolution, + level = IdeMultiplatformImport.DependencyResolutionLevel.Default, + ) + + registerDependencyResolver( + resolver = IdeCommonizedCinteropDependencyResolver, + constraint = { sourceSet -> SourceSetConstraint.isNative(sourceSet) && getCommonizerTarget(sourceSet) is SharedCommonizerTarget }, + phase = IdeMultiplatformImport.DependencyResolutionPhase.BinaryDependencyResolution, + level = IdeMultiplatformImport.DependencyResolutionLevel.Default, + ) + + registerDependencyResolver( + resolver = IdeCInteropMetadataDependencyClasspathResolver, + constraint = { SourceSetConstraint.isNative(it) && !SourceSetConstraint.isLeaf(it) }, + phase = IdeMultiplatformImport.DependencyResolutionPhase.BinaryDependencyResolution, + level = IdeMultiplatformImport.DependencyResolutionLevel.Default, + ) + /* Register resolution of dependencies for jvm+android dependencies: This resolver will resolve dependencies visible to the source set from a 'jvm' perspective. diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCInteropMetadataDependencyClasspathResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCInteropMetadataDependencyClasspathResolver.kt new file mode 100644 index 00000000000..84df2ed224f --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCInteropMetadataDependencyClasspathResolver.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers + +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver +import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet +import org.jetbrains.kotlin.gradle.targets.native.internal.createCInteropMetadataDependencyClasspathForIde + +object IdeCInteropMetadataDependencyClasspathResolver : IdeDependencyResolver { + override fun resolve(sourceSet: KotlinSourceSet): Set { + if (sourceSet !is DefaultKotlinSourceSet) return emptySet() + + val project = sourceSet.project + // TODO (kirpichenkov): sensitive to task being registered for the source set + val cinteropFiles = project.createCInteropMetadataDependencyClasspathForIde(sourceSet) + return resolveCinteropDependencies(project, cinteropFiles) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCommonizedCinteropDependencyResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCommonizedCinteropDependencyResolver.kt new file mode 100644 index 00000000000..b9b14539756 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCommonizedCinteropDependencyResolver.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers + +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver +import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet +import org.jetbrains.kotlin.gradle.targets.native.internal.cinteropCommonizerDependencies + +object IdeCommonizedCinteropDependencyResolver : IdeDependencyResolver { + override fun resolve(sourceSet: KotlinSourceSet): Set { + if (sourceSet !is DefaultKotlinSourceSet) return emptySet() + + val project = sourceSet.project + val cinteropFiles = project.cinteropCommonizerDependencies(sourceSet) + return resolveCinteropDependencies(project, cinteropFiles) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdePlatformCinteropDependencyResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdePlatformCinteropDependencyResolver.kt new file mode 100644 index 00000000000..450c9761184 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdePlatformCinteropDependencyResolver.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers + +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation +import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.sources.internal +import org.jetbrains.kotlin.gradle.targets.native.internal.getAllCInteropOutputFiles +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +object IdePlatformCinteropDependencyResolver : IdeDependencyResolver { + override fun resolve(sourceSet: KotlinSourceSet): Set { + if (sourceSet !is DefaultKotlinSourceSet) return emptySet() + val project = sourceSet.project + + val nativeCompilation = sourceSet.internal.compilations.singleOrNull().safeAs() ?: return emptySet() + val cinteropFiles = project.getAllCInteropOutputFiles(nativeCompilation) + + return resolveCinteropDependencies(project, cinteropFiles) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeProjectToProjectCInteropDependencyResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeProjectToProjectCInteropDependencyResolver.kt new file mode 100644 index 00000000000..0bef866e134 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeProjectToProjectCInteropDependencyResolver.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers + +import org.gradle.api.artifacts.component.ProjectComponentIdentifier +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver + +object IdeProjectToProjectCInteropDependencyResolver : IdeDependencyResolver { + private val platformDependencyResolver = IdePlatformDependencyResolver( + resolvedArtifactHandler = handler@{ artifact, context -> + val identifier = artifact.id.componentIdentifier as? ProjectComponentIdentifier + ?: return@handler null + + val projectArtifact = context.allArtifacts.filter { otherArtifact -> + val otherIdentifier = otherArtifact.id.componentIdentifier + otherIdentifier is ProjectComponentIdentifier && otherIdentifier.projectName == identifier.projectName + } + + null + } + ) + + override fun resolve(sourceSet: KotlinSourceSet): Set { + return platformDependencyResolver.resolve(sourceSet) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/resolveCinteropDependency.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/resolveCinteropDependency.kt new file mode 100644 index 00000000000..51c397badfb --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/resolveCinteropDependency.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers + +import org.gradle.api.Project +import org.gradle.api.file.FileCollection +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryCoordinates +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency +import org.jetbrains.kotlin.gradle.idea.tcs.extras.klibExtra +import org.jetbrains.kotlin.gradle.plugin.ide.KlibExtra +import org.jetbrains.kotlin.konan.file.File +import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION +import org.jetbrains.kotlin.library.ToolingSingleFileKlibResolveStrategy +import org.jetbrains.kotlin.library.commonizerTarget +import org.jetbrains.kotlin.library.resolveSingleFileKlib + +fun resolveCinteropDependencies(project: Project, cinteropFiles: FileCollection): Set { + return cinteropFiles.files + .filter { it.isDirectory || it.extension == KLIB_FILE_EXTENSION } + .mapNotNullTo(mutableSetOf()) { libraryFile -> + createCinteropLibraryDependency(project, libraryFile) + } +} + +private fun createCinteropLibraryDependency(project: Project, libraryFile: java.io.File): IdeaKotlinResolvedBinaryDependency? { + val library = try { + resolveSingleFileKlib( + libraryFile = File(libraryFile.absolutePath), + strategy = ToolingSingleFileKlibResolveStrategy + ) + } catch (error: Throwable) { + project.logger.error("Failed to resolve library ${libraryFile.path}", error) + return null + } + + return IdeaKotlinResolvedBinaryDependency( + binaryType = IdeaKotlinDependency.CLASSPATH_BINARY_TYPE, + binaryFile = libraryFile, + coordinates = IdeaKotlinBinaryCoordinates( + group = project.group.toString(), + module = library.moduleDisplayName, + version = null, + sourceSetName = library.commonizerTarget + ), + ).apply { + klibExtra = KlibExtra(library) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/utils.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/utils.kt index ee1aecd1471..729c51c1bc1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/utils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/utils.kt @@ -9,8 +9,17 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution import org.jetbrains.kotlin.gradle.plugin.mpp.metadataDependencyResolutionsOrEmpty import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope +import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope.* +import org.jetbrains.kotlin.library.KotlinLibrary +import org.jetbrains.kotlin.library.packageFqName +import org.jetbrains.kotlin.library.shortName +import org.jetbrains.kotlin.library.uniqueName internal inline fun KotlinSourceSet.resolveMetadata(): List { if (this !is DefaultKotlinSourceSet) return emptyList() return compileDependenciesTransformation.metadataDependencyResolutionsOrEmpty.filterIsInstance() } + +internal val KotlinLibrary.moduleDisplayName: String + get() = packageFqName ?: shortName ?: uniqueName diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerDependencies.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerDependencies.kt index 5a16107ef6a..73f2459b1e1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerDependencies.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerDependencies.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.gradle.targets.native.internal import org.gradle.api.Project +import org.gradle.api.file.FileCollection import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation @@ -42,16 +43,20 @@ private fun Project.setupCInteropCommonizerDependenciesForCompilation(compilatio * The copying task prevent red code within the IDE after cleaning the build output. */ private fun Project.setupCInteropCommonizerDependenciesForIde(sourceSet: DefaultKotlinSourceSet) { - val cinteropCommonizerTask = project.copyCommonizeCInteropForIdeTask ?: return + addIntransitiveMetadataDependencyIfPossible(sourceSet, cinteropCommonizerDependencies(sourceSet)) +} - addIntransitiveMetadataDependencyIfPossible(sourceSet, filesProvider files@{ +internal fun Project.cinteropCommonizerDependencies(sourceSet: DefaultKotlinSourceSet): FileCollection { + val cinteropCommonizerTask = project.copyCommonizeCInteropForIdeTask ?: return project.files() + + return filesProvider { val directlyDependent = CInteropCommonizerDependent.from(sourceSet) val associateDependent = CInteropCommonizerDependent.fromAssociateCompilations(sourceSet) listOfNotNull(directlyDependent, associateDependent).map { cinteropCommonizerDependent -> cinteropCommonizerTask.get().commonizedOutputLibraries(cinteropCommonizerDependent) } - }) + } } private fun Project.setupCInteropTransformCompositeMetadataDependenciesForIde(sourceSet: DefaultKotlinSourceSet) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropPropagatedDependencies.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropPropagatedDependencies.kt index f9e5bcc8e34..46669f1b437 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropPropagatedDependencies.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropPropagatedDependencies.kt @@ -81,7 +81,7 @@ private fun Project.getPropagatedCInteropDependenciesOrEmpty(compilation: Kotlin getAllCInteropOutputFiles(platformCompilation) } -private fun Project.getAllCInteropOutputFiles(compilation: KotlinNativeCompilation): FileCollection { +internal fun Project.getAllCInteropOutputFiles(compilation: KotlinNativeCompilation): FileCollection { val cinteropTasks = compilation.cinterops.map { interop -> interop.interopProcessingTaskName } .mapNotNull { taskName -> tasks.findByName(taskName) as? CInteropProcess }