Prepare test infrastructure for Apple Silicon simulators.
* Get rid of explicit target enumerations by using TargetTriple. * Remove some code duplication with `project.testTargetConfigurables`
This commit is contained in:
committed by
TeamCityServer
parent
cebf815fed
commit
437a0aa450
@@ -46,42 +46,32 @@ interface ExecutorService {
|
||||
* Creates an ExecutorService depending on a test target -Ptest_target
|
||||
*/
|
||||
fun create(project: Project): ExecutorService {
|
||||
val platformManager = project.platformManager
|
||||
val testTarget = project.testTarget
|
||||
val platform = platformManager.platform(testTarget)
|
||||
val absoluteTargetToolchain = platform.absoluteTargetToolchain
|
||||
|
||||
return if (project.hasProperty("remote")) {
|
||||
sshExecutor(project)
|
||||
} else when (testTarget) {
|
||||
KonanTarget.WASM32 -> object : ExecutorService {
|
||||
override fun execute(action: Action<in ExecSpec>): ExecResult? = project.exec {
|
||||
action.execute(this)
|
||||
val exe = executable
|
||||
val d8 = "$absoluteTargetToolchain/bin/d8"
|
||||
val launcherJs = "$executable.js"
|
||||
this.executable = d8
|
||||
this.args = listOf("--expose-wasm", launcherJs, "--", exe) + args
|
||||
}
|
||||
}
|
||||
|
||||
KonanTarget.LINUX_MIPS32,
|
||||
KonanTarget.LINUX_MIPSEL32,
|
||||
KonanTarget.LINUX_ARM32_HFP,
|
||||
KonanTarget.LINUX_ARM64 -> emulatorExecutor(project, testTarget)
|
||||
|
||||
KonanTarget.IOS_X64,
|
||||
KonanTarget.TVOS_X64,
|
||||
KonanTarget.WATCHOS_X86,
|
||||
KonanTarget.WATCHOS_X64 -> simulator(project)
|
||||
|
||||
KonanTarget.IOS_ARM32,
|
||||
KonanTarget.IOS_ARM64 -> deviceLauncher(project)
|
||||
val configurables = project.testTargetConfigurables
|
||||
|
||||
return when {
|
||||
project.hasProperty("remote") -> sshExecutor(project)
|
||||
configurables is WasmConfigurables -> wasmExecutor(project)
|
||||
configurables is ConfigurablesWithEmulator && testTarget != HostManager.host -> emulatorExecutor(project, testTarget)
|
||||
configurables.targetTriple.isSimulator -> simulator(project)
|
||||
testTarget == KonanTarget.IOS_ARM32 || testTarget == KonanTarget.IOS_ARM64 -> deviceLauncher(project)
|
||||
else -> localExecutorService(project)
|
||||
}
|
||||
}
|
||||
|
||||
private fun wasmExecutor(project: Project) = object : ExecutorService {
|
||||
val absoluteTargetToolchain = project.testTargetConfigurables.absoluteTargetToolchain
|
||||
|
||||
override fun execute(action: Action<in ExecSpec>): ExecResult? = project.exec {
|
||||
action.execute(this)
|
||||
val exe = executable
|
||||
val d8 = "$absoluteTargetToolchain/bin/d8"
|
||||
val launcherJs = "$executable.js"
|
||||
this.executable = d8
|
||||
this.args = listOf("--expose-wasm", launcherJs, "--", exe) + args
|
||||
}
|
||||
}
|
||||
|
||||
data class ProcessOutput(var stdOut: String, var stdErr: String, var exitCode: Int)
|
||||
|
||||
/**
|
||||
@@ -196,8 +186,7 @@ fun localExecutorService(project: Project): ExecutorService = object : ExecutorS
|
||||
}
|
||||
|
||||
private fun emulatorExecutor(project: Project, target: KonanTarget) = object : ExecutorService {
|
||||
val platformManager = project.platformManager
|
||||
val configurables = platformManager.platform(target).configurables as? ConfigurablesWithEmulator
|
||||
val configurables = project.testTargetConfigurables as? ConfigurablesWithEmulator
|
||||
?: error("$target does not support emulation!")
|
||||
val absoluteTargetSysRoot = configurables.absoluteTargetSysRoot
|
||||
|
||||
@@ -234,15 +223,19 @@ private fun emulatorExecutor(project: Project, target: KonanTarget) = object : E
|
||||
private fun simulator(project: Project): ExecutorService = object : ExecutorService {
|
||||
|
||||
private val target = project.testTarget
|
||||
val configurables = project.testTargetConfigurables as AppleConfigurables
|
||||
|
||||
init {
|
||||
require(configurables.targetTriple.isSimulator) {
|
||||
"${configurables.target} is not a simulator."
|
||||
}
|
||||
require(HostManager.host.architecture == configurables.target.architecture) {
|
||||
"Can't run simulator with ${configurables.target.architecture} architecture."
|
||||
}
|
||||
}
|
||||
|
||||
private val simctl by lazy {
|
||||
val sdk = when (target) {
|
||||
KonanTarget.TVOS_X64 -> Xcode.current.appletvsimulatorSdk
|
||||
KonanTarget.IOS_X64 -> Xcode.current.iphonesimulatorSdk
|
||||
KonanTarget.WATCHOS_X64,
|
||||
KonanTarget.WATCHOS_X86 -> Xcode.current.watchsimulatorSdk
|
||||
else -> error("Unexpected simulation target: $target")
|
||||
}
|
||||
val sdk = Xcode.current.pathToPlatformSdk(configurables.platformName())
|
||||
val out = ByteArrayOutputStream()
|
||||
val result = project.exec {
|
||||
commandLine("/usr/bin/xcrun", "--find", "simctl", "--sdk", sdk)
|
||||
@@ -282,7 +275,8 @@ private fun simulator(project: Project): ExecutorService = object : ExecutorServ
|
||||
|
||||
private val archSpecification = when (target.architecture) {
|
||||
Architecture.X86 -> listOf("-a", "i386")
|
||||
Architecture.X64 -> listOf() // x86-64 is used by default.
|
||||
Architecture.X64 -> listOf() // x86-64 is used by default on Intel Macs.
|
||||
Architecture.ARM64 -> listOf() // arm64 is used by default on Apple Silicon.
|
||||
else -> error("${target.architecture} can't be used in simulator.")
|
||||
}.toTypedArray()
|
||||
|
||||
|
||||
@@ -178,26 +178,12 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable {
|
||||
* test target.
|
||||
*/
|
||||
private fun getSwiftLibsPathForTestTarget(): String {
|
||||
val target = project.testTarget
|
||||
val platform = project.platformManager.platform(target)
|
||||
val configs = platform.configurables as AppleConfigurables
|
||||
val swiftPlatform = when (target) {
|
||||
KonanTarget.IOS_X64 -> "iphonesimulator"
|
||||
KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64 -> "iphoneos"
|
||||
KonanTarget.TVOS_X64 -> "appletvsimulator"
|
||||
KonanTarget.TVOS_ARM64 -> "appletvos"
|
||||
KonanTarget.MACOS_X64, KonanTarget.MACOS_ARM64 -> "macosx"
|
||||
KonanTarget.WATCHOS_ARM64 -> "watchos"
|
||||
KonanTarget.WATCHOS_X64, KonanTarget.WATCHOS_X86 -> "watchsimulator"
|
||||
else -> throw IllegalStateException("Test target $target is not supported")
|
||||
}
|
||||
val simulatorPath = when (target) {
|
||||
KonanTarget.TVOS_X64,
|
||||
KonanTarget.IOS_X64,
|
||||
KonanTarget.WATCHOS_X86,
|
||||
KonanTarget.WATCHOS_X64 -> Xcode.current.getLatestSimulatorRuntimeFor(target, configs.osVersionMin)?.bundlePath?.let {
|
||||
"$it/Contents/Resources/RuntimeRoot/usr/lib/swift"
|
||||
}
|
||||
val configs = project.testTargetConfigurables as AppleConfigurables
|
||||
val swiftPlatform = configs.platformName().toLowerCase()
|
||||
val simulatorPath = when (configs.targetTriple.isSimulator) {
|
||||
true -> Xcode.current.getLatestSimulatorRuntimeFor(configs.target.family, configs.osVersionMin)
|
||||
?.bundlePath
|
||||
?.let { "$it/Contents/Resources/RuntimeRoot/usr/lib/swift" }
|
||||
else -> null
|
||||
}
|
||||
// Use default path from toolchain if we cannot get `bundlePath` for target.
|
||||
@@ -206,18 +192,16 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable {
|
||||
}
|
||||
|
||||
private fun buildEnvironment(): Map<String, String> {
|
||||
val target = project.testTarget
|
||||
val configs = project.testTargetConfigurables
|
||||
// Hopefully, lexicographical comparison will work.
|
||||
val newMacos = System.getProperty("os.version").compareTo("10.14.4") >= 0
|
||||
val dyldLibraryPathKey = when (target) {
|
||||
KonanTarget.IOS_X64,
|
||||
KonanTarget.WATCHOS_X86,
|
||||
KonanTarget.WATCHOS_X64,
|
||||
KonanTarget.TVOS_X64 -> "SIMCTL_CHILD_DYLD_LIBRARY_PATH"
|
||||
else -> "DYLD_LIBRARY_PATH"
|
||||
val dyldLibraryPathKey = if (configs.targetTriple.isSimulator) {
|
||||
"SIMCTL_CHILD_DYLD_LIBRARY_PATH"
|
||||
} else {
|
||||
"DYLD_LIBRARY_PATH"
|
||||
}
|
||||
// TODO: macos_arm64?
|
||||
return if (newMacos && target == KonanTarget.MACOS_X64) emptyMap() else mapOf(
|
||||
return if (newMacos && configs.target == KonanTarget.MACOS_X64) emptyMap() else mapOf(
|
||||
dyldLibraryPathKey to getSwiftLibsPathForTestTarget()
|
||||
)
|
||||
}
|
||||
@@ -245,25 +229,14 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable {
|
||||
if (!fullBitcode) {
|
||||
return
|
||||
}
|
||||
val testTarget = project.testTarget
|
||||
val configurables = project.platformManager.platform(testTarget).configurables as AppleConfigurables
|
||||
val configurables = project.testTargetConfigurables as AppleConfigurables
|
||||
|
||||
val bitcodeBuildTool = "${configurables.absoluteAdditionalToolsDir}/bin/bitcode-build-tool"
|
||||
val toolPath = "${configurables.absoluteTargetToolchain}/usr/bin/"
|
||||
val sdk = when (testTarget) {
|
||||
KonanTarget.IOS_X64,
|
||||
KonanTarget.TVOS_X64,
|
||||
KonanTarget.WATCHOS_X86,
|
||||
KonanTarget.WATCHOS_X64 -> return // bitcode-build-tool doesn't support simulators.
|
||||
KonanTarget.IOS_ARM64,
|
||||
KonanTarget.IOS_ARM32 -> Xcode.current.iphoneosSdk
|
||||
KonanTarget.MACOS_X64,
|
||||
KonanTarget.MACOS_ARM64 -> Xcode.current.macosxSdk
|
||||
KonanTarget.TVOS_ARM64 -> Xcode.current.appletvosSdk
|
||||
KonanTarget.WATCHOS_ARM32,
|
||||
KonanTarget.WATCHOS_ARM64 -> Xcode.current.watchosSdk
|
||||
else -> error("Cannot validate bitcode for test target $testTarget")
|
||||
if (configurables.targetTriple.isSimulator) {
|
||||
return // bitcode-build-tool doesn't support simulators.
|
||||
}
|
||||
val sdk = Xcode.current.pathToPlatformSdk(configurables.platformName())
|
||||
|
||||
val python3 = listOf("/usr/bin/python3", "/usr/local/bin/python3")
|
||||
.map { Paths.get(it) }.firstOrNull { Files.exists(it) }
|
||||
|
||||
@@ -292,18 +292,7 @@ fun compileSwift(project: Project, target: KonanTarget, sources: List<String>, o
|
||||
val configs = platform.configurables as AppleConfigurables
|
||||
val compiler = configs.absoluteTargetToolchain + "/usr/bin/swiftc"
|
||||
|
||||
val swiftTarget = when (target) {
|
||||
KonanTarget.IOS_X64 -> "x86_64-apple-ios" + configs.osVersionMin
|
||||
KonanTarget.IOS_ARM32 -> "armv7-apple-ios" + configs.osVersionMin
|
||||
KonanTarget.IOS_ARM64 -> "arm64-apple-ios" + configs.osVersionMin
|
||||
KonanTarget.TVOS_X64 -> "x86_64-apple-tvos" + configs.osVersionMin
|
||||
KonanTarget.TVOS_ARM64 -> "arm64-apple-tvos" + configs.osVersionMin
|
||||
KonanTarget.MACOS_X64 -> "x86_64-apple-macosx" + configs.osVersionMin
|
||||
KonanTarget.MACOS_ARM64 -> "arm64-apple-macos" + configs.osVersionMin
|
||||
KonanTarget.WATCHOS_X86 -> "i386-apple-watchos" + configs.osVersionMin
|
||||
KonanTarget.WATCHOS_X64 -> "x86_64-apple-watchos" + configs.osVersionMin
|
||||
else -> throw IllegalStateException("Test target $target is not supported")
|
||||
}
|
||||
val swiftTarget = configs.targetTriple.withOSVersion(configs.osVersionMin).toString()
|
||||
|
||||
val args = listOf("-sdk", configs.absoluteTargetSysRoot, "-target", swiftTarget) +
|
||||
options + "-o" + output.toString() + sources +
|
||||
@@ -411,3 +400,10 @@ internal fun StringBuilder.appendln(o: Any?) {
|
||||
append(o)
|
||||
append('\n')
|
||||
}
|
||||
|
||||
internal val Project.testTargetConfigurables: Configurables
|
||||
get() {
|
||||
val platformManager = project.platformManager
|
||||
val testTarget = project.testTarget
|
||||
return platformManager.platform(testTarget).configurables
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.jetbrains.kotlin
|
||||
|
||||
import com.google.gson.annotations.Expose
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.target.Family
|
||||
import org.jetbrains.kotlin.konan.target.Xcode
|
||||
import kotlin.math.min
|
||||
|
||||
@@ -28,12 +28,12 @@ private fun Xcode.getSimulatorRuntimeDescriptors(): List<SimulatorRuntimeDescrip
|
||||
/**
|
||||
* Returns first available simulator runtime for [target] with at least [osMinVersion] OS version.
|
||||
* */
|
||||
fun Xcode.getLatestSimulatorRuntimeFor(target: KonanTarget, osMinVersion: String): SimulatorRuntimeDescriptor? {
|
||||
val osName = when (target) {
|
||||
KonanTarget.IOS_X64 -> "iOS"
|
||||
KonanTarget.WATCHOS_X64, KonanTarget.WATCHOS_X86 -> "watchOS"
|
||||
KonanTarget.TVOS_X64 -> "tvOS"
|
||||
else -> error("Unexpected simulator target: $target")
|
||||
fun Xcode.getLatestSimulatorRuntimeFor(family: Family, osMinVersion: String): SimulatorRuntimeDescriptor? {
|
||||
val osName = when (family) {
|
||||
Family.IOS -> "iOS"
|
||||
Family.WATCHOS -> "watchOS"
|
||||
Family.TVOS -> "tvOS"
|
||||
else -> error("Unexpected simulator OS: $family")
|
||||
}
|
||||
return getSimulatorRuntimeDescriptors().firstOrNull {
|
||||
it.checkAvailability() && it.name.startsWith(osName) && compareStringsAsVersions(it.version, osMinVersion) >= 0
|
||||
|
||||
@@ -32,16 +32,7 @@ class AppleConfigurablesImpl(
|
||||
private val xcodeAddonDependency = this.additionalToolsDir!!
|
||||
|
||||
override val absoluteTargetSysRoot: String get() = when (val provider = xcodePartsProvider) {
|
||||
is XcodePartsProvider.Local -> when (target) {
|
||||
KonanTarget.MACOS_X64, KonanTarget.MACOS_ARM64 -> provider.xcode.macosxSdk
|
||||
KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64 -> provider.xcode.iphoneosSdk
|
||||
KonanTarget.IOS_X64 -> provider.xcode.iphonesimulatorSdk
|
||||
KonanTarget.TVOS_ARM64 -> provider.xcode.appletvosSdk
|
||||
KonanTarget.TVOS_X64 -> provider.xcode.appletvsimulatorSdk
|
||||
KonanTarget.WATCHOS_ARM64, KonanTarget.WATCHOS_ARM32 -> provider.xcode.watchosSdk
|
||||
KonanTarget.WATCHOS_X64, KonanTarget.WATCHOS_X86 -> provider.xcode.watchsimulatorSdk
|
||||
else -> error(target)
|
||||
}
|
||||
is XcodePartsProvider.Local -> provider.xcode.pathToPlatformSdk(platformName())
|
||||
XcodePartsProvider.InternalServer -> absolute(sdkDependency)
|
||||
}
|
||||
|
||||
@@ -101,3 +92,26 @@ class AppleConfigurablesImpl(
|
||||
object InternalServer : XcodePartsProvider()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of an Apple platform as in Xcode.app/Contents/Developer/Platforms.
|
||||
*/
|
||||
fun AppleConfigurables.platformName(): String = when (target.family) {
|
||||
Family.OSX -> "MacOSX"
|
||||
Family.IOS -> if (targetTriple.isSimulator) {
|
||||
"iPhoneSimulator"
|
||||
} else {
|
||||
"iPhoneOS"
|
||||
}
|
||||
Family.TVOS -> if (targetTriple.isSimulator) {
|
||||
"AppleTVSimulator"
|
||||
} else {
|
||||
"AppleTVOS"
|
||||
}
|
||||
Family.WATCHOS -> if (targetTriple.isSimulator) {
|
||||
"WatchSimulator"
|
||||
} else {
|
||||
"WatchOS"
|
||||
}
|
||||
else -> error("Not an Apple target: $target")
|
||||
}
|
||||
|
||||
+15
-1
@@ -50,4 +50,18 @@ data class TargetTriple(
|
||||
?: ""
|
||||
return "$architecture-$vendor-$os$envSuffix"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that given target is Apple simulator.
|
||||
*/
|
||||
val TargetTriple.isSimulator: Boolean
|
||||
get() = environment == "simulator"
|
||||
|
||||
/**
|
||||
* Appends version to OS part of triple.
|
||||
*
|
||||
* Useful for precise target specification in Clang and Swift.
|
||||
*/
|
||||
fun TargetTriple.withOSVersion(osVersion: String): TargetTriple =
|
||||
copy(os = "${os}${osVersion}")
|
||||
@@ -35,6 +35,17 @@ interface Xcode {
|
||||
val additionalTools: String
|
||||
val simulatorRuntimes: String
|
||||
|
||||
fun pathToPlatformSdk(platformName: String): String = when (platformName.toLowerCase()) {
|
||||
"macosx" -> macosxSdk
|
||||
"iphoneos" -> iphoneosSdk
|
||||
"iphonesimulator" -> iphonesimulatorSdk
|
||||
"appletvos" -> appletvosSdk
|
||||
"appletvsimulator" -> appletvsimulatorSdk
|
||||
"watchos" -> watchosSdk
|
||||
"watchsimulator" -> watchsimulatorSdk
|
||||
else -> error("Unknown Apple platform: $platformName")
|
||||
}
|
||||
|
||||
companion object {
|
||||
val current: Xcode by lazy {
|
||||
CurrentXcode
|
||||
|
||||
Reference in New Issue
Block a user