From fa2e787f76dbc9ed8d2bd32a140169e07fd2dae9 Mon Sep 17 00:00:00 2001 From: Viacheslav Kormushkin Date: Fri, 23 Jul 2021 12:42:10 +0300 Subject: [PATCH] CocoaPods Gradle plugin: Support incremental task execution when switching between Xcode and terminal #KT-37511 --- .../kotlin/gradle/native/CocoaPodsIT.kt | 18 ++++ .../native/cocoapods/CocoapodsExtension.kt | 33 +++---- .../native/cocoapods/KotlinCocoapodsPlugin.kt | 86 +++++++++---------- .../targets/native/tasks/CocoapodsTasks.kt | 5 +- 4 files changed, 75 insertions(+), 67 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsIT.kt index 4ef12622ba1..04ad894945e 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsIT.kt @@ -885,6 +885,24 @@ class CocoaPodsIT : BaseGradleIT() { fun testPodDependencyInUnitTests() = getProjectByName(cocoapodsTestsProjectName).testWithWrapper(":iosX64Test") + @Test + fun testCinteropUpToDate() { + project.gradleBuildScript().addPod(defaultPodName, produceGitBlock(defaultPodRepo)) + project.testImport() + hooks.addHook { + assertTasksUpToDate( + defaultCinteropTaskName + ) + } + project.test( + "syncFramework", + "-Pkotlin.native.cocoapods.platform=iphonesimulator", + "-Pkotlin.native.cocoapods.archs=x86_64", + "-Pkotlin.native.cocoapods.configuration=Debug", + "-Pkotlin.native.cocoapods.generate.wrapper=true" + ) + } + // paths private fun CompiledProject.url() = externalSources().resolve("url") diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/CocoapodsExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/CocoapodsExtension.kt index b2ee25bf70a..877f85b3c91 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/CocoapodsExtension.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/CocoapodsExtension.kt @@ -251,26 +251,27 @@ open class CocoapodsExtension(private val project: Project) { } internal fun configureLinkingOptions(binary: NativeBinary, setRPath: Boolean = false) { - project.findProperty(KotlinCocoapodsPlugin.FRAMEWORK_PATHS_PROPERTY)?.toString()?.let { args -> - binary.linkerOpts.addAll(args.splitQuotedArgs().map { "-F$it" }) - } pods.all { pod -> binary.linkerOpts("-framework", pod.moduleName) - if (project.shouldUseSyntheticProjectSettings && - KotlinCocoapodsPlugin.isAvailableToProduceSynthetic - ) { - binary.linkTaskProvider.configure { task -> - val podBuildTaskProvider = project.getPodBuildTaskProvider(binary.target, pod) - task.inputs.file(podBuildTaskProvider.map { it.buildSettingsFile }) - task.dependsOn(podBuildTaskProvider) + check(KotlinCocoapodsPlugin.isAvailableToProduceSynthetic) { + """ + Dependency on pods requires cocoapods-generate plugin to be installed. + Please install it by executing 'gem install cocoapods-generate' in terminal. + """.trimMargin() + } - task.doFirst { _ -> - val podBuildSettings = project.getPodBuildSettingsProperties(binary.target, pod) - binary.linkerOpts.addAll(podBuildSettings.frameworkSearchPaths.map { "-F$it" }) - if (setRPath) { - binary.linkerOpts.addAll(podBuildSettings.frameworkSearchPaths.flatMap { listOf("-rpath", it) }) - } + binary.linkTaskProvider.configure { task -> + + val podBuildTaskProvider = project.getPodBuildTaskProvider(binary.target, pod) + task.inputs.file(podBuildTaskProvider.map { it.buildSettingsFile }) + task.dependsOn(podBuildTaskProvider) + + task.doFirst { _ -> + val podBuildSettings = project.getPodBuildSettingsProperties(binary.target, pod) + binary.linkerOpts.addAll(podBuildSettings.frameworkSearchPaths.map { "-F$it" }) + if (setRPath) { + binary.linkerOpts.addAll(podBuildSettings.frameworkSearchPaths.flatMap { listOf("-rpath", it) }) } } } 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 ecc391a8eaa..33e377b3e2d 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 @@ -18,9 +18,6 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.addExtension import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency.PodLocation.* -import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.ARCHS_PROPERTY -import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.CONFIGURATION_PROPERTY -import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.PLATFORM_PROPERTY import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType import org.jetbrains.kotlin.gradle.plugin.mpp.TestExecutable @@ -92,11 +89,6 @@ private val CocoapodsDependency.toPodDownloadTaskName: String name.asValidTaskName() ) -internal val Project.shouldUseSyntheticProjectSettings: Boolean - get() = (project.findProperty(PLATFORM_PROPERTY) == null && - project.findProperty(ARCHS_PROPERTY) == null && - project.findProperty(CONFIGURATION_PROPERTY) == null) - private val KotlinNativeTarget.toValidSDK: String get() = when (konanTarget) { IOS_X64, IOS_SIMULATOR_ARM64 -> "iphonesimulator" @@ -231,6 +223,21 @@ open class KotlinCocoapodsPlugin : Plugin { val platforms = project.findProperty(PLATFORM_PROPERTY)?.toString()?.split(",", " ")?.filter { it.isNotBlank() } val archs = project.findProperty(ARCHS_PROPERTY)?.toString()?.split(",", " ")?.filter { it.isNotBlank() } + if ( + project.findProperty(CFLAGS_PROPERTY) != null || + project.findProperty(FRAMEWORK_PATHS_PROPERTY) != null || + project.findProperty(HEADER_PATHS_PROPERTY) != null + ) { + logger.warn( + """ + Properties + kotlin.native.cocoapods.cflags + kotlin.native.cocoapods.paths.frameworks + kotlin.native.cocoapods.paths.headers + are not supported and will be ignored since Cocoapods plugin generates all required properties automatically. + """.trimIndent()) + } + if (platforms == null || archs == null) { check(project.findProperty(TARGET_PROPERTY) == null) { """ @@ -292,6 +299,13 @@ open class KotlinCocoapodsPlugin : Plugin { // to avoid showing it in the `tasks` output. } + check(isAvailableToProduceSynthetic) { + """ + Dependency on pods requires cocoapods-generate plugin to be installed. + Please install it by executing 'gem install cocoapods-generate' in terminal. + """.trimMargin() + } + kotlinExtension.supportedTargets().all { target -> target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).cinterops.create(pod.moduleName) { interop -> @@ -305,46 +319,27 @@ open class KotlinCocoapodsPlugin : Plugin { _extraOptsProp.addAll(project.provider { pod.extraOpts }) } - if (project.shouldUseSyntheticProjectSettings && - isAvailableToProduceSynthetic - ) { - val podBuildTaskProvider = project.getPodBuildTaskProvider(target, pod) - interopTask.inputs.file(podBuildTaskProvider.map {it.buildSettingsFile }) - interopTask.dependsOn(podBuildTaskProvider) - } - - project.findProperty(CFLAGS_PROPERTY)?.toString()?.let { args -> - // Xcode quotes around paths with spaces. - // Here and below we need to split such paths taking this into account. - interop.compilerOpts.addAll(args.splitQuotedArgs()) - } - project.findProperty(HEADER_PATHS_PROPERTY)?.toString()?.let { args -> - interop.compilerOpts.addAll(args.splitQuotedArgs().map { "-I$it" }) - } - project.findProperty(FRAMEWORK_PATHS_PROPERTY)?.toString()?.let { args -> - interop.compilerOpts.addAll(args.splitQuotedArgs().map { "-F$it" }) - } + val podBuildTaskProvider = project.getPodBuildTaskProvider(target, pod) + interopTask.inputs.file(podBuildTaskProvider.map {it.buildSettingsFile }) + interopTask.dependsOn(podBuildTaskProvider) interopTask.doFirst { _ -> // Since we cannot expand the configuration phase of interop tasks // receiving the required environment variables happens on execution phase. // TODO This needs to be fixed to improve UP-TO-DATE checks. - if (project.shouldUseSyntheticProjectSettings && - isAvailableToProduceSynthetic - ) { - val podBuildSettings = project.getPodBuildSettingsProperties(target, pod) + val podBuildSettings = project.getPodBuildSettingsProperties(target, pod) - podBuildSettings.cflags?.let { args -> - // Xcode quotes around paths with spaces. - // Here and below we need to split such paths taking this into account. - interop.compilerOpts.addAll(args.splitQuotedArgs()) - } - podBuildSettings.headerPaths?.let { args -> - interop.compilerOpts.addAll(args.splitQuotedArgs().map { "-I$it" }) - } - - interop.compilerOpts.addAll(podBuildSettings.frameworkSearchPaths.map { "-F$it" }) + podBuildSettings.cflags?.let { args -> + // Xcode quotes around paths with spaces. + // Here and below we need to split such paths taking this into account. + interop.compilerOpts.addAll(args.splitQuotedArgs()) } + podBuildSettings.headerPaths?.let { args -> + interop.compilerOpts.addAll(args.splitQuotedArgs().map { "-I$it" }) + } + + interop.compilerOpts.addAll(podBuildSettings.frameworkSearchPaths.map { "-F$it" }) + } } } @@ -589,12 +584,9 @@ open class KotlinCocoapodsPlugin : Plugin { if (HostManager.hostIsMac && !isAvailableToProduceSynthetic) { logger.quiet( """ - To take advantage of the new functionality for Cocoapods Integration like synchronizing with the Xcode project - and supporting dependencies on pods, please install the `cocoapods-generate` plugin for CocoaPods - by calling `gem install cocoapods-generate` in terminal. - - More details are available by https://github.com/square/cocoapods-generate - """.trimIndent() + Dependency on pods requires cocoapods-generate plugin to be installed. + If you plan to add dependencies on third party pods, don't forget to install it by executing 'gem install cocoapods-generate' in terminal. + """.trimIndent() ) } createInterops(project, kotlinExtension, cocoapodsExtension) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CocoapodsTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CocoapodsTasks.kt index c741c9c9b53..5226cb08ebf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CocoapodsTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CocoapodsTasks.kt @@ -149,10 +149,7 @@ open class PodspecTask : DefaultTask() { | "$gradleCommand" -p "${'$'}REPO_ROOT" ${'$'}KOTLIN_PROJECT_PATH:$SYNC_TASK_NAME \ | -P${KotlinCocoapodsPlugin.PLATFORM_PROPERTY}=${'$'}PLATFORM_NAME \ | -P${KotlinCocoapodsPlugin.ARCHS_PROPERTY}="${'$'}ARCHS" \ - | -P${KotlinCocoapodsPlugin.CONFIGURATION_PROPERTY}=${'$'}CONFIGURATION \ - | -P${KotlinCocoapodsPlugin.CFLAGS_PROPERTY}="${'$'}OTHER_CFLAGS" \ - | -P${KotlinCocoapodsPlugin.HEADER_PATHS_PROPERTY}="${'$'}HEADER_SEARCH_PATHS" \ - | -P${KotlinCocoapodsPlugin.FRAMEWORK_PATHS_PROPERTY}="${'$'}FRAMEWORK_SEARCH_PATHS" + | -P${KotlinCocoapodsPlugin.CONFIGURATION_PROPERTY}=${'$'}CONFIGURATION | SCRIPT | } | ]