From 02f0af39e34a67b65ecdc9ad47ef5625711ad6a9 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Mon, 7 Jul 2025 15:03:11 -0700 Subject: [PATCH] Change Triple.isiOS to no longer match tvOS This behavior is confusing and leads to wrong answers in a number of places. All usage sites of isiOS have been audited to ensure they're now correct. - unsupportedTargetVariant was showing an error message including -target-variant, which should have only matched iOS and not tvOS - getDefaultDwarfVersion checked isiOS in two places, but just so happened to always get the right answer anyways (tvOS's first version was 9, so checking for tvOS < 9 was nonsensical and didn't matter, and iOS and tvOS version numbers have always been aligned, so a < 18 check was right for both) --- .../Toolchains/DarwinToolchain.swift | 2 +- .../Utilities/Triple+Platforms.swift | 18 +++++-- Sources/SwiftDriver/Utilities/Triple.swift | 50 ++++++++++++++----- Tests/SwiftDriverTests/TripleTests.swift | 31 +++++++++++- 4 files changed, 82 insertions(+), 19 deletions(-) diff --git a/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift b/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift index 9cadd4511..2277bb2d0 100644 --- a/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift @@ -232,7 +232,7 @@ public final class DarwinToolchain: Toolchain { if (targetTriple.isMacOSX && targetTriple.version(for: .macOS) < Triple.Version(10, 11, 0)) || (targetTriple.isiOS && targetTriple.version( for: .iOS(targetTriple._isSimulatorEnvironment ? .simulator : .device)) < Triple.Version(9, 0, 0)) { - return 2; + return 2 } if (targetTriple.isMacOSX && targetTriple.version(for: .macOS) < Triple.Version(15, 0, 0)) || (targetTriple.isiOS && targetTriple.version( diff --git a/Sources/SwiftDriver/Utilities/Triple+Platforms.swift b/Sources/SwiftDriver/Utilities/Triple+Platforms.swift index d66c17314..65b1488e0 100644 --- a/Sources/SwiftDriver/Utilities/Triple+Platforms.swift +++ b/Sources/SwiftDriver/Utilities/Triple+Platforms.swift @@ -215,8 +215,10 @@ extension Triple { switch compatibilityPlatform ?? darwinPlatform! { case .macOS: return _macOSVersion ?? osVersion - case .iOS, .tvOS: + case .iOS: return _iOSVersion + case .tvOS: + return _tvOSVersion case .watchOS: return _watchOSVersion case .visionOS: @@ -282,14 +284,22 @@ extension Triple { } return _iOSVersion - case .iOS(.device), .iOS(.simulator), .tvOS(_): - // The first deployment of arm64 simulators is iOS/tvOS 14.0; + case .iOS(_): + // The first deployment of arm64 simulators is iOS 14.0; // the linker doesn't want to see a deployment target before that. if _isSimulatorEnvironment && _iOSVersion.major < 14 && arch == .aarch64 { return Version(14, 0, 0) } return _iOSVersion + case .tvOS(_): + // The first deployment of arm64 simulators is tvOS 14.0; + // the linker doesn't want to see a deployment target before that. + if _isSimulatorEnvironment && _tvOSVersion.major < 14 && arch == .aarch64 { + return Version(14, 0, 0) + } + + return _tvOSVersion case .watchOS(_): // The first deployment of arm64 simulators is watchOS 7; // the linker doesn't want to see a deployment target before that. @@ -297,7 +307,7 @@ extension Triple { return Version(7, 0, 0) } - return osVersion + return _watchOSVersion case .visionOS(_): return _visionOSVersion } diff --git a/Sources/SwiftDriver/Utilities/Triple.swift b/Sources/SwiftDriver/Utilities/Triple.swift index 714babc4b..d0ccfd978 100644 --- a/Sources/SwiftDriver/Utilities/Triple.swift +++ b/Sources/SwiftDriver/Utilities/Triple.swift @@ -1473,19 +1473,16 @@ extension Triple.OS { self == .aix } - /// isMacOSX - Is this a Mac OS X triple. For legacy reasons, we support both - /// "darwin" and "osx" as OS X triples. + /// Is this an Apple macOS triple. + /// - note: For legacy reasons, we support both "darwin" and "macosx" as macOS triples. public var isMacOSX: Bool { self == .darwin || self == .macosx } - /// Is this an iOS triple. - /// Note: This identifies tvOS as a variant of iOS. If that ever - /// changes, i.e., if the two operating systems diverge or their version - /// numbers get out of sync, that will need to be changed. - /// watchOS has completely different version numbers so it is not included. + /// Is this an Apple iOS triple. + /// - note: Contrary to historical behavior with regard to LLVM's Triple type, this does NOT match tvOS in order to avoid confusion moving forward. public var isiOS: Bool { - self == .ios || isTvOS + self == .ios } /// Is this an Apple tvOS triple. @@ -1498,14 +1495,15 @@ extension Triple.OS { self == .watchos } + /// Is this an Apple visionOS triple. public var isVisionOS: Bool { self == .visionos } - /// isOSDarwin - Is this a "Darwin" OS (OS X, iOS, or watchOS). + /// isOSDarwin - Is this a "Darwin" OS (macOS, iOS, tvOS, watchOS, or visionOS). public var isDarwin: Bool { - isMacOSX || isiOS || isWatchOS || isVisionOS + isMacOSX || isiOS || isTvOS || isWatchOS || isVisionOS } } @@ -1640,13 +1638,15 @@ extension Triple { // toolchain that wants to know the iOS version number even when targeting // OS X. return Version(5, 0, 0) - case .ios, .tvos: + case .ios: var version = self.osVersion // Default to 5.0 (or 7.0 for arm64). if version.major == 0 { version.major = arch == .aarch64 ? 7 : 5 } return version + case .tvos: + return osVersion case .visionos: return Version(15, 0, 0) case .watchos: @@ -1656,6 +1656,32 @@ extension Triple { } } + /// Parse the version number as with getOSVersion. This should + /// only be called with tvOS or generic triples. + /// + /// This accessor is semi-private; it's typically better to use `version(for:)` or + /// `Triple.FeatureAvailability`. + public var _tvOSVersion: Version { + switch os { + case .darwin, .macosx: + // Ignore the version from the triple. This is only handled because the + // the clang driver combines OS X and iOS support into a common Darwin + // toolchain that wants to know the iOS version number even when targeting + // OS X. + return Version(9, 0, 0) + case .ios, .tvos: + var version = self.osVersion + if version.major == 0 { + version.major = 9 + } + return version + case .watchos: + fatalError("conflicting triple info") + default: + fatalError("unexpected OS for Darwin triple") + } + } + /// Parse the version number as with getOSVersion. This should only be /// called with WatchOS or generic triples. /// @@ -1705,7 +1731,7 @@ extension Triple { extension Triple { @_spi(Testing) public var isMacCatalyst: Bool { - return self.isiOS && !self.isTvOS && environment == .macabi + return self.isiOS && environment == .macabi } func isValidForZipperingWithTriple(_ variant: Triple) -> Bool { diff --git a/Tests/SwiftDriverTests/TripleTests.swift b/Tests/SwiftDriverTests/TripleTests.swift index d5d0f2a3c..96cb661ad 100644 --- a/Tests/SwiftDriverTests/TripleTests.swift +++ b/Tests/SwiftDriverTests/TripleTests.swift @@ -1054,12 +1054,23 @@ final class TripleTests: XCTestCase { T = Triple("x86_64-apple-ios12.0") XCTAssertTrue(T.os?.isiOS) + XCTAssertFalse(T.os?.isTvOS) V = T._iOSVersion XCTAssertEqual(V?.major, 12) XCTAssertEqual(V?.minor, 0) XCTAssertEqual(V?.micro, 0) XCTAssertFalse(T._isSimulatorEnvironment) XCTAssertFalse(T.isMacCatalyst) + + T = Triple("x86_64-apple-tvos12.0") + XCTAssertTrue(T.os?.isTvOS) + XCTAssertFalse(T.os?.isiOS) + V = T._tvOSVersion + XCTAssertEqual(V?.major, 12) + XCTAssertEqual(V?.minor, 0) + XCTAssertEqual(V?.micro, 0) + XCTAssertFalse(T._isSimulatorEnvironment) + XCTAssertFalse(T.isMacCatalyst) } func testFileFormat() { @@ -1143,6 +1154,7 @@ final class TripleTests: XCTestCase { environment: T, macOSVersion: Triple.Version?, iOSVersion: Triple.Version?, + tvOSVersion: Triple.Version?, watchOSVersion: Triple.Version?, shouldHaveJetPacks: Bool, file: StaticString = #file, line: UInt = #line @@ -1170,9 +1182,11 @@ final class TripleTests: XCTestCase { "iOS device version", file: file, line: line) XCTAssertEqual(triple.version(for: .iOS(.simulator)), iOSVersion, "iOS simulator version", file: file, line: line) - XCTAssertEqual(triple.version(for: .tvOS(.device)), iOSVersion, + } + if let tvOSVersion = tvOSVersion { + XCTAssertEqual(triple.version(for: .tvOS(.device)), tvOSVersion, "tvOS device version", file: file, line: line) - XCTAssertEqual(triple.version(for: .tvOS(.simulator)), iOSVersion, + XCTAssertEqual(triple.version(for: .tvOS(.simulator)), tvOSVersion, "tvOS simulator version", file: file, line: line) } if let watchOSVersion = watchOSVersion { @@ -1214,6 +1228,7 @@ final class TripleTests: XCTestCase { environment: .device, macOSVersion: .init(10, 12, 0), iOSVersion: .init(5, 0, 0), + tvOSVersion: .init(9, 0, 0), watchOSVersion: .init(2, 0, 0), shouldHaveJetPacks: false) assertDarwinPlatformCorrect(macOS2, @@ -1221,6 +1236,7 @@ final class TripleTests: XCTestCase { environment: .device, macOSVersion: .init(10, 50, 0), iOSVersion: .init(5, 0, 0), + tvOSVersion: .init(9, 0, 0), watchOSVersion: .init(2, 0, 0), shouldHaveJetPacks: true) assertDarwinPlatformCorrect(macOS3, @@ -1228,6 +1244,7 @@ final class TripleTests: XCTestCase { environment: .device, macOSVersion: .init(10, 60, 9), iOSVersion: .init(5, 0, 0), + tvOSVersion: .init(9, 0, 0), watchOSVersion: .init(2, 0, 0), shouldHaveJetPacks: true) assertDarwinPlatformCorrect(macOS4, @@ -1235,6 +1252,7 @@ final class TripleTests: XCTestCase { environment: .device, macOSVersion: .init(10, 15, 0), iOSVersion: .init(5, 0, 0), + tvOSVersion: .init(9, 0, 0), watchOSVersion: .init(2, 0, 0), shouldHaveJetPacks: false) @@ -1247,6 +1265,7 @@ final class TripleTests: XCTestCase { environment: .simulator, macOSVersion: .init(10, 4, 0), iOSVersion: .init(13, 0, 0), + tvOSVersion: nil, watchOSVersion: nil, shouldHaveJetPacks: false) assertDarwinPlatformCorrect(iOS2, @@ -1254,6 +1273,7 @@ final class TripleTests: XCTestCase { environment: .device, macOSVersion: .init(10, 4, 0), iOSVersion: .init(50, 0, 0), + tvOSVersion: nil, watchOSVersion: nil, shouldHaveJetPacks: true) assertDarwinPlatformCorrect(iOS3, @@ -1261,6 +1281,7 @@ final class TripleTests: XCTestCase { environment: .catalyst, macOSVersion: .init(10, 4, 0), iOSVersion: .init(60, 0, 0), + tvOSVersion: nil, watchOSVersion: nil, shouldHaveJetPacks: true) @@ -1273,6 +1294,7 @@ final class TripleTests: XCTestCase { environment: .simulator, macOSVersion: .init(10, 4, 0), iOSVersion: .init(13, 0, 0), + tvOSVersion: .init(13, 0, 0), watchOSVersion: nil, shouldHaveJetPacks: false) assertDarwinPlatformCorrect(tvOS2, @@ -1280,6 +1302,7 @@ final class TripleTests: XCTestCase { environment: .device, macOSVersion: .init(10, 4, 0), iOSVersion: .init(50, 0, 0), + tvOSVersion: .init(50, 0, 0), watchOSVersion: nil, shouldHaveJetPacks: true) assertDarwinPlatformCorrect(tvOS3, @@ -1287,6 +1310,7 @@ final class TripleTests: XCTestCase { environment: .simulator, macOSVersion: .init(10, 4, 0), iOSVersion: .init(60, 0, 0), + tvOSVersion: .init(60, 0, 0), watchOSVersion: nil, shouldHaveJetPacks: true) @@ -1299,6 +1323,7 @@ final class TripleTests: XCTestCase { environment: .simulator, macOSVersion: .init(10, 4, 0), iOSVersion: nil, + tvOSVersion: nil, watchOSVersion: .init(6, 0, 0), shouldHaveJetPacks: false) assertDarwinPlatformCorrect(watchOS2, @@ -1306,6 +1331,7 @@ final class TripleTests: XCTestCase { environment: .device, macOSVersion: .init(10, 4, 0), iOSVersion: nil, + tvOSVersion: nil, watchOSVersion: .init(50, 0, 0), shouldHaveJetPacks: true) assertDarwinPlatformCorrect(watchOS3, @@ -1313,6 +1339,7 @@ final class TripleTests: XCTestCase { environment: .simulator, macOSVersion: .init(10, 4, 0), iOSVersion: nil, + tvOSVersion: nil, watchOSVersion: .init(60, 0, 0), shouldHaveJetPacks: true) }