From 9acb9ff2b74b38dbbeae85a9d335ed467876bbda Mon Sep 17 00:00:00 2001 From: Anton Lakotka Date: Mon, 22 Jan 2024 16:39:54 +0100 Subject: [PATCH] [Gradle] Pass stdlib explicitly as K/native dependency. Keep original... ... platform dependencies while filter out them from actual compiler invocation. So kotlin native compiler will provide them implicitly from kotlin native bundle. Since K/Native compiler is not yet optimised to consume platform dependencies explicitly and simply slow. More details in related issue: KT-61559 ^KT-61430 Verification Pending ^KT-61559 Verification Pending --- .../plugin/registerKotlinPluginExtensions.kt | 1 + ...tlinNativePlatformDependenciesAndStdlib.kt | 26 +++++++++- .../targets/native/tasks/KotlinNativeLink.kt | 10 +++- .../targets/native/tasks/KotlinNativeTasks.kt | 22 +++++++-- .../kotlin/gradle/utils/fileUtils.kt | 6 +++ .../KotlinNativeCompileArgumentsTest.kt | 49 +++++++++++++++++++ 6 files changed, 105 insertions(+), 9 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt index 5babe451bba..87ab6359ecb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt @@ -72,6 +72,7 @@ internal fun Project.registerKotlinPluginExtensions() { register(project, KotlinRegisterCompilationArchiveTasksExtension) register(project, IdeMultiplatformImportActionSetupAction) register(project, KotlinLLDBScriptSetupAction) + register(project, ExcludeDefaultPlatformDependenciesFromKotlinNativeCompileTasks) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/SetupKotlinNativePlatformDependenciesAndStdlib.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/SetupKotlinNativePlatformDependenciesAndStdlib.kt index 911063ccce6..4812a918b00 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/SetupKotlinNativePlatformDependenciesAndStdlib.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/SetupKotlinNativePlatformDependenciesAndStdlib.kt @@ -9,13 +9,18 @@ import org.gradle.api.Project import org.gradle.api.file.FileCollection import org.jetbrains.kotlin.commonizer.* import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull +import org.jetbrains.kotlin.gradle.plugin.KotlinProjectSetupAction import org.jetbrains.kotlin.gradle.plugin.KotlinProjectSetupCoroutine import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinNativeCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSideEffectCoroutine import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet import org.jetbrains.kotlin.gradle.targets.metadata.isNativeSourceSet +import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile +import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink +import org.jetbrains.kotlin.gradle.tasks.withType import org.jetbrains.kotlin.gradle.utils.filesProvider import org.jetbrains.kotlin.gradle.utils.konanDistribution +import org.jetbrains.kotlin.konan.target.KonanTarget import java.io.File internal val SetupKotlinNativePlatformDependenciesAndStdlib = @@ -31,6 +36,20 @@ internal val SetupKotlinNativePlatformDependenciesAndStdlib = compilation.compileDependencyFiles += stdlib } +internal val ExcludeDefaultPlatformDependenciesFromKotlinNativeCompileTasks = KotlinProjectSetupAction { + tasks.withType().configureEach { task -> + @Suppress("DEPRECATION") + val konanTarget = task.compilation.konanTarget + task.excludeOriginalPlatformLibraries = task.project.getOriginalPlatformLibrariesFor(konanTarget) + } + tasks.withType().configureEach { task -> + // metadata compilations should have commonized platform libraries in the classpath i.e. they are not "original" + if (task.isMetadataCompilation) return@configureEach + val konanTarget = task.konanTarget + task.excludeOriginalPlatformLibraries = task.project.getOriginalPlatformLibrariesFor(konanTarget) + } +} + internal val SetupKotlinNativePlatformDependenciesForLegacyImport = KotlinProjectSetupCoroutine { val multiplatform = multiplatformExtensionOrNull ?: return@KotlinProjectSetupCoroutine val sourceSets = multiplatform @@ -60,8 +79,11 @@ internal fun Project.getNativeDistributionDependencies(target: CommonizerTarget) } } -private fun Project.getOriginalPlatformLibrariesFor(target: LeafCommonizerTarget): FileCollection = project.filesProvider { - konanDistribution.platformLibsDir.resolve(target.konanTarget.name).listLibraryFiles().toSet() +private fun Project.getOriginalPlatformLibrariesFor(target: LeafCommonizerTarget): FileCollection = + getOriginalPlatformLibrariesFor(target.konanTarget) + +private fun Project.getOriginalPlatformLibrariesFor(konanTarget: KonanTarget): FileCollection = project.filesProvider { + konanDistribution.platformLibsDir.resolve(konanTarget.name).listLibraryFiles().toSet() } private fun getCommonizedPlatformLibrariesFor(rootOutputDirectory: File, target: SharedCommonizerTarget): List { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeLink.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeLink.kt index 2f1000616af..39a7b7dd9ab 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeLink.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeLink.kt @@ -78,6 +78,11 @@ constructor( } ) + @get:InputFiles + @get:Optional + @get:PathSensitive(PathSensitivity.RELATIVE) + internal var excludeOriginalPlatformLibraries: FileCollection? = null + @get:Input val outputKind: CompilerOutputKind by lazyConvention { binary.outputKind.compilerOutputKind } @@ -239,7 +244,6 @@ constructor( args.produce = outputKind.name.toLowerCaseAsciiOnly() args.multiPlatform = true args.noendorsedlibs = true - args.nodefaultlibs = true args.nostdlib = true args.pluginOptions = compilerPlugins.flatMap { it.options.arguments }.toTypedArray() args.generateTestRunner = processTests @@ -263,7 +267,9 @@ constructor( } dependencyClasspath { args -> - args.libraries = runSafe { libraries.files.filterKlibsPassedToCompiler() }?.toPathsArray() + args.libraries = runSafe { + libraries.exclude(excludeOriginalPlatformLibraries).files.filterKlibsPassedToCompiler() + }?.toPathsArray() args.exportedLibraries = runSafe { exportLibraries.files.filterKlibsPassedToCompiler() }?.toPathsArray() args.friendModules = runSafe { friendModule.files.toList().takeIf { it.isNotEmpty() } } ?.joinToString(File.pathSeparator) { it.absolutePath } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index 5ddb08c0157..2731604c1b0 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -157,7 +157,7 @@ abstract class AbstractKotlinNativeCompile< internal abstract val explicitApiMode: Property @get:Internal - protected val konanTarget by project.provider { + internal val konanTarget by project.provider { when (val compilation = compilation) { is KotlinCompilationInfo.TCS -> (compilation.compilation as AbstractKotlinNativeCompilation).konanTarget } @@ -425,6 +425,16 @@ internal constructor( ) // endregion. + /** + * This is utility property that contains list of native platform dependencies that are present in [compileDependencyFiles] + * but should be excluded from actual classpath because they are included by default by Kotlin Native Compiler. + * this behaviour will be fixed as part of KT-65232 + */ + @get:InputFiles + @get:Optional + @get:PathSensitive(PathSensitivity.RELATIVE) + internal var excludeOriginalPlatformLibraries: FileCollection? = null + @Suppress("DeprecatedCallableAddReplaceWith") @Deprecated("KTIJ-25227: Necessary override for IDEs < 2023.2", level = DeprecationLevel.ERROR) override fun setupCompilerArgs(args: K2NativeCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { @@ -452,7 +462,7 @@ internal constructor( args.target = konanTarget.name args.produce = outputKind.name.toLowerCaseAsciiOnly() args.metadataKlib = sharedCompilationData != null - args.nodefaultlibs = true + args.nodefaultlibs = sharedCompilationData != null args.nostdlib = true args.manifestFile = sharedCompilationData?.manifestFile?.absolutePath args.nopack = produceUnpackedKlib.get() @@ -475,7 +485,9 @@ internal constructor( } dependencyClasspath { args -> - args.libraries = runSafe { libraries.files.filterKlibsPassedToCompiler().toPathsArray() } + args.libraries = runSafe { + libraries.exclude(excludeOriginalPlatformLibraries).files.filterKlibsPassedToCompiler().toPathsArray() + } args.friendModules = runSafe { friendModule.files.takeIf { it.isNotEmpty() }?.map { it.absolutePath }?.joinToString(File.pathSeparator) } @@ -496,8 +508,8 @@ internal constructor( } } - - private val isMetadataCompilation: Boolean = when (compilation) { + @get:Internal + internal val isMetadataCompilation: Boolean = when (compilation) { is KotlinCompilationInfo.TCS -> compilation.compilation is KotlinMetadataCompilation<*> } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/fileUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/fileUtils.kt index 59fd17a0aac..8350523a1f6 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/fileUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/fileUtils.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.utils import org.gradle.api.Project import org.gradle.api.file.Directory +import org.gradle.api.file.FileCollection import org.gradle.api.file.RegularFile import org.gradle.api.provider.Provider import org.jetbrains.kotlin.gradle.plugin.internal.CustomPropertiesFileValueSource @@ -144,3 +145,8 @@ internal val Project.localProperties: Provider> ) } .usedAtConfigurationTime(configurationTimePropertiesAccessor) + +/** + * Returns file collection [this] excluding files from [excludes] if not null + */ +internal fun FileCollection.exclude(excludes: FileCollection?): FileCollection = if (excludes != null) minus(excludes) else this \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/compilerArgumetns/KotlinNativeCompileArgumentsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/compilerArgumetns/KotlinNativeCompileArgumentsTest.kt index fd2778b704b..7a5c1de6fa8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/compilerArgumetns/KotlinNativeCompileArgumentsTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/compilerArgumetns/KotlinNativeCompileArgumentsTest.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.unitTests.compilerArgumetns +import org.gradle.api.file.FileCollection import org.jetbrains.kotlin.cli.common.arguments.K2NativeCompilerArguments import org.jetbrains.kotlin.compilerRunner.ArgumentUtils import org.jetbrains.kotlin.gradle.dependencyResolutionTests.mavenCentralCacheRedirector @@ -15,6 +16,7 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext.Companion.default import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext.Companion.lenient import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile +import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP import org.jetbrains.kotlin.gradle.util.main import java.io.File @@ -223,4 +225,51 @@ class KotlinNativeCompileArgumentsTest { assertEquals(expectedDependencies, actualDependencies) } + + @Test + fun `native compile tasks SHOULD NOT have native platform dependencies but SHOULD have stdlib`() { + val project = buildProjectWithMPP() + project.repositories.mavenLocal() + project.repositories.mavenCentralCacheRedirector() + val kotlin = project.multiplatformExtension + + kotlin.linuxX64().binaries.executable() + kotlin.linuxArm64().binaries.executable() + + project.evaluate() + + val compileLinuxX64 = project.tasks.getByName("compileKotlinLinuxX64") as KotlinNativeCompile + val compileLinuxArm64 = project.tasks.getByName("compileKotlinLinuxArm64") as KotlinNativeCompile + val compileLinuxMainMetadata = project.tasks.getByName("compileLinuxMainKotlinMetadata") as KotlinNativeCompile + + val linkLinuxX64 = project.tasks.getByName("linkDebugExecutableLinuxX64") as KotlinNativeLink + val linkLinuxArm64 = project.tasks.getByName("linkDebugExecutableLinuxArm64") as KotlinNativeLink + + fun FileCollection?.assertIsPlatformDependencies(target: String) { + if (this == null) fail("Expected to have platform dependencies of target $target but got null") + for (file in this) { + if (!file.path.contains("platform${File.separator}$target")) fail("File $file is expected to be a platform dependency of $target") + } + } + compileLinuxX64.excludeOriginalPlatformLibraries.assertIsPlatformDependencies("linux_x64") + compileLinuxArm64.excludeOriginalPlatformLibraries.assertIsPlatformDependencies("linux_arm64") + if (compileLinuxMainMetadata.excludeOriginalPlatformLibraries != null) fail( + "Native metadata compilation should not exclude platform libraries because they are coming from commonizer. " + + "And is not included by default by Kotlin/Native compiler like default platform libraries." + ) + linkLinuxX64.excludeOriginalPlatformLibraries.assertIsPlatformDependencies("linux_x64") + linkLinuxArm64.excludeOriginalPlatformLibraries.assertIsPlatformDependencies("linux_arm64") + + fun Array?.assertFilePathsDontContain(pathSubString: String) { + if (this == null) return + val badFiles = filter { it.contains(pathSubString) } + if (badFiles.isEmpty()) return + fail("Following files contain unexpected '$pathSubString' substring in their paths: \n${badFiles.joinToString("\n")}") + } + + compileLinuxX64.createCompilerArguments(default).libraries.assertFilePathsDontContain("linux_x64") + compileLinuxArm64.createCompilerArguments(default).libraries.assertFilePathsDontContain("linux_arm64") + linkLinuxX64.createCompilerArguments(default).libraries.assertFilePathsDontContain("linux_x64") + linkLinuxArm64.createCompilerArguments(default).libraries.assertFilePathsDontContain("linux_arm64") + } } \ No newline at end of file