diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CocoaPodsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CocoaPodsIT.kt index 0d70a29b4ca..c1bded7b3c0 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CocoaPodsIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CocoaPodsIT.kt @@ -55,11 +55,12 @@ class CocoaPodsIT : BaseGradleIT() { private val defaultPodRepo = "https://github.com/AFNetworking/AFNetworking" private val defaultPodName = "AFNetworking" private val defaultTarget = "IOS" - + private val defaultFamily = "IOS" + private val defaultSDK = "iphonesimulator" private val defaultPodDownloadTaskName = podDownloadTaskName + defaultPodName - private val defaultPodGenTaskName = podGenTaskName + defaultTarget - private val defaultBuildTaskName = podBuildTaskName + defaultTarget - private val defaultSetupBuildTaskName = podSetupBuildTaskName + defaultTarget + private val defaultPodGenTaskName = podGenTaskName + defaultFamily + private val defaultBuildTaskName = podBuildTaskName + defaultSDK.capitalize() + private val defaultSetupBuildTaskName = podSetupBuildTaskName + defaultSDK.capitalize() private val defaultCinteropTaskName = cinteropTaskName + defaultPodName + defaultTarget private lateinit var hooks: CustomHooks diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt index 8f7d602b9fa..ad94b594ef3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt @@ -24,8 +24,10 @@ import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.utils.asValidTaskName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName +import org.jetbrains.kotlin.konan.target.Family import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget +import org.jetbrains.kotlin.konan.target.KonanTarget.* import java.io.File internal val Project.cocoapodsBuildDirs: CocoapodsBuildDirs @@ -47,7 +49,7 @@ internal class CocoapodsBuildDirs(val project: Project) { val synthetic: File get() = root.resolve("synthetic") - fun synthetic(kotlinNativeTarget: KotlinNativeTarget) = synthetic.resolve(kotlinNativeTarget.name) + fun synthetic(family: Family) = synthetic.resolve(family.name) val externalSources: File get() = root.resolve("externalSources") @@ -60,19 +62,22 @@ internal class CocoapodsBuildDirs(val project: Project) { internal fun String.asValidFrameworkName() = replace('-', '_') -private val KotlinNativeTarget.toPodGenTaskName: String - get() = lowerCamelCaseName(KotlinCocoapodsPlugin.POD_GEN_TASK_NAME, disambiguationClassifier) - -private val KotlinNativeTarget.toSetupBuildTaskName: String +private val Family.toPodGenTaskName: String get() = lowerCamelCaseName( - KotlinCocoapodsPlugin.POD_SETUP_BUILD_TASK_NAME, - disambiguationClassifier + KotlinCocoapodsPlugin.POD_GEN_TASK_NAME, + name ) -private val KotlinNativeTarget.toBuildDependenciesTaskName: String +private val String.toSetupBuildTaskName: String + get() = lowerCamelCaseName( + KotlinCocoapodsPlugin.POD_SETUP_BUILD_TASK_NAME, + this + ) + +private val String.toBuildDependenciesTaskName: String get() = lowerCamelCaseName( KotlinCocoapodsPlugin.POD_BUILD_DEPENDENCIES_TASK_NAME, - disambiguationClassifier + this ) private val CocoapodsDependency.toPodDownloadTaskName: String @@ -87,6 +92,18 @@ open class KotlinCocoapodsPlugin : Plugin { .withType(KotlinNativeTarget::class.java) .matching { it.konanTarget.family.isAppleFamily } + private val KotlinNativeTarget.toValidSDK: String + get() = when (konanTarget) { + IOS_X64 -> "iphonesimulator" + IOS_ARM32, IOS_ARM64 -> "iphoneos" + WATCHOS_X86, WATCHOS_X64 -> "watchsimulator" + WATCHOS_ARM32, WATCHOS_ARM64 -> "watchos" + TVOS_X64 -> "appletvsimulator" + TVOS_ARM64 -> "appletvos" + MACOS_X64 -> "macosx" + else -> throw IllegalArgumentException("Bad target ${konanTarget.name}.") + } + /** * Splits a string using a whitespace characters as delimiters. * Ignores whitespaces in quotes and drops quotes, e.g. a string @@ -177,8 +194,8 @@ open class KotlinCocoapodsPlugin : Plugin { // We create a fat framework only for device platforms which have several // device architectures: iosArm64, iosArm32, watchosArm32 and watchosArm64. val frameworkPlatforms: List = when (requestedTargetName) { - KOTLIN_TARGET_FOR_IOS_DEVICE -> listOf(KonanTarget.IOS_ARM64, KonanTarget.IOS_ARM32) - KOTLIN_TARGET_FOR_WATCHOS_DEVICE -> listOf(KonanTarget.WATCHOS_ARM32, KonanTarget.WATCHOS_ARM64) + KOTLIN_TARGET_FOR_IOS_DEVICE -> listOf(IOS_ARM64, IOS_ARM32) + KOTLIN_TARGET_FOR_WATCHOS_DEVICE -> listOf(WATCHOS_ARM32, WATCHOS_ARM64) else -> listOf(HostManager().targetByName(requestedTargetName)) // A requested target doesn't require building a fat framework. } @@ -230,7 +247,8 @@ open class KotlinCocoapodsPlugin : Plugin { && project.findProperty(TARGET_PROPERTY) == null && project.findProperty(CONFIGURATION_PROPERTY) == null ) { - val podBuildTaskProvider = project.tasks.named(target.toBuildDependenciesTaskName, PodBuildTask::class.java) + val podBuildTaskProvider = + project.tasks.named(target.toValidSDK.toBuildDependenciesTaskName, PodBuildTask::class.java) interopTask.inputs.file(podBuildTaskProvider.get().buildSettingsFileProvider) interopTask.dependsOn(podBuildTaskProvider) } @@ -256,7 +274,8 @@ open class KotlinCocoapodsPlugin : Plugin { && project.findProperty(TARGET_PROPERTY) == null && project.findProperty(CONFIGURATION_PROPERTY) == null ) { - val podBuildTaskProvider = project.tasks.named(target.toBuildDependenciesTaskName, PodBuildTask::class.java) + val podBuildTaskProvider = + project.tasks.named(target.toValidSDK.toBuildDependenciesTaskName, PodBuildTask::class.java) val buildSettings = podBuildTaskProvider.get().buildSettingsFileProvider.get() .inputStream() @@ -361,14 +380,22 @@ open class KotlinCocoapodsPlugin : Plugin { private fun registerPodGenTask( project: Project, kotlinExtension: KotlinMultiplatformExtension, cocoapodsExtension: CocoapodsExtension ) { + val families = mutableSetOf() val podspecTaskProvider = project.tasks.named(POD_SPEC_TASK_NAME, PodspecTask::class.java) val downloadPods = project.tasks.named(POD_DOWNLOAD_TASK_NAME) kotlinExtension.supportedTargets().all { target -> - project.tasks.register(target.toPodGenTaskName, PodGenTask::class.java) { + + val family = target.konanTarget.family + if (family in families) { + return@all + } + families += family + + project.tasks.register(family.toPodGenTaskName, PodGenTask::class.java) { it.description = "Сreates a synthetic Xcode project to retrieve CocoaPods dependencies" it.podspecProvider = podspecTaskProvider.get().outputFileProvider - it.kotlinNativeTarget = target + it.family = family it.cocoapodsExtension = cocoapodsExtension it.dependsOn(podspecTaskProvider) it.dependsOn(downloadPods) @@ -382,19 +409,27 @@ open class KotlinCocoapodsPlugin : Plugin { kotlinExtension: KotlinMultiplatformExtension, cocoapodsExtension: CocoapodsExtension ) { + val sdks = mutableSetOf() kotlinExtension.supportedTargets().all { target -> - project.tasks.register(target.toSetupBuildTaskName, PodSetupBuildTask::class.java) { + val sdk = target.toValidSDK + if (sdk in sdks) { + return@all + } + sdks += sdk + + val podGenTaskProvider = project.tasks.named(target.konanTarget.family.toPodGenTaskName, PodGenTask::class.java) + + project.tasks.register(sdk.toSetupBuildTaskName, PodSetupBuildTask::class.java) { it.group = TASK_GROUP it.description = "Collect environment variables from .xcworkspace file" it.cocoapodsExtension = cocoapodsExtension - it.kotlinNativeTarget = target + it.sdk = project.provider { sdk } val podspecTaskProvider = project.tasks.named(POD_SPEC_TASK_NAME, PodspecTask::class.java) it.schemeName = podspecTaskProvider.map { it.specName } - val podGenTaskProvider = project.tasks.named(target.toPodGenTaskName, PodGenTask::class.java) it.podsXcodeProjDirProvider = podGenTaskProvider.get().podsXcodeProjDirProvider it.dependsOn(podGenTaskProvider) it.onlyIf { isAvailableToProduceSynthetic } @@ -407,15 +442,22 @@ open class KotlinCocoapodsPlugin : Plugin { kotlinExtension: KotlinMultiplatformExtension, cocoapodsExtension: CocoapodsExtension ) { + val sdks = mutableSetOf() kotlinExtension.supportedTargets().all { target -> - val podSetupBuildTaskProvider = project.tasks.named(target.toSetupBuildTaskName, PodSetupBuildTask::class.java) + val sdk = target.toValidSDK + if (sdk in sdks) { + return@all + } + sdks += sdk - project.tasks.register(target.toBuildDependenciesTaskName, PodBuildTask::class.java) { + val podSetupBuildTaskProvider = project.tasks.named(sdk.toSetupBuildTaskName, PodSetupBuildTask::class.java) + + project.tasks.register(sdk.toBuildDependenciesTaskName, PodBuildTask::class.java) { it.group = TASK_GROUP it.description = "Calls `xcodebuild` on xcworkspace for the pod scheme" - it.kotlinNativeTarget = target + it.sdk = project.provider { sdk } it.cocoapodsExtension = cocoapodsExtension it.podsXcodeProjDirProvider = podSetupBuildTaskProvider.get().podsXcodeProjDirProvider it.buildSettingsFileProvider = podSetupBuildTaskProvider.get().buildSettingsFileProvider diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/AdvancedCocoapodsTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/AdvancedCocoapodsTasks.kt index dd7822c1217..0041302e9f8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/AdvancedCocoapodsTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/AdvancedCocoapodsTasks.kt @@ -17,9 +17,7 @@ import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.Cocoapods import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.konan.target.Family -import org.jetbrains.kotlin.konan.target.KonanTarget import java.io.File import java.io.FileInputStream import java.io.InputStream @@ -27,28 +25,13 @@ import java.net.URI import java.util.* import kotlin.concurrent.thread -internal val KotlinNativeTarget.toBuildSettingsFileName: String - get() = "build-settings-$disambiguationClassifier.properties" - -internal val KotlinNativeTarget.toValidSDK: String - get() = when (konanTarget) { - KonanTarget.IOS_X64 -> "iphonesimulator" - KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64 -> "iphoneos" - KonanTarget.WATCHOS_X86, KonanTarget.WATCHOS_X64 -> "watchsimulator" - KonanTarget.WATCHOS_ARM32, KonanTarget.WATCHOS_ARM64 -> "watchos" - KonanTarget.TVOS_X64 -> "appletvsimulator" - KonanTarget.TVOS_ARM64 -> "appletvos" - KonanTarget.MACOS_X64 -> "macosx" - else -> throw IllegalArgumentException("Bad target ${konanTarget.name}.") - } - -internal val KotlinNativeTarget.platformLiteral: String - get() = when (konanTarget.family) { +private val Family.platformLiteral: String + get() = when (this) { Family.OSX -> "macos" Family.IOS -> "ios" Family.TVOS -> "tvos" Family.WATCHOS -> "watchos" - else -> throw IllegalArgumentException("Unsupported native target '${konanTarget.name}'") + else -> throw IllegalArgumentException("Bad family ${this.name}") } /** @@ -350,13 +333,13 @@ open class PodGenTask : CocoapodsWithSyntheticTask() { @get:InputFile internal lateinit var podspecProvider: Provider - @Internal - lateinit var kotlinNativeTarget: KotlinNativeTarget + @get:Internal + lateinit var family: Family @get:OutputDirectory internal val podsXcodeProjDirProvider: Provider get() = project.provider { - project.cocoapodsBuildDirs.synthetic(kotlinNativeTarget) + project.cocoapodsBuildDirs.synthetic(family) .resolve(podspecProvider.get().nameWithoutExtension) .resolve("Pods") .resolve("Pods.xcodeproj") @@ -364,7 +347,7 @@ open class PodGenTask : CocoapodsWithSyntheticTask() { @TaskAction fun generate() { - val syntheticDir = project.cocoapodsBuildDirs.synthetic(kotlinNativeTarget).apply { mkdirs() } + val syntheticDir = project.cocoapodsBuildDirs.synthetic(family).apply { mkdirs() } val localPodspecPaths = cocoapodsExtension.pods.mapNotNull { it.source?.getLocalPath(project, it.name) } val sources = cocoapodsExtension.specRepos.getAll().toMutableList() @@ -372,7 +355,7 @@ open class PodGenTask : CocoapodsWithSyntheticTask() { val podGenProcessArgs = listOfNotNull( "pod", "gen", - "--platforms=${kotlinNativeTarget.platformLiteral}", + "--platforms=${family.platformLiteral}", "--gen-directory=${syntheticDir.absolutePath}", localPodspecPaths.takeIf { it.isNotEmpty() }?.joinToString(separator = ",")?.let { "--local-sources=$it" }, sources.takeIf { it.isNotEmpty() }?.joinToString(separator = ",")?.let { "--sources=$it" }, @@ -391,13 +374,13 @@ open class PodGenTask : CocoapodsWithSyntheticTask() { outputText, outputText.takeIf { it.contains("deployment target") - || it.contains("requested platforms: [\"${kotlinNativeTarget.platformLiteral}\"]") + || it.contains("requested platforms: [\"${family.platformLiteral}\"]") }?.let { """ Tip: try to configure deployment_target for ALL targets as follows: cocoapods { ... - ${kotlinNativeTarget.konanTarget.family.name.toLowerCase()}.deploymentTarget = "..." + ${family.name.toLowerCase()}.deploymentTarget = "..." ... } """.trimIndent() @@ -418,8 +401,8 @@ open class PodSetupBuildTask : CocoapodsWithSyntheticTask() { @get:InputDirectory internal lateinit var podsXcodeProjDirProvider: Provider - @Internal - lateinit var kotlinNativeTarget: KotlinNativeTarget + @get:Input + internal lateinit var sdk: Provider @Input lateinit var schemeName: Provider @@ -428,9 +411,12 @@ open class PodSetupBuildTask : CocoapodsWithSyntheticTask() { internal val buildSettingsFileProvider: Provider = project.provider { project.cocoapodsBuildDirs .buildSettings - .resolve(kotlinNativeTarget.toBuildSettingsFileName) + .resolve(sdk.get().toBuildSettingsFileName) } + private val String.toBuildSettingsFileName: String + get() = "build-settings-$this.properties" + @TaskAction fun setupBuild() { val podsXcodeProjDir = podsXcodeProjDirProvider.get() @@ -439,7 +425,7 @@ open class PodSetupBuildTask : CocoapodsWithSyntheticTask() { "xcodebuild", "-showBuildSettings", "-project", podsXcodeProjDir.name, "-scheme", schemeName.get(), - "-sdk", kotlinNativeTarget.toValidSDK + "-sdk", sdk.get() ) val buildSettingsProcess = ProcessBuilder(buildSettingsReceivingCommand) @@ -473,8 +459,8 @@ open class PodBuildTask : CocoapodsWithSyntheticTask() { @get:InputFile internal lateinit var buildSettingsFileProvider: Provider - @Internal - lateinit var kotlinNativeTarget: KotlinNativeTarget + @get:Input + internal lateinit var sdk: Provider @get:Optional @get:OutputDirectory @@ -497,7 +483,7 @@ open class PodBuildTask : CocoapodsWithSyntheticTask() { "xcodebuild", "-project", podsXcodeProjDir.name, "-scheme", it.schemeName, - "-sdk", kotlinNativeTarget.toValidSDK, + "-sdk", sdk.get(), "-configuration", podBuildSettings.configuration )