Move commonizer to gradle task and attach to lazy file collection.
This commit is contained in:
+79
-54
@@ -5,8 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.native.internal
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.compilerRunner.KotlinNativeKlibCommonizerToolRunner
|
||||
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_COMMONIZED_LIBS_DIR
|
||||
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_KLIB_DIR
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.File
|
||||
@@ -16,73 +19,95 @@ import java.nio.file.*
|
||||
import java.nio.file.attribute.*
|
||||
import java.time.*
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
internal fun runCommonizerInBulk(
|
||||
project: Project,
|
||||
distributionDir: File,
|
||||
baseDestinationDir: File,
|
||||
targetGroups: List<Set<KonanTarget>>,
|
||||
kotlinVersion: String
|
||||
): List<File> {
|
||||
internal data class CommonizerTaskParams(
|
||||
@get:InputDirectory val distributionDir: File,
|
||||
@get:InputDirectory val baseDestinationDir: File,
|
||||
@Internal val targetGroups: List<Set<KonanTarget>>,
|
||||
@get:Input val kotlinVersion: String
|
||||
) {
|
||||
@Internal
|
||||
val commandLineArguments = mutableListOf<String>()
|
||||
|
||||
@Internal
|
||||
val successPostActions = mutableListOf<() -> Unit>()
|
||||
|
||||
@Internal
|
||||
val failurePostActions = mutableListOf<() -> Unit>()
|
||||
|
||||
val destinationDirs = targetGroups.map { targets ->
|
||||
if (targets.size == 1) {
|
||||
// no need to commonize, just use the libraries from the distribution
|
||||
distributionDir.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
|
||||
} else {
|
||||
// need stable order of targets for consistency
|
||||
val orderedTargets = targets.sortedBy { it.name }
|
||||
// It isn't best option for "up-to-date" checker (for multi project build it will be started few times)
|
||||
// but commonizer has inner check
|
||||
@get:OutputDirectories
|
||||
val destinationDirs: List<File>
|
||||
|
||||
val discriminator = buildString {
|
||||
orderedTargets.joinTo(this, separator = "-")
|
||||
append("-")
|
||||
append(kotlinVersion.toLowerCase().base64)
|
||||
// need stable order of targets for consistency
|
||||
private val orderedTargetGroups = targetGroups.map { it.sortedBy { target -> target.name } }
|
||||
|
||||
@Input
|
||||
fun getTargetNames() = orderedTargetGroups.map { it.map { target -> target.name } }
|
||||
|
||||
init {
|
||||
destinationDirs = orderedTargetGroups.map { orderedTargets ->
|
||||
if (orderedTargets.size == 1) {
|
||||
// no need to commonize, just use the libraries from the distribution
|
||||
distributionDir.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
|
||||
} else {
|
||||
val discriminator = buildString {
|
||||
orderedTargets.joinTo(this, separator = "-")
|
||||
append("-")
|
||||
append(kotlinVersion.toLowerCase().base64)
|
||||
}
|
||||
|
||||
val destinationDir = baseDestinationDir.resolve(discriminator)
|
||||
if (!destinationDir.isDirectory) {
|
||||
val parentDir = destinationDir.parentFile
|
||||
parentDir.mkdirs()
|
||||
|
||||
val destinationTmpDir = createTempDir(
|
||||
prefix = "tmp-" + destinationDir.name,
|
||||
suffix = ".new",
|
||||
directory = parentDir
|
||||
)
|
||||
|
||||
commandLineArguments += "native-dist-commonize"
|
||||
commandLineArguments += "-distribution-path"
|
||||
commandLineArguments += distributionDir.toString()
|
||||
commandLineArguments += "-output-path"
|
||||
commandLineArguments += destinationTmpDir.toString()
|
||||
commandLineArguments += "-targets"
|
||||
commandLineArguments += orderedTargets.joinToString(separator = ",")
|
||||
|
||||
successPostActions.add { renameDirectory(destinationTmpDir, destinationDir) }
|
||||
failurePostActions.add { renameToTempAndDelete(destinationTmpDir) }
|
||||
}
|
||||
|
||||
destinationDir
|
||||
}
|
||||
|
||||
val destinationDir = baseDestinationDir.resolve(discriminator)
|
||||
if (!destinationDir.isDirectory) {
|
||||
val parentDir = destinationDir.parentFile
|
||||
parentDir.mkdirs()
|
||||
|
||||
val destinationTmpDir = createTempDir(
|
||||
prefix = "tmp-" + destinationDir.name,
|
||||
suffix = ".new",
|
||||
directory = parentDir
|
||||
)
|
||||
|
||||
commandLineArguments += "native-dist-commonize"
|
||||
commandLineArguments += "-distribution-path"
|
||||
commandLineArguments += distributionDir.toString()
|
||||
commandLineArguments += "-output-path"
|
||||
commandLineArguments += destinationTmpDir.toString()
|
||||
commandLineArguments += "-targets"
|
||||
commandLineArguments += orderedTargets.joinToString(separator = ",")
|
||||
|
||||
successPostActions.add { renameDirectory(destinationTmpDir, destinationDir) }
|
||||
failurePostActions.add { renameToTempAndDelete(destinationTmpDir) }
|
||||
}
|
||||
|
||||
destinationDir
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// first of all remove directories with unused commonized libraries plus temporary directories with commonized libraries
|
||||
// that accidentally were not cleaned up before
|
||||
cleanUp(baseDestinationDir, excludedDirectories = destinationDirs)
|
||||
internal const val COMMONIZER_TASK_NAME = "runCommonizer"
|
||||
|
||||
try {
|
||||
callCommonizerCLI(project, commandLineArguments)
|
||||
successPostActions.forEach { it() }
|
||||
} catch (e: Exception) {
|
||||
failurePostActions.forEach { it() }
|
||||
throw e
|
||||
internal open class CommonizerTask @Inject constructor(
|
||||
@Nested val params: CommonizerTaskParams
|
||||
) : DefaultTask() {
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
// first of all remove directories with unused commonized libraries plus temporary directories with commonized libraries
|
||||
// that accidentally were not cleaned up before
|
||||
cleanUp(params.baseDestinationDir, excludedDirectories = params.destinationDirs)
|
||||
|
||||
try {
|
||||
callCommonizerCLI(project, params.commandLineArguments)
|
||||
params.successPostActions.forEach { it() }
|
||||
} catch (e: Exception) {
|
||||
params.failurePostActions.forEach { it() }
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
return destinationDirs
|
||||
}
|
||||
|
||||
private fun callCommonizerCLI(project: Project, commandLineArguments: List<String>) {
|
||||
+55
-32
@@ -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.compilerRunner.konanHome
|
||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
@@ -18,15 +19,31 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation
|
||||
import org.jetbrains.kotlin.gradle.targets.metadata.getMetadataCompilationForSourceSet
|
||||
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
|
||||
import org.jetbrains.kotlin.gradle.targets.native.internal.NativePlatformDependency.*
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild
|
||||
import org.jetbrains.kotlin.konan.library.*
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.flattenTo
|
||||
import java.io.File
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
private val Project.isNativeDependencyPropagationEnabled: Boolean
|
||||
get() = (findProperty("kotlin.native.enableDependencyPropagation") as? String)?.toBoolean() ?: true
|
||||
|
||||
//for reflection call from KotlinCommonizerModelBuilder
|
||||
@JvmOverloads
|
||||
@JvmName("isAllowCommonizer")
|
||||
internal fun Project.isAllowCommonizer(
|
||||
kotlinVersion: String = getKotlinPluginVersion()!!
|
||||
): Boolean {
|
||||
multiplatformExtensionOrNull ?: return false
|
||||
|
||||
//register commonizer only for 1.4+, only for HMPP projects
|
||||
return compareVersionNumbers(kotlinVersion, "1.4") >= 0
|
||||
&& isKotlinGranularMetadataEnabled
|
||||
&& !isNativeDependencyPropagationEnabled // temporary fix: turn on commonizer only when native deps propagation is disabled
|
||||
}
|
||||
|
||||
internal fun Project.setUpKotlinNativePlatformDependencies() {
|
||||
if (multiplatformExtensionOrNull == null) {
|
||||
// not a multiplatform project, nothing to set up
|
||||
@@ -34,26 +51,19 @@ internal fun Project.setUpKotlinNativePlatformDependencies() {
|
||||
}
|
||||
|
||||
val kotlinVersion = getKotlinPluginVersion()!!
|
||||
|
||||
// run commonizer only for 1.4+, only for HMPP projects and only on IDE sync
|
||||
val allowCommonizer = compareVersionNumbers(kotlinVersion, "1.4") >= 0
|
||||
&& isKotlinGranularMetadataEnabled
|
||||
&& !isNativeDependencyPropagationEnabled // temporary fix: turn on commonizer only when native deps propagation is disabled
|
||||
|
||||
val allowCommonizer = isAllowCommonizer(kotlinVersion)
|
||||
val dependencyResolver = NativePlatformDependencyResolver(this, kotlinVersion)
|
||||
|
||||
findSourceSetsToAddDependencies(allowCommonizer).forEach { (sourceSet: KotlinSourceSet, sourceSetDeps: Set<NativePlatformDependency>) ->
|
||||
sourceSetDeps.forEach { sourceSetDep: NativePlatformDependency ->
|
||||
dependencyResolver.addForResolve(sourceSetDep) { resolvedFiles: Set<File> ->
|
||||
dependencyResolver.addForResolve(sourceSetDep) { resolvedFiles: FileCollection ->
|
||||
//add commonized klibs to metadata compilation
|
||||
if (sourceSetDep is CommonizedCommon) {
|
||||
getMetadataCompilationForSourceSet(sourceSet)?.let { compilation ->
|
||||
compilation.compileDependencyFiles += project.files(resolvedFiles)
|
||||
compilation.compileDependencyFiles += resolvedFiles
|
||||
}
|
||||
}
|
||||
resolvedFiles.forEach { resolvedFile ->
|
||||
dependencies.add(sourceSet.implementationMetadataConfigurationName, dependencies.create(files(resolvedFile)))
|
||||
}
|
||||
dependencies.add(sourceSet.implementationMetadataConfigurationName, dependencies.create(resolvedFiles))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,9 +90,9 @@ private class NativePlatformDependencyResolver(val project: Project, val kotlinV
|
||||
private val distributionLibsDir = distributionDir.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
|
||||
|
||||
private var alreadyResolved = false
|
||||
private val dependencies = mutableMapOf<NativePlatformDependency, MutableList<(Set<File>) -> Unit>>()
|
||||
private val dependencies = mutableMapOf<NativePlatformDependency, MutableList<(FileCollection) -> Unit>>()
|
||||
|
||||
fun addForResolve(dependency: NativePlatformDependency, whenResolved: (Set<File>) -> Unit) {
|
||||
fun addForResolve(dependency: NativePlatformDependency, whenResolved: (FileCollection) -> Unit) {
|
||||
check(!alreadyResolved)
|
||||
dependencies.computeIfAbsent(dependency) { mutableListOf() }.add(whenResolved)
|
||||
}
|
||||
@@ -91,24 +101,32 @@ private class NativePlatformDependencyResolver(val project: Project, val kotlinV
|
||||
check(!alreadyResolved)
|
||||
alreadyResolved = true
|
||||
|
||||
// first, run commonization
|
||||
val targetGroups: List<Pair<CommonizedCommon, Set<KonanTarget>>> = dependencies.keys.filterIsInstance<CommonizedCommon>()
|
||||
.map { it to it.targets }
|
||||
val targetGroups: List<Pair<CommonizedCommon, Set<KonanTarget>>> =
|
||||
dependencies.keys
|
||||
.filterIsInstance<CommonizedCommon>()
|
||||
.map { it to it.targets }
|
||||
|
||||
val commonizedLibsDirs: Map<CommonizedCommon, File> =
|
||||
runCommonizerInBulk(
|
||||
project = project,
|
||||
distributionDir = distributionDir,
|
||||
baseDestinationDir = distributionDir.resolve(KONAN_DISTRIBUTION_KLIB_DIR).resolve(KONAN_DISTRIBUTION_COMMONIZED_LIBS_DIR),
|
||||
targetGroups = targetGroups.map { it.second },
|
||||
kotlinVersion = kotlinVersion
|
||||
).mapIndexed { index: Int, commonizedLibsDir: File ->
|
||||
targetGroups[index].first to commonizedLibsDir
|
||||
}.toMap()
|
||||
val commonizerTaskParams = CommonizerTaskParams(
|
||||
distributionDir,
|
||||
distributionDir.resolve(KONAN_DISTRIBUTION_KLIB_DIR).resolve(KONAN_DISTRIBUTION_COMMONIZED_LIBS_DIR),
|
||||
targetGroups.map { it.second },
|
||||
kotlinVersion
|
||||
)
|
||||
|
||||
val commonizerTaskProvider = project.registerTask(
|
||||
COMMONIZER_TASK_NAME,
|
||||
CommonizerTask::class.java,
|
||||
listOf(commonizerTaskParams)
|
||||
) {}
|
||||
|
||||
val commonizedLibsDirs =
|
||||
commonizerTaskParams.destinationDirs
|
||||
.mapIndexed { index: Int, commonizedLibsDir: File -> targetGroups[index].first to commonizedLibsDir }
|
||||
.toMap()
|
||||
|
||||
// then, resolve dependencies one by one
|
||||
dependencies.forEach { (dependency, actions) ->
|
||||
val libs = when (dependency) {
|
||||
val fileCollection = when (dependency) {
|
||||
is OutOfDistributionCommon -> {
|
||||
/* stdlib, endorsed libs */
|
||||
var hasStdlib = false
|
||||
@@ -122,28 +140,33 @@ private class NativePlatformDependencyResolver(val project: Project, val kotlinV
|
||||
|
||||
if (!hasStdlib) warnAboutMissingNativeStdlib()
|
||||
|
||||
libs
|
||||
project.files(libs)
|
||||
}
|
||||
|
||||
is OutOfDistributionPlatform -> {
|
||||
/* platform libs for a specific target */
|
||||
libsInPlatformDir(distributionLibsDir, dependency.target)
|
||||
project.files(libsInPlatformDir(distributionLibsDir, dependency.target))
|
||||
}
|
||||
|
||||
is CommonizedCommon -> {
|
||||
/* commonized platform libs with expect declarations */
|
||||
val commonizedLibsDir = commonizedLibsDirs.getValue(dependency)
|
||||
libsInCommonDir(commonizedLibsDir)
|
||||
project.files(Callable {
|
||||
libsInCommonDir(commonizedLibsDir)
|
||||
}).builtBy(commonizerTaskProvider)
|
||||
|
||||
}
|
||||
|
||||
is CommonizedPlatform -> {
|
||||
/* commonized platform libs with actual declarations */
|
||||
val commonizedLibsDir = commonizedLibsDirs.getValue(dependency.common)
|
||||
libsInPlatformDir(commonizedLibsDir, dependency.target) + libsInCommonDir(commonizedLibsDir)
|
||||
project.files(Callable {
|
||||
libsInPlatformDir(commonizedLibsDir, dependency.target) + libsInCommonDir(commonizedLibsDir)
|
||||
}).builtBy(commonizerTaskProvider)
|
||||
}
|
||||
}
|
||||
|
||||
actions.forEach { it(libs) }
|
||||
actions.forEach { it(fileCollection) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user