[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
This commit is contained in:
Anton Lakotka
2024-01-22 16:39:54 +01:00
committed by Space Team
parent 90a47e0488
commit 9acb9ff2b7
6 changed files with 105 additions and 9 deletions
@@ -72,6 +72,7 @@ internal fun Project.registerKotlinPluginExtensions() {
register(project, KotlinRegisterCompilationArchiveTasksExtension)
register(project, IdeMultiplatformImportActionSetupAction)
register(project, KotlinLLDBScriptSetupAction)
register(project, ExcludeDefaultPlatformDependenciesFromKotlinNativeCompileTasks)
}
}
@@ -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<KotlinNativeLink>().configureEach { task ->
@Suppress("DEPRECATION")
val konanTarget = task.compilation.konanTarget
task.excludeOriginalPlatformLibraries = task.project.getOriginalPlatformLibrariesFor(konanTarget)
}
tasks.withType<KotlinNativeCompile>().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<File> {
@@ -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 }
@@ -157,7 +157,7 @@ abstract class AbstractKotlinNativeCompile<
internal abstract val explicitApiMode: Property<ExplicitApiMode>
@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<*>
}
@@ -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<Map<String, String>>
)
}
.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
@@ -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<String>?.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")
}
}