[KT-54060] Disable bitcode embedding to frameworks for Xcode >= 14.

This commit is contained in:
konstantin.tskhovrebov
2022-09-26 17:42:04 +02:00
committed by Space Team
parent ea3713f051
commit afa8a577cc
7 changed files with 136 additions and 80 deletions
@@ -7,29 +7,25 @@
package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Named
import org.jetbrains.kotlin.konan.target.Architecture.ARM32
import org.jetbrains.kotlin.konan.target.Architecture.ARM64
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.Family.*
import org.jetbrains.kotlin.konan.target.KonanTarget
enum class NativeBuildType(
val optimized: Boolean,
val debuggable: Boolean,
private val embedBitcodeForAppleDevices: BitcodeEmbeddingMode
val debuggable: Boolean
) : Named {
RELEASE(true, false, BitcodeEmbeddingMode.BITCODE),
DEBUG(false, true, BitcodeEmbeddingMode.MARKER);
RELEASE(true, false),
DEBUG(false, true);
override fun getName(): String = name.toLowerCase()
fun embedBitcode(target: KonanTarget) = with(target) {
if (family in listOf(IOS, WATCHOS, TVOS) && architecture in listOf(ARM32, ARM64)) {
embedBitcodeForAppleDevices
} else {
BitcodeEmbeddingMode.DISABLE
}
}
@Suppress("UNUSED_PARAMETER")
@Deprecated(
"Default BitcodeEmbeddingMode is BitcodeEmbeddingMode.DISABLE",
ReplaceWith("BitcodeEmbeddingMode.DISABLE")
)
fun embedBitcode(target: KonanTarget) = BitcodeEmbeddingMode.DISABLE
companion object {
val DEFAULT_BUILD_TYPES = setOf(DEBUG, RELEASE)
@@ -373,15 +373,29 @@ class GeneralNativeIT : BaseGradleIT() {
frameworkPaths.forEach { assertFileExists(it) }
assertTrue(fileInWorkingDir(headerPaths[0]).readText().contains("+ (int32_t)exported"))
val xcodeVersionString = runProcess(
listOf("/usr/bin/xcrun", "xcodebuild", "-version"),
workingDir,
System.getenv()
).output.lines()[0].removePrefix("Xcode ")
val xcodeMajorVersion = xcodeVersionString.split(".")[0].toInt()
// Check that by default release frameworks have bitcode embedded.
withNativeCommandLineArguments(":linkMainReleaseFrameworkIos") { arguments ->
assertTrue("-Xembed-bitcode" in arguments)
if (xcodeMajorVersion < 14) {
assertTrue("-Xembed-bitcode" in arguments)
} else {
assertFalse("-Xembed-bitcode" in arguments)
}
assertTrue("-opt" in arguments)
}
// Check that by default debug frameworks have bitcode marker embedded.
withNativeCommandLineArguments(":linkMainDebugFrameworkIos") { arguments ->
assertTrue("-Xembed-bitcode-marker" in arguments)
if (xcodeMajorVersion < 14) {
assertTrue("-Xembed-bitcode-marker" in arguments)
} else {
assertFalse("-Xembed-bitcode-marker" in arguments)
}
assertTrue("-g" in arguments)
}
// Check that bitcode can be disabled by setting custom compiler options
@@ -19,6 +19,7 @@ import org.gradle.api.provider.Provider
import org.gradle.api.tasks.AbstractExecTask
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink
import org.jetbrains.kotlin.gradle.utils.Xcode
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
@@ -278,7 +279,8 @@ class Framework(
/**
* Embed bitcode for the framework or not. See [BitcodeEmbeddingMode].
*/
var embedBitcode: org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode = buildType.embedBitcode(konanTarget)
var embedBitcode: org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode =
Xcode.defaultBitcodeEmbeddingMode(konanTarget, buildType)
/**
* Enable or disable embedding bitcode for the framework. See [BitcodeEmbeddingMode].
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.gradle.targets.native.cocoapods.MissingCocoapodsMess
import org.jetbrains.kotlin.gradle.targets.native.cocoapods.MissingSpecReposMessage
import org.jetbrains.kotlin.gradle.tasks.PodspecTask.Companion.retrievePods
import org.jetbrains.kotlin.gradle.tasks.PodspecTask.Companion.retrieveSpecRepos
import org.jetbrains.kotlin.gradle.utils.runCommand
import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.konan.target.HostManager
import java.io.File
@@ -114,69 +115,6 @@ open class PodInstallTask : CocoapodsTask() {
}
}
private fun runCommand(
command: List<String>,
logger: Logger,
errorHandler: ((retCode: Int, output: String, process: Process) -> String?)? = null,
exceptionHandler: ((ex: IOException) -> Unit)? = null,
processConfiguration: ProcessBuilder.() -> Unit = { }
): String {
var process: Process? = null
try {
process = ProcessBuilder(command)
.apply {
this.processConfiguration()
}.start()
} catch (e: IOException) {
if (exceptionHandler != null) exceptionHandler(e) else throw e
}
if (process == null) {
throw IllegalStateException("Failed to run command ${command.joinToString(" ")}")
}
var inputText = ""
var errorText = ""
val inputThread = thread {
inputText = process.inputStream.use {
it.reader().readText()
}
}
val errorThread = thread {
errorText = process.errorStream.use {
it.reader().readText()
}
}
inputThread.join()
errorThread.join()
val retCode = process.waitFor()
logger.info(
"""
|Information about "${command.joinToString(" ")}" call:
|
|${inputText}
""".trimMargin()
)
check(retCode == 0) {
errorHandler?.invoke(retCode, inputText.ifBlank { errorText }, process)
?: """
|Executing of '${command.joinToString(" ")}' failed with code $retCode and message:
|
|$inputText
|
|$errorText
|
""".trimMargin()
}
return inputText
}
/**
* The task generates a synthetic project with all cocoapods dependencies
*/
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind
import org.jetbrains.kotlin.gradle.plugin.mpp.enabledOnCurrentHost
import org.jetbrains.kotlin.gradle.tasks.dependsOn
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.utils.Xcode
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.presetName
@@ -122,7 +123,7 @@ internal fun KotlinNativeArtifact.registerLinkFrameworkTask(
task.linkerOptions = linkerOptions
task.binaryOptions = binaryOptions
task.isStaticFramework = isStatic
task.embedBitcode = embedBitcode ?: buildType.embedBitcode(target)
task.embedBitcode = embedBitcode ?: Xcode.defaultBitcodeEmbeddingMode(target, buildType)
task.librariesConfiguration = librariesConfigurationName
task.exportLibrariesConfiguration = exportConfigurationName
task.kotlinOptions(kotlinOptionsFn)
@@ -0,0 +1,73 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.utils
import org.gradle.api.logging.Logger
import java.io.IOException
import kotlin.concurrent.thread
internal fun runCommand(
command: List<String>,
logger: Logger? = null,
errorHandler: ((retCode: Int, output: String, process: Process) -> String?)? = null,
exceptionHandler: ((ex: IOException) -> Unit)? = null,
processConfiguration: ProcessBuilder.() -> Unit = { }
): String {
var process: Process? = null
try {
process = ProcessBuilder(command)
.apply {
this.processConfiguration()
}.start()
} catch (e: IOException) {
if (exceptionHandler != null) exceptionHandler(e) else throw e
}
if (process == null) {
throw IllegalStateException("Failed to run command ${command.joinToString(" ")}")
}
var inputText = ""
var errorText = ""
val inputThread = thread {
inputText = process.inputStream.use {
it.reader().readText()
}
}
val errorThread = thread {
errorText = process.errorStream.use {
it.reader().readText()
}
}
inputThread.join()
errorThread.join()
val retCode = process.waitFor()
logger?.info(
"""
|Information about "${command.joinToString(" ")}" call:
|
|${inputText}
""".trimMargin()
)
check(retCode == 0) {
errorHandler?.invoke(retCode, inputText.ifBlank { errorText }, process)
?: """
|Executing of '${command.joinToString(" ")}' failed with code $retCode and message:
|
|$inputText
|
|$errorText
|
""".trimMargin()
}
return inputText
}
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.utils
import org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
import org.jetbrains.kotlin.konan.target.Architecture.ARM32
import org.jetbrains.kotlin.konan.target.Architecture.ARM64
import org.jetbrains.kotlin.konan.target.Family.*
import org.jetbrains.kotlin.konan.target.KonanTarget
internal object Xcode {
val currentVersion: String by lazy {
val out = runCommand(listOf("/usr/bin/xcrun", "xcodebuild", "-version"))
out.lines()[0].removePrefix("Xcode ")
}
fun defaultBitcodeEmbeddingMode(target: KonanTarget, buildType: NativeBuildType): BitcodeEmbeddingMode {
if (currentVersion.split(".")[0].toInt() < 14) {
if (target.family in listOf(IOS, WATCHOS, TVOS) && target.architecture in listOf(ARM32, ARM64)) {
when (buildType) {
NativeBuildType.RELEASE -> return BitcodeEmbeddingMode.BITCODE
NativeBuildType.DEBUG -> return BitcodeEmbeddingMode.MARKER
}
}
}
return BitcodeEmbeddingMode.DISABLE
}
}