Implement Info.plist generation for produced frameworks
This commit is contained in:
committed by
SvyatoslavScherbina
parent
954caf836a
commit
5ade7505b3
+1
-1
@@ -107,7 +107,7 @@ internal open class MacOSBasedPlatform(distribution: Distribution)
|
||||
open val osVersionMin by lazy {
|
||||
listOf(
|
||||
propertyTargetString("osVersionMinFlagLd"),
|
||||
propertyTargetString("osVersionMin") + ".0")
|
||||
properties.osVersionMin!! + ".0")
|
||||
}
|
||||
|
||||
override fun filterStaticLibraries(binaries: List<String>)
|
||||
|
||||
+18
-4
@@ -35,10 +35,7 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
@@ -322,3 +319,20 @@ fun AnnotationDescriptor.getStringValueOrNull(name: String): String? {
|
||||
}
|
||||
|
||||
fun AnnotationDescriptor.getStringValue(name: String): String = this.getStringValueOrNull(name)!!
|
||||
|
||||
private fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
|
||||
val result = mutableSetOf<FqName>()
|
||||
|
||||
fun getSubPackages(fqName: FqName) {
|
||||
result.add(fqName)
|
||||
module.getSubPackagesOf(fqName) { true }.forEach { getSubPackages(it) }
|
||||
}
|
||||
|
||||
getSubPackages(FqName.ROOT)
|
||||
return result
|
||||
}
|
||||
|
||||
fun ModuleDescriptor.getPackageFragments(): List<PackageFragmentDescriptor> =
|
||||
getPackagesFqNames(this).flatMap {
|
||||
getPackage(it).fragments.filter { it.module == this }
|
||||
}
|
||||
|
||||
+110
@@ -17,12 +17,21 @@
|
||||
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getPackageFragments
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.CodeGenerator
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.objcexport.ObjCExportCodeGenerator
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.isSubpackageOf
|
||||
|
||||
internal class ObjCExport(val context: Context) {
|
||||
|
||||
private val target get() = context.config.targetManager.target
|
||||
|
||||
internal fun produceObjCFramework() {
|
||||
if (context.config.produce != CompilerOutputKind.FRAMEWORK) return
|
||||
|
||||
@@ -55,7 +64,108 @@ internal class ObjCExport(val context: Context) {
|
||||
|
||||
modules.child("module.modulemap").writeBytes(moduleMap.toByteArray())
|
||||
|
||||
emitInfoPlist(framework, frameworkName)
|
||||
|
||||
val objCCodeGenerator = ObjCExportCodeGenerator(CodeGenerator(context), namer, mapper)
|
||||
objCCodeGenerator.emitRtti(headerGenerator.generatedClasses, headerGenerator.topLevel)
|
||||
}
|
||||
|
||||
private fun emitInfoPlist(framework: File, name: String) {
|
||||
val directory = when (target) {
|
||||
KonanTarget.IPHONE,
|
||||
KonanTarget.IPHONE_SIM -> framework
|
||||
KonanTarget.MACBOOK -> framework.child("Resources").also { it.mkdirs() }
|
||||
else -> error(target)
|
||||
}
|
||||
|
||||
val file = directory.child("Info.plist")
|
||||
val bundleExecutable = name
|
||||
val pkg = context.moduleDescriptor.guessMainPackage() // TODO: consider showing warning if it is root.
|
||||
val bundleId = pkg.child(Name.identifier(name)).asString()
|
||||
|
||||
val platform = when (target) {
|
||||
KonanTarget.IPHONE -> "iPhoneOS"
|
||||
KonanTarget.IPHONE_SIM -> "iPhoneSimulator"
|
||||
KonanTarget.MACBOOK -> "MacOSX"
|
||||
else -> error(target)
|
||||
}
|
||||
val minimumOsVersion = context.config.distribution.targetProperties.osVersionMin!!
|
||||
|
||||
val contents = StringBuilder()
|
||||
contents.append("""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$bundleExecutable</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$bundleId</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$name</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>$platform</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
|
||||
""".trimIndent())
|
||||
|
||||
|
||||
contents.append(when (target) {
|
||||
KonanTarget.IPHONE,
|
||||
KonanTarget.IPHONE_SIM -> """
|
||||
| <key>MinimumOSVersion</key>
|
||||
| <string>$minimumOsVersion</string>
|
||||
| <key>UIDeviceFamily</key>
|
||||
| <array>
|
||||
| <integer>1</integer>
|
||||
| <integer>2</integer>
|
||||
| </array>
|
||||
|
||||
""".trimMargin()
|
||||
KonanTarget.MACBOOK -> ""
|
||||
else -> error(target)
|
||||
})
|
||||
|
||||
if (target == KonanTarget.IPHONE) {
|
||||
contents.append("""
|
||||
| <key>UIRequiredDeviceCapabilities</key>
|
||||
| <array>
|
||||
| <string>arm64</string>
|
||||
| </array>
|
||||
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
contents.append("""
|
||||
</dict>
|
||||
</plist>
|
||||
""".trimIndent())
|
||||
|
||||
// TODO: Xcode also add some number of DT* keys.
|
||||
|
||||
file.writeBytes(contents.toString().toByteArray())
|
||||
}
|
||||
}
|
||||
|
||||
private fun ModuleDescriptor.guessMainPackage(): FqName {
|
||||
val allPackages = this.getPackageFragments() // Includes also all parent packages, e.g. the root one.
|
||||
|
||||
val nonEmptyPackages = allPackages
|
||||
.filter { it.getMemberScope().getContributedDescriptors().isNotEmpty() }
|
||||
.map { it.fqName }.distinct()
|
||||
|
||||
return allPackages.map { it.fqName }.distinct()
|
||||
.filter { candidate -> nonEmptyPackages.all { it.isSubpackageOf(candidate) } }
|
||||
// Now there are all common ancestors of non-empty packages. Longest of them is the least common accessor:
|
||||
.maxBy { it.asString().length }!!
|
||||
}
|
||||
|
||||
+1
-17
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getPackageFragments
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
|
||||
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
@@ -568,20 +569,3 @@ private inline fun buildStub(block: StubBuilder.() -> Unit) = StubBuilder().let
|
||||
private inline fun MutableCollection<Stub>.addBuiltBy(block: StubBuilder.() -> Unit) {
|
||||
this.add(buildStub(block))
|
||||
}
|
||||
|
||||
private fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
|
||||
val result = mutableSetOf<FqName>()
|
||||
|
||||
fun getSubPackages(fqName: FqName) {
|
||||
result.add(fqName)
|
||||
module.getSubPackagesOf(fqName) { true }.forEach { getSubPackages(it) }
|
||||
}
|
||||
|
||||
getSubPackages(FqName.ROOT)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun ModuleDescriptor.getPackageFragments(): List<PackageFragmentDescriptor> =
|
||||
getPackagesFqNames(this).flatMap {
|
||||
getPackage(it).fragments.filter { it.module == this }
|
||||
}
|
||||
|
||||
@@ -73,4 +73,6 @@ class KonanProperties(val target: KonanTarget, val properties: Properties, val b
|
||||
// Use (equal) llvmHome fow now.
|
||||
return targetString("llvmHome")
|
||||
}
|
||||
|
||||
val osVersionMin: String? get() = targetString("osVersionMin")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user