[KT-47355] Support macOS targets in FatFramework task.
This commit is contained in:
committed by
Space
parent
09a72fd679
commit
d5164fbc86
+41
-6
@@ -7,12 +7,14 @@ package org.jetbrains.kotlin.gradle.native
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.gradle.*
|
import org.jetbrains.kotlin.gradle.*
|
||||||
import org.jetbrains.kotlin.gradle.embedProject
|
import org.jetbrains.kotlin.gradle.embedProject
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.FrameworkLayout
|
||||||
import org.jetbrains.kotlin.gradle.transformProjectWithPluginsDsl
|
import org.jetbrains.kotlin.gradle.transformProjectWithPluginsDsl
|
||||||
import org.jetbrains.kotlin.gradle.util.*
|
import org.jetbrains.kotlin.gradle.util.*
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
import org.jetbrains.kotlin.konan.target.HostManager
|
||||||
import org.junit.Assume
|
import org.junit.Assume
|
||||||
import org.junit.BeforeClass
|
import org.junit.BeforeClass
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
@@ -71,10 +73,39 @@ class FatFrameworkIT : BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun smokeMacos() {
|
||||||
|
with(transformProjectWithPluginsDsl("smoke", directoryPrefix = "native-fat-framework")) {
|
||||||
|
|
||||||
|
gradleBuildScript().modify {
|
||||||
|
it.checkedReplace("iosArm32()", "")
|
||||||
|
.checkedReplace("iosArm64()", "macosArm64()")
|
||||||
|
.checkedReplace("iosX64()", "macosX64()")
|
||||||
|
}
|
||||||
|
|
||||||
|
build("fat") {
|
||||||
|
checkSmokeBuild(
|
||||||
|
archs = listOf("x64", "arm64"),
|
||||||
|
targetPrefix = "macos",
|
||||||
|
expectedPlistPlatform = "MacOSX",
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
val binary = fileInWorkingDir("build/fat-framework/smoke.framework/Versions/A/smoke")
|
||||||
|
with(runProcess(listOf("file", binary.absolutePath), projectDir)) {
|
||||||
|
assertTrue(isSuccessful)
|
||||||
|
assertTrue(output.contains("\\(for architecture x86_64\\):\\s+Mach-O 64-bit dynamically linked shared library x86_64".toRegex()))
|
||||||
|
assertTrue(output.contains("\\(for architecture arm64\\):\\s+Mach-O 64-bit dynamically linked shared library arm64".toRegex()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun CompiledProject.checkSmokeBuild(
|
private fun CompiledProject.checkSmokeBuild(
|
||||||
archs: List<String>,
|
archs: List<String>,
|
||||||
targetPrefix: String,
|
targetPrefix: String,
|
||||||
expectedPlistPlatform: String
|
expectedPlistPlatform: String,
|
||||||
|
isMacosFramework: Boolean = false
|
||||||
) {
|
) {
|
||||||
assertSuccessful()
|
assertSuccessful()
|
||||||
val linkTasks = archs.map {
|
val linkTasks = archs.map {
|
||||||
@@ -89,17 +120,21 @@ class FatFrameworkIT : BaseGradleIT() {
|
|||||||
assertTasksExecuted(linkTasks)
|
assertTasksExecuted(linkTasks)
|
||||||
assertTasksExecuted(":fat")
|
assertTasksExecuted(":fat")
|
||||||
|
|
||||||
assertFileExists("build/fat-framework/smoke.framework/smoke")
|
val frameworkLayout = FrameworkLayout(fileInWorkingDir("build/fat-framework/smoke.framework"), isMacosFramework)
|
||||||
assertFileExists("build/fat-framework/smoke.framework/Headers/smoke.h")
|
|
||||||
assertFileExists("build/fat-framework/smoke.framework.dSYM/Contents/Resources/DWARF/smoke")
|
|
||||||
|
|
||||||
val headerContent = fileInWorkingDir("build/fat-framework/smoke.framework/Headers/smoke.h").readText()
|
fun File.projectRelative() = relativeTo(File(workingDir, project.projectName)).path
|
||||||
|
|
||||||
|
assertFileExists(frameworkLayout.binary.projectRelative())
|
||||||
|
assertFileExists(frameworkLayout.header.projectRelative())
|
||||||
|
assertFileExists(frameworkLayout.dSYM.binary.projectRelative())
|
||||||
|
|
||||||
|
val headerContent = frameworkLayout.header.readText()
|
||||||
assertTrue(
|
assertTrue(
|
||||||
headerContent.contains("+ (int32_t)foo __attribute__((swift_name(\"foo()\")));"),
|
headerContent.contains("+ (int32_t)foo __attribute__((swift_name(\"foo()\")));"),
|
||||||
"Unexpected header content:\n$headerContent"
|
"Unexpected header content:\n$headerContent"
|
||||||
)
|
)
|
||||||
|
|
||||||
val plistContent = fileInWorkingDir("build/fat-framework/smoke.framework/Info.plist")
|
val plistContent = frameworkLayout.infoPlist
|
||||||
.readLines()
|
.readLines()
|
||||||
.joinToString(separator = "\n") { it.trim() }
|
.joinToString(separator = "\n") { it.trim() }
|
||||||
|
|
||||||
|
|||||||
+33
-16
@@ -20,8 +20,11 @@ import org.jetbrains.kotlin.konan.target.HostManager
|
|||||||
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.target.KonanTarget.*
|
||||||
import org.jetbrains.kotlin.konan.util.visibleName
|
import org.jetbrains.kotlin.konan.util.visibleName
|
||||||
|
import org.jetbrains.kotlin.utils.PathUtil
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
class FrameworkDsymLayout(val rootDir: File) {
|
class FrameworkDsymLayout(val rootDir: File) {
|
||||||
init {
|
init {
|
||||||
@@ -41,27 +44,43 @@ class FrameworkDsymLayout(val rootDir: File) {
|
|||||||
fun exists() = rootDir.exists()
|
fun exists() = rootDir.exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
class FrameworkLayout(val rootDir: File) {
|
class FrameworkLayout(
|
||||||
|
val rootDir: File,
|
||||||
|
val isMacosFramework: Boolean
|
||||||
|
) {
|
||||||
init {
|
init {
|
||||||
require(rootDir.extension == "framework")
|
require(rootDir.extension == "framework")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val frameworkName = rootDir.nameWithoutExtension
|
private val frameworkName = rootDir.nameWithoutExtension
|
||||||
|
private val macosVersionsDir = rootDir.resolve("Versions")
|
||||||
|
private val macosADir = macosVersionsDir.resolve("A")
|
||||||
|
private val macosResourcesDir = macosADir.resolve("Resources")
|
||||||
|
private val contentDir = if (isMacosFramework) macosADir else rootDir
|
||||||
|
|
||||||
val headerDir = rootDir.resolve("Headers")
|
val headerDir = contentDir.resolve("Headers")
|
||||||
val modulesDir = rootDir.resolve("Modules")
|
val modulesDir = contentDir.resolve("Modules")
|
||||||
|
|
||||||
val binary = rootDir.resolve(frameworkName)
|
val binary = contentDir.resolve(frameworkName)
|
||||||
val header = headerDir.resolve("$frameworkName.h")
|
val header = headerDir.resolve("$frameworkName.h")
|
||||||
val moduleFile = modulesDir.resolve("module.modulemap")
|
val moduleFile = modulesDir.resolve("module.modulemap")
|
||||||
val infoPlist = rootDir.resolve("Info.plist")
|
val infoPlist = (if (isMacosFramework) macosResourcesDir else rootDir).resolve("Info.plist")
|
||||||
|
|
||||||
val dSYM = FrameworkDsymLayout(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.mkdirs()
|
||||||
modulesDir.mkdir()
|
modulesDir.mkdirs()
|
||||||
|
if (isMacosFramework) {
|
||||||
|
macosResourcesDir.mkdirs()
|
||||||
|
val root = rootDir.toPath()
|
||||||
|
Files.createSymbolicLink(root.resolve("Headers"), headerDir.toPath())
|
||||||
|
Files.createSymbolicLink(root.resolve("Modules"), modulesDir.toPath())
|
||||||
|
Files.createSymbolicLink(root.resolve("Resources"), macosResourcesDir.toPath())
|
||||||
|
Files.createSymbolicLink(root.resolve(frameworkName), binary.toPath())
|
||||||
|
Files.createSymbolicLink(macosVersionsDir.toPath().resolve("Current"), macosADir.toPath())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exists() = rootDir.exists()
|
fun exists() = rootDir.exists()
|
||||||
@@ -83,7 +102,7 @@ class FrameworkDescriptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val name = file.nameWithoutExtension
|
val name = file.nameWithoutExtension
|
||||||
val files = FrameworkLayout(file)
|
val files = FrameworkLayout(file, target.family == Family.OSX)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,9 +143,6 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
val fatFramework: File
|
val fatFramework: File
|
||||||
get() = destinationDir.resolve(fatFrameworkName + ".framework")
|
get() = destinationDir.resolve(fatFrameworkName + ".framework")
|
||||||
|
|
||||||
private val fatFrameworkLayout: FrameworkLayout
|
|
||||||
get() = FrameworkLayout(fatFramework)
|
|
||||||
|
|
||||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||||
@get:IgnoreEmptyDirectories
|
@get:IgnoreEmptyDirectories
|
||||||
@get:InputFiles
|
@get:InputFiles
|
||||||
@@ -212,6 +228,7 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
|
|
||||||
private val FrameworkDescriptor.plistPlatform: String
|
private val FrameworkDescriptor.plistPlatform: String
|
||||||
get() = when (target) {
|
get() = when (target) {
|
||||||
|
MACOS_X64, MACOS_ARM64 -> "MacOSX"
|
||||||
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"
|
||||||
@@ -358,7 +375,7 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mergeDSYM() {
|
private fun mergeDSYM(fatDsym: FrameworkDsymLayout) {
|
||||||
val dsymInputs = archToFramework.mapValues { (_, framework) ->
|
val dsymInputs = archToFramework.mapValues { (_, framework) ->
|
||||||
framework.files.dSYM
|
framework.files.dSYM
|
||||||
}.filterValues {
|
}.filterValues {
|
||||||
@@ -369,7 +386,6 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val fatDsym = fatFrameworkLayout.dSYM
|
|
||||||
fatDsym.mkdirs()
|
fatDsym.mkdirs()
|
||||||
|
|
||||||
// Merge dSYM binary.
|
// Merge dSYM binary.
|
||||||
@@ -386,21 +402,22 @@ open class FatFrameworkTask : DefaultTask() {
|
|||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
protected fun createFatFramework() {
|
protected fun createFatFramework() {
|
||||||
val outFramework = fatFrameworkLayout
|
val outFramework = FrameworkLayout(fatFramework, getFatFrameworkFamily() == Family.OSX)
|
||||||
|
|
||||||
outFramework.mkdirs()
|
outFramework.mkdirs()
|
||||||
mergeBinaries(outFramework.binary)
|
mergeBinaries(outFramework.binary)
|
||||||
mergeHeaders(outFramework.header)
|
mergeHeaders(outFramework.header)
|
||||||
createModuleFile(outFramework.moduleFile, fatFrameworkName)
|
createModuleFile(outFramework.moduleFile, fatFrameworkName)
|
||||||
mergePlists(outFramework.infoPlist, fatFrameworkName)
|
mergePlists(outFramework.infoPlist, fatFrameworkName)
|
||||||
mergeDSYM()
|
mergeDSYM(outFramework.dSYM)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val supportedTargets = listOf(
|
private val supportedTargets = listOf(
|
||||||
IOS_ARM32, IOS_ARM64, IOS_X64,
|
IOS_ARM32, IOS_ARM64, IOS_X64,
|
||||||
WATCHOS_ARM32, WATCHOS_ARM64, WATCHOS_X86, WATCHOS_X64,
|
WATCHOS_ARM32, WATCHOS_ARM64, WATCHOS_X86, WATCHOS_X64,
|
||||||
TVOS_ARM64, TVOS_X64
|
TVOS_ARM64, TVOS_X64,
|
||||||
|
MACOS_X64, MACOS_ARM64
|
||||||
)
|
)
|
||||||
|
|
||||||
fun isSupportedTarget(target: KotlinNativeTarget): Boolean {
|
fun isSupportedTarget(target: KotlinNativeTarget): Boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user