Skip to content

Commit d0a312b

Browse files
authored
Merge pull request #177 from owenv/deployment
Validate Darwin deployment targets and target variants
2 parents c4d4f61 + 3c65eb7 commit d0a312b

File tree

4 files changed

+107
-1
lines changed

4 files changed

+107
-1
lines changed

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ public struct Driver {
309309

310310
try Self.validateWarningControlArgs(&parsedOptions)
311311
Self.validateCoverageArgs(&parsedOptions, diagnosticsEngine: diagnosticEngine)
312+
try toolchain.validateArgs(&parsedOptions,
313+
targetTriple: self.frontendTargetInfo.target.triple,
314+
targetVariantTriple: self.frontendTargetInfo.targetVariant?.triple)
312315

313316
// Compute debug information output.
314317
self.debugInfo = Self.computeDebugInfo(&parsedOptions, diagnosticsEngine: diagnosticEngine)

Sources/SwiftDriver/Toolchains/DarwinToolchain.swift

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212
import TSCBasic
13+
import SwiftOptions
1314

1415
/// Toolchain for Darwin-based platforms, such as macOS and iOS.
1516
///
@@ -119,4 +120,62 @@ public final class DarwinToolchain: Toolchain {
119120
\(isShared ? "_dynamic.dylib" : ".a")
120121
"""
121122
}
123+
124+
public enum ToolchainValidationError: Error, DiagnosticData {
125+
case osVersionBelowMinimumDeploymentTarget(String)
126+
case iOSVersionAboveMaximumDeploymentTarget(Int)
127+
case unsupportedTargetVariant(variant: Triple)
128+
129+
public var description: String {
130+
switch self {
131+
case .osVersionBelowMinimumDeploymentTarget(let target):
132+
return "Swift requires a minimum deployment target of \(target)"
133+
case .iOSVersionAboveMaximumDeploymentTarget(let version):
134+
return "iOS \(version) does not support 32-bit programs"
135+
case .unsupportedTargetVariant(variant: let variant):
136+
return "unsupported '\(variant.isiOS ? "-target" : "-target-variant")' value '\(variant)'; use 'ios-macabi' instead"
137+
}
138+
}
139+
}
140+
141+
public func validateArgs(_ parsedOptions: inout ParsedOptions,
142+
targetTriple: Triple,
143+
targetVariantTriple: Triple?) throws {
144+
// TODO: Validating arclite library path when link-objc-runtime.
145+
146+
// Validating apple platforms deployment targets.
147+
try validateDeploymentTarget(&parsedOptions, targetTriple: targetTriple)
148+
if let targetVariantTriple = targetVariantTriple,
149+
!targetTriple.isValidForZipperingWithTriple(targetVariantTriple) {
150+
throw ToolchainValidationError.unsupportedTargetVariant(variant: targetVariantTriple)
151+
}
152+
153+
// TODO: Validating darwin unsupported -static-stdlib argument.
154+
// TODO: If a C++ standard library is specified, it has to be libc++.
155+
}
156+
157+
func validateDeploymentTarget(_ parsedOptions: inout ParsedOptions,
158+
targetTriple: Triple) throws {
159+
// Check minimum supported OS versions.
160+
if targetTriple.isMacOSX,
161+
targetTriple.version(for: .macOS) < Triple.Version(10, 9, 0) {
162+
throw ToolchainValidationError.osVersionBelowMinimumDeploymentTarget("OS X 10.9")
163+
}
164+
// tvOS triples are also iOS, so check it first.
165+
else if targetTriple.isTvOS,
166+
targetTriple.version(for: .tvOS(.device)) < Triple.Version(9, 0, 0) {
167+
throw ToolchainValidationError.osVersionBelowMinimumDeploymentTarget("tvOS 9.0")
168+
} else if targetTriple.isiOS {
169+
if targetTriple.version(for: .iOS(.device)) < Triple.Version(7, 0, 0) {
170+
throw ToolchainValidationError.osVersionBelowMinimumDeploymentTarget("iOS 7")
171+
}
172+
if targetTriple.arch?.is32Bit == true,
173+
targetTriple.version(for: .iOS(.device)) >= Triple.Version(11, 0, 0) {
174+
throw ToolchainValidationError.iOSVersionAboveMaximumDeploymentTarget(targetTriple.version(for: .iOS(.device)).major)
175+
}
176+
} else if targetTriple.isWatchOS,
177+
targetTriple.version(for: .watchOS(.device)) < Triple.Version(2, 0, 0) {
178+
throw ToolchainValidationError.osVersionBelowMinimumDeploymentTarget("watchOS 2.0")
179+
}
180+
}
122181
}

Sources/SwiftDriver/Toolchains/Toolchain.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ public protocol Toolchain {
5353
/// Constructs a proper output file name for a linker product.
5454
func makeLinkerOutputFilename(moduleName: String, type: LinkOutputType) -> String
5555

56+
/// Perform platform-specific argument validation.
57+
func validateArgs(_ parsedOptions: inout ParsedOptions,
58+
targetTriple: Triple,
59+
targetVariantTriple: Triple?) throws
60+
5661
/// Adds platform-specific linker flags to the provided command line
5762
func addPlatformSpecificLinkerArgs(
5863
to commandLine: inout [Job.ArgTemplate],
@@ -147,6 +152,10 @@ extension Toolchain {
147152
).spm_chomp()
148153
return AbsolutePath(path)
149154
}
155+
156+
public func validateArgs(_ parsedOptions: inout ParsedOptions,
157+
targetTriple: Triple,
158+
targetVariantTriple: Triple?) {}
150159
}
151160

152161
public enum ToolchainError: Swift.Error {

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,7 @@ final class SwiftDriverTests: XCTestCase {
10091009
#if os(macOS)
10101010
let commonArgs = [
10111011
"swiftc", "foo.swift", "bar.swift",
1012-
"-emit-executable", "-target", "x86_64-apple-macosx",
1012+
"-emit-executable", "-target", "x86_64-apple-macosx10.9",
10131013
"-module-name", "Test"
10141014
]
10151015
do {
@@ -1507,6 +1507,41 @@ final class SwiftDriverTests: XCTestCase {
15071507
}
15081508
}
15091509

1510+
func testDarwinToolchainArgumentValidation() throws {
1511+
XCTAssertThrowsError(try Driver(args: ["swiftc", "-c", "-target", "x86_64-apple-ios6.0",
1512+
"foo.swift"])) { error in
1513+
guard case DarwinToolchain.ToolchainValidationError.osVersionBelowMinimumDeploymentTarget("iOS 7") = error else {
1514+
XCTFail()
1515+
return
1516+
}
1517+
}
1518+
1519+
XCTAssertThrowsError(try Driver(args: ["swiftc", "-c", "-target", "x86_64-apple-macosx10.4",
1520+
"foo.swift"])) { error in
1521+
guard case DarwinToolchain.ToolchainValidationError.osVersionBelowMinimumDeploymentTarget("OS X 10.9") = error else {
1522+
XCTFail()
1523+
return
1524+
}
1525+
}
1526+
1527+
XCTAssertThrowsError(try Driver(args: ["swiftc", "-c", "-target", "armv7-apple-ios12.0",
1528+
"foo.swift"])) { error in
1529+
guard case DarwinToolchain.ToolchainValidationError.iOSVersionAboveMaximumDeploymentTarget(12) = error else {
1530+
XCTFail()
1531+
return
1532+
}
1533+
}
1534+
1535+
XCTAssertThrowsError(try Driver(args: ["swiftc", "-c", "-target", "x86_64-apple-ios13.0",
1536+
"-target-variant", "x86_64-apple-macosx10.14",
1537+
"foo.swift"])) { error in
1538+
guard case DarwinToolchain.ToolchainValidationError.unsupportedTargetVariant(variant: _) = error else {
1539+
XCTFail()
1540+
return
1541+
}
1542+
}
1543+
}
1544+
15101545
func testDSYMGeneration() throws {
15111546
let commonArgs = [
15121547
"swiftc", "foo.swift", "bar.swift",

0 commit comments

Comments
 (0)