Refactor FatFrameworkTask: use FrameworkDescriptor instead Framework.
for independence from module compilation.
This commit is contained in:
committed by
Space
parent
c3c79b874d
commit
a9f850dac0
+1
-1
@@ -85,7 +85,7 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
|
|||||||
project.afterEvaluate {
|
project.afterEvaluate {
|
||||||
val task = taskProvider.get()
|
val task = taskProvider.get()
|
||||||
val artifactFile = when (task) {
|
val artifactFile = when (task) {
|
||||||
is FatFrameworkTask -> task.fatFrameworkDir
|
is FatFrameworkTask -> task.fatFramework
|
||||||
else -> binary.outputFile
|
else -> binary.outputFile
|
||||||
}
|
}
|
||||||
val linkArtifact = project.artifacts.add(name, artifactFile) { artifact ->
|
val linkArtifact = project.artifacts.add(name, artifactFile) { artifact ->
|
||||||
|
|||||||
+70
-49
@@ -12,20 +12,22 @@ import org.gradle.api.tasks.*
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
|
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
|
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind
|
||||||
import org.jetbrains.kotlin.gradle.utils.appendLine
|
import org.jetbrains.kotlin.gradle.utils.appendLine
|
||||||
import org.jetbrains.kotlin.konan.target.Architecture
|
import org.jetbrains.kotlin.konan.target.Architecture
|
||||||
import org.jetbrains.kotlin.konan.target.Family
|
import org.jetbrains.kotlin.konan.target.Family
|
||||||
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
||||||
import org.jetbrains.kotlin.konan.util.visibleName
|
import org.jetbrains.kotlin.konan.util.visibleName
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
private val Framework.files: IosFrameworkFiles
|
class FrameworkDsymLayout(val rootDir: File) {
|
||||||
get() = IosFrameworkFiles(outputFile)
|
init {
|
||||||
|
require(rootDir.extension == "framework.dSYM")
|
||||||
|
}
|
||||||
|
|
||||||
private class IosDsymFiles(val rootDir: File) {
|
private val frameworkName = rootDir.name.removeSuffix(".framework.dSYM")
|
||||||
|
|
||||||
val frameworkName = rootDir.name.removeSuffix(".framework.dSYM")
|
|
||||||
|
|
||||||
val binaryDir = rootDir.resolve("Contents/Resources/DWARF")
|
val binaryDir = rootDir.resolve("Contents/Resources/DWARF")
|
||||||
val binary = binaryDir.resolve(frameworkName)
|
val binary = binaryDir.resolve(frameworkName)
|
||||||
@@ -35,15 +37,15 @@ private class IosDsymFiles(val rootDir: File) {
|
|||||||
binaryDir.mkdirs()
|
binaryDir.mkdirs()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exists(): Boolean = rootDir.exists()
|
fun exists() = rootDir.exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class IosFrameworkFiles(val rootDir: File) {
|
class FrameworkLayout(val rootDir: File) {
|
||||||
|
init {
|
||||||
|
require(rootDir.extension == "framework")
|
||||||
|
}
|
||||||
|
|
||||||
constructor(parentDir: File, frameworkName: String):
|
private val frameworkName = rootDir.nameWithoutExtension
|
||||||
this(parentDir.resolve("$frameworkName.framework"))
|
|
||||||
|
|
||||||
val frameworkName: String = rootDir.nameWithoutExtension
|
|
||||||
|
|
||||||
val headerDir = rootDir.resolve("Headers")
|
val headerDir = rootDir.resolve("Headers")
|
||||||
val modulesDir = rootDir.resolve("Modules")
|
val modulesDir = rootDir.resolve("Modules")
|
||||||
@@ -53,26 +55,48 @@ private class IosFrameworkFiles(val rootDir: File) {
|
|||||||
val moduleFile = modulesDir.resolve("module.modulemap")
|
val moduleFile = modulesDir.resolve("module.modulemap")
|
||||||
val infoPlist = rootDir.resolve("Info.plist")
|
val infoPlist = rootDir.resolve("Info.plist")
|
||||||
|
|
||||||
val dSYM: IosDsymFiles = IosDsymFiles(rootDir.parentFile.resolve("$frameworkName.framework.dSYM"))
|
val dSYM = FrameworkDsymLayout(rootDir.parentFile.resolve("$frameworkName.framework.dSYM"))
|
||||||
|
|
||||||
fun mkdirs() {
|
fun mkdirs() {
|
||||||
rootDir.mkdirs()
|
rootDir.mkdirs()
|
||||||
headerDir.mkdir()
|
headerDir.mkdir()
|
||||||
modulesDir.mkdir()
|
modulesDir.mkdir()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun exists() = rootDir.exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
class FrameworkDescriptor(
|
||||||
|
val file: File,
|
||||||
|
val isStatic: Boolean,
|
||||||
|
val target: KonanTarget
|
||||||
|
) {
|
||||||
|
constructor(framework: Framework) : this(
|
||||||
|
framework.outputFile,
|
||||||
|
framework.isStatic,
|
||||||
|
framework.konanTarget
|
||||||
|
)
|
||||||
|
|
||||||
|
init {
|
||||||
|
require(NativeOutputKind.FRAMEWORK.availableFor(target))
|
||||||
|
}
|
||||||
|
|
||||||
|
val name = file.nameWithoutExtension
|
||||||
|
val files = FrameworkLayout(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Task running lipo to create a fat framework from several simple frameworks. It also merges headers, plists and module files.
|
* Task running lipo to create a fat framework from several simple frameworks. It also merges headers, plists and module files.
|
||||||
*/
|
*/
|
||||||
open class FatFrameworkTask : DefaultTask() {
|
open class FatFrameworkTask : DefaultTask() {
|
||||||
|
private val archToFramework: MutableMap<Architecture, FrameworkDescriptor> = mutableMapOf()
|
||||||
|
|
||||||
//region DSL properties.
|
//region DSL properties.
|
||||||
/**
|
/**
|
||||||
* A collection of frameworks used ot build the fat framework.
|
* A collection of frameworks used ot build the fat framework.
|
||||||
*/
|
*/
|
||||||
@get:Internal // We take it into account as an input in the inputFrameworkFiles property.
|
@get:Internal // We take it into account as an input in the inputFrameworkFiles property.
|
||||||
val frameworks: Collection<Framework>
|
val frameworks: Collection<FrameworkDescriptor>
|
||||||
get() = archToFramework.values
|
get() = archToFramework.values
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,33 +111,23 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
@OutputDirectory
|
@OutputDirectory
|
||||||
var destinationDir: File = project.buildDir.resolve("fat-framework")
|
var destinationDir: File = project.buildDir.resolve("fat-framework")
|
||||||
|
|
||||||
@get:Internal // We take it into account as an input in the destinationDir property.
|
|
||||||
val fatFrameworkDir: File
|
|
||||||
get() = fatFramework.rootDir
|
|
||||||
|
|
||||||
@get:Internal // We take it into account as an input in the destinationDir property.
|
|
||||||
val fatDsymDir: File
|
|
||||||
get() = fatDsym.rootDir
|
|
||||||
// endregion.
|
|
||||||
|
|
||||||
private val archToFramework: MutableMap<Architecture, Framework> = mutableMapOf()
|
|
||||||
|
|
||||||
@get:Internal
|
@get:Internal
|
||||||
val fatFrameworkName: String
|
val fatFrameworkName: String
|
||||||
get() = baseName.asValidFrameworkName()
|
get() = baseName.asValidFrameworkName()
|
||||||
|
|
||||||
private val fatFramework: IosFrameworkFiles
|
@get:Internal
|
||||||
get() = IosFrameworkFiles(destinationDir, fatFrameworkName)
|
val fatFramework: File
|
||||||
|
get() = destinationDir.resolve(fatFrameworkName + ".framework")
|
||||||
|
|
||||||
private val fatDsym: IosDsymFiles
|
private val fatFrameworkLayout: FrameworkLayout
|
||||||
get() = fatFramework.dSYM
|
get() = FrameworkLayout(fatFramework)
|
||||||
|
|
||||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||||
@get:IgnoreEmptyDirectories
|
@get:IgnoreEmptyDirectories
|
||||||
@get:InputFiles
|
@get:InputFiles
|
||||||
@get:SkipWhenEmpty
|
@get:SkipWhenEmpty
|
||||||
protected val inputFrameworkFiles: Iterable<FileTree>
|
protected val inputFrameworkFiles: Iterable<FileTree>
|
||||||
get() = frameworks.map { project.fileTree(it.outputFile) }
|
get() = frameworks.map { project.fileTree(it.file) }
|
||||||
|
|
||||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||||
@get:IgnoreEmptyDirectories
|
@get:IgnoreEmptyDirectories
|
||||||
@@ -137,9 +151,17 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
* Adds the specified frameworks in this fat framework.
|
* Adds the specified frameworks in this fat framework.
|
||||||
*/
|
*/
|
||||||
fun from(frameworks: Iterable<Framework>) {
|
fun from(frameworks: Iterable<Framework>) {
|
||||||
|
fromFrameworkDescriptors(frameworks.map { FrameworkDescriptor(it) })
|
||||||
|
frameworks.forEach { dependsOn(it.linkTask) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the specified frameworks in this fat framework.
|
||||||
|
*/
|
||||||
|
fun fromFrameworkDescriptors(frameworks: Iterable<FrameworkDescriptor>) {
|
||||||
frameworks.forEach { framework ->
|
frameworks.forEach { framework ->
|
||||||
val arch = framework.konanTarget.architecture
|
val arch = framework.target.architecture
|
||||||
val family = framework.konanTarget.family
|
val family = framework.target.family
|
||||||
val fatFrameworkFamily = getFatFrameworkFamily()
|
val fatFrameworkFamily = getFatFrameworkFamily()
|
||||||
require(fatFrameworkFamily == null || family == fatFrameworkFamily) {
|
require(fatFrameworkFamily == null || family == fatFrameworkFamily) {
|
||||||
"Cannot add a binary with platform family '${family.visibleName}' to the fat framework:\n" +
|
"Cannot add a binary with platform family '${family.visibleName}' to the fat framework:\n" +
|
||||||
@@ -154,30 +176,28 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
require(archToFramework.all { it.value.isStatic == framework.isStatic }) {
|
require(archToFramework.all { it.value.isStatic == framework.isStatic }) {
|
||||||
fun Framework.staticOrDynamic(): String = if (isStatic) "static" else "dynamic"
|
fun staticName(isStatic: Boolean) = if (isStatic) "static" else "dynamic"
|
||||||
|
|
||||||
buildString {
|
buildString {
|
||||||
append("Cannot create a fat framework from:\n")
|
append("Cannot create a fat framework from:\n")
|
||||||
archToFramework.forEach { append("${it.value.baseName} - ${it.key.name.toLowerCase()} - ${it.value.staticOrDynamic()}\n") }
|
archToFramework.forEach { append("${it.value.name} - ${it.key.name.toLowerCase()} - ${staticName(it.value.isStatic)}\n") }
|
||||||
append("${framework.baseName} - ${arch.name.toLowerCase()} - ${framework.staticOrDynamic()}\n")
|
append("${framework.name} - ${arch.name.toLowerCase()} - ${staticName(framework.isStatic)}\n")
|
||||||
append("All input frameworks must be either static or dynamic")
|
append("All input frameworks must be either static or dynamic")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
archToFramework[arch] = framework
|
archToFramework[arch] = framework
|
||||||
dependsOn(framework.linkTask)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// endregion.
|
// endregion.
|
||||||
|
|
||||||
private fun getFatFrameworkFamily(): Family? {
|
private fun getFatFrameworkFamily(): Family? {
|
||||||
assert(archToFramework.values.distinctBy { it.konanTarget.family }.size <= 1)
|
assert(archToFramework.values.distinctBy { it.target.family }.size <= 1)
|
||||||
return archToFramework.values.firstOrNull()?.konanTarget?.family
|
return archToFramework.values.firstOrNull()?.target?.family
|
||||||
}
|
}
|
||||||
|
|
||||||
private val Architecture.clangMacro: String
|
private val Architecture.clangMacro: String
|
||||||
get() = when(this) {
|
get() = when (this) {
|
||||||
Architecture.X86 -> "__i386__"
|
Architecture.X86 -> "__i386__"
|
||||||
Architecture.X64 -> "__x86_64__"
|
Architecture.X64 -> "__x86_64__"
|
||||||
Architecture.ARM32 -> "__arm__"
|
Architecture.ARM32 -> "__arm__"
|
||||||
@@ -185,12 +205,12 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
else -> error("Fat frameworks are not supported for architecture `$name`")
|
else -> error("Fat frameworks are not supported for architecture `$name`")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val Framework.plistPlatform: String
|
private val FrameworkDescriptor.plistPlatform: String
|
||||||
get() = when (konanTarget) {
|
get() = when (target) {
|
||||||
IOS_ARM32, IOS_ARM64, IOS_X64, IOS_SIMULATOR_ARM64 -> "iPhoneOS"
|
IOS_ARM32, IOS_ARM64, IOS_X64, IOS_SIMULATOR_ARM64 -> "iPhoneOS"
|
||||||
TVOS_ARM64, TVOS_X64, TVOS_SIMULATOR_ARM64 -> "AppleTVOS"
|
TVOS_ARM64, TVOS_X64, TVOS_SIMULATOR_ARM64 -> "AppleTVOS"
|
||||||
WATCHOS_ARM32, WATCHOS_ARM64, WATCHOS_X86, WATCHOS_X64, WATCHOS_SIMULATOR_ARM64 -> "WatchOS"
|
WATCHOS_ARM32, WATCHOS_ARM64, WATCHOS_X86, WATCHOS_X64, WATCHOS_SIMULATOR_ARM64 -> "WatchOS"
|
||||||
else -> error("Fat frameworks are not supported for platform `${konanTarget.visibleName}`")
|
else -> error("Fat frameworks are not supported for platform `${target.visibleName}`")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runs the PlistBuddy utility with the given commands to configure the given plist file.
|
// Runs the PlistBuddy utility with the given commands to configure the given plist file.
|
||||||
@@ -248,7 +268,7 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
|
|
||||||
runLipo(archToFramework.values.map { it.files.binary }, outputFile)
|
runLipo(archToFramework.values.map { it.files.binary }, outputFile)
|
||||||
|
|
||||||
if (archToFramework.values.any{ it.isStatic.not() && it.baseName != fatFrameworkName }) {
|
if (archToFramework.values.any { !it.isStatic && it.name != fatFrameworkName }) {
|
||||||
runInstallNameTool(outputFile, fatFrameworkName)
|
runInstallNameTool(outputFile, fatFrameworkName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,6 +364,7 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val fatDsym = fatFrameworkLayout.dSYM
|
||||||
fatDsym.mkdirs()
|
fatDsym.mkdirs()
|
||||||
|
|
||||||
// Merge dSYM binary.
|
// Merge dSYM binary.
|
||||||
@@ -360,13 +381,13 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
protected fun createFatFramework() {
|
protected fun createFatFramework() {
|
||||||
fatFramework.mkdirs()
|
val outFramework = fatFrameworkLayout
|
||||||
|
|
||||||
val frameworkName = fatFramework.frameworkName
|
outFramework.mkdirs()
|
||||||
mergeBinaries(fatFramework.binary)
|
mergeBinaries(outFramework.binary)
|
||||||
mergeHeaders(fatFramework.header)
|
mergeHeaders(outFramework.header)
|
||||||
createModuleFile(fatFramework.moduleFile, frameworkName)
|
createModuleFile(outFramework.moduleFile, fatFrameworkName)
|
||||||
mergePlists(fatFramework.infoPlist, frameworkName)
|
mergePlists(outFramework.infoPlist, fatFrameworkName)
|
||||||
mergeDSYM()
|
mergeDSYM()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user