Skip to content

Attempt to diagnose arguments to -sdk that point to unsupported SDKs #606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion Sources/SwiftDriver/Driver/Driver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2005,8 +2005,11 @@ extension Driver {

if !fileSystem.exists(path) {
diagnosticsEngine.emit(.warning_no_such_sdk(sdkPath))
} else if isSDKTooOld(sdkPath: path, fileSystem: fileSystem,
diagnosticsEngine: diagnosticsEngine) {
diagnosticsEngine.emit(.error_sdk_too_old(sdkPath))
return nil
}
// .. else check if SDK is too old (we need target triple to diagnose that).

return .absolute(path)
}
Expand All @@ -2015,6 +2018,32 @@ extension Driver {
}
}

// SDK checking: attempt to diagnose if the SDK we are pointed at is too old.
extension Driver {
static func isSDKTooOld(sdkPath: AbsolutePath, fileSystem: FileSystem,
diagnosticsEngine: DiagnosticsEngine) -> Bool {
let sdkInfo = DarwinToolchain.readSDKInfo(fileSystem, VirtualPath.absolute(sdkPath).intern())
guard let sdkInfo = sdkInfo else {
diagnosticsEngine.emit(.warning_no_sdksettings_json(sdkPath.pathString))
return false
}
guard let sdkVersion = Version(potentiallyIncompleteVersionString: sdkInfo.versionString) else {
diagnosticsEngine.emit(.warning_fail_parse_sdk_ver(sdkInfo.versionString, sdkPath.pathString))
return false
}
if sdkInfo.canonicalName.hasPrefix("macos") {
return sdkVersion < Version(10, 15, 0)
} else if sdkInfo.canonicalName.hasPrefix("iphoneos") ||
sdkInfo.canonicalName.hasPrefix("appletvos") {
return sdkVersion < Version(13, 0, 0)
} else if sdkInfo.canonicalName.hasPrefix("watchos") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about missing this. Do we need to handle simulator SDKs here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, that's a good catch.
I thought this would work as is because it is a prefix, but it turns out that it won't. The os part of the prefix is not present for the simulator platforms so we need to pattern match prefixes: appletv, watch, iphone, without the os to also catch this for the simulator. I'll create another PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Using a more concise prefix will just work.

return sdkVersion < Version(6, 0, 0)
} else {
return false
}
}
}

// Imported Objective-C header.
extension Driver {
/// Compute the path of the imported Objective-C header.
Expand Down
7 changes: 5 additions & 2 deletions Sources/SwiftDriver/Jobs/PrebuiltModulesJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,11 @@ public struct SDKPrebuiltModuleInputsCollector {
let canonicalName = sdkInfo.canonicalName
func extractVersion(_ platform: String) -> Substring? {
if canonicalName.starts(with: platform) {
return canonicalName.suffix(from: canonicalName.index(canonicalName.startIndex,
offsetBy: platform.count))
let versionStartIndex = canonicalName.index(canonicalName.startIndex,
offsetBy: platform.count)
let delimiterRange = canonicalName.range(of: "internal", options: .backwards)
let versionEndIndex = delimiterRange == nil ? canonicalName.endIndex : delimiterRange!.lowerBound
return canonicalName[versionStartIndex..<versionEndIndex]
}
return nil
}
Expand Down
12 changes: 12 additions & 0 deletions Sources/SwiftDriver/Utilities/Diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@ extension Diagnostic.Message {
.warning("no such SDK: \(path)")
}

static func warning_no_sdksettings_json(_ path: String) -> Diagnostic.Message {
.warning("Could not read SDKSettings.json for SDK at: \(path)")
}

static func warning_fail_parse_sdk_ver(_ version: String, _ path: String) -> Diagnostic.Message {
.warning("Could not parse SDK version '\(version)' at: \(path)")
}

static func error_sdk_too_old(_ path: String) -> Diagnostic.Message {
.error("Swift does not support the SDK \(path)")
}

static func error_unknown_target(_ target: String) -> Diagnostic.Message {
.error("unknown target '\(target)'")
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftDriver/Utilities/Triple+Platforms.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ extension Triple {
{
switch compatibilityPlatform ?? darwinPlatform! {
case .macOS:
return _macOSVersion!
return _macOSVersion ?? osVersion
case .iOS, .tvOS:
return _iOSVersion
case .watchOS:
Expand Down
8 changes: 8 additions & 0 deletions TestInputs/SDKChecks/MacOSX10.10.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Version": "10.10",
"VersionMap": {
"macOS_iOSMac": {},
"iOSMac_macOS": {}
},
"CanonicalName": "macosx10.10"
}
8 changes: 8 additions & 0 deletions TestInputs/SDKChecks/MacOSX10.11.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Version": "10.11",
"VersionMap": {
"macOS_iOSMac": {},
"iOSMac_macOS": {}
},
"CanonicalName": "macosx10.11"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Version": "10.14",
"VersionMap": {
"macOS_iOSMac": {},
"iOSMac_macOS": {}
},
"CanonicalName": "macosx10.14internal"
}
8 changes: 8 additions & 0 deletions TestInputs/SDKChecks/MacOSX10.15.4.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Version": "10.15.4",
"VersionMap": {
"macOS_iOSMac": {},
"iOSMac_macOS": {}
},
"CanonicalName": "macosx10.15.4"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Version": "10.15",
"VersionMap": {
"macOS_iOSMac": {},
"iOSMac_macOS": {}
},
"CanonicalName": "macosx10.15internal"
}
8 changes: 8 additions & 0 deletions TestInputs/SDKChecks/MacOSX10.15.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Version": "10.15",
"VersionMap": {
"macOS_iOSMac": {},
"iOSMac_macOS": {}
},
"CanonicalName": "macosx10.15"
}
8 changes: 8 additions & 0 deletions TestInputs/SDKChecks/MacOSX10.8.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Version": "10.8",
"VersionMap": {
"macOS_iOSMac": {},
"iOSMac_macOS": {}
},
"CanonicalName": "macosx10.8"
}
8 changes: 8 additions & 0 deletions TestInputs/SDKChecks/MacOSX10.9.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Version": "10.9",
"VersionMap": {
"macOS_iOSMac": {},
"iOSMac_macOS": {}
},
"CanonicalName": "macosx10.9"
}
8 changes: 8 additions & 0 deletions TestInputs/SDKChecks/MacOSX7.17.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Version": "7.17",
"VersionMap": {
"macOS_iOSMac": {},
"iOSMac_macOS": {}
},
"CanonicalName": "macosx7.17"
}
4 changes: 4 additions & 0 deletions TestInputs/SDKChecks/iPhoneOS.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Version": "13.00",
"CanonicalName": "iphoneos13.0"
}
4 changes: 4 additions & 0 deletions TestInputs/SDKChecks/iPhoneOS12.99.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Version": "12.99",
"CanonicalName": "iphoneos12.99"
}
4 changes: 4 additions & 0 deletions TestInputs/SDKChecks/iPhoneOS13.0.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Version": "13.0",
"CanonicalName": "iphoneos13.0"
}
4 changes: 4 additions & 0 deletions TestInputs/SDKChecks/iPhoneOS7.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Version": "7.0",
"CanonicalName": "iphoneos7.0"
}
4 changes: 4 additions & 0 deletions TestInputs/SDKChecks/tvOS.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Version": "13.0",
"CanonicalName": "appletvos13.0"
}
4 changes: 4 additions & 0 deletions TestInputs/SDKChecks/tvOS13.0.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Version": "13.0",
"CanonicalName": "appletvos13.0"
}
4 changes: 4 additions & 0 deletions TestInputs/SDKChecks/tvOS8.0.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Version": "8.0",
"CanonicalName": "appletvos8.0"
}
4 changes: 4 additions & 0 deletions TestInputs/SDKChecks/watchOS.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Version": "7.0",
"CanonicalName": "watchos7.0"
}
4 changes: 4 additions & 0 deletions TestInputs/SDKChecks/watchOS2.0.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Version": "2.0",
"CanonicalName": "watchos2.0"
}
4 changes: 4 additions & 0 deletions TestInputs/SDKChecks/watchOS3.0.Internal.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Version": "3.0",
"CanonicalName": "watchos3.0internal"
}
4 changes: 4 additions & 0 deletions TestInputs/SDKChecks/watchOS3.0.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Version": "3.0",
"CanonicalName": "watchos3.0"
}
4 changes: 4 additions & 0 deletions TestInputs/SDKChecks/watchOS6.0.sdk/SDKSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Version": "6.0",
"CanonicalName": "watchos6.0"
}
58 changes: 56 additions & 2 deletions Tests/SwiftDriverTests/SwiftDriverTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2581,7 +2581,7 @@ final class SwiftDriverTests: XCTestCase {
// Test cases ported from Driver/macabi-environment.swift
func testDarwinSDKVersioning() throws {
try withTemporaryDirectory { tmpDir in
let sdk1 = tmpDir.appending(component: "MacOSX10.15.versioned.sdk")
let sdk1 = tmpDir.appending(component: "MacOSX10.15.sdk")
try localFileSystem.writeFileContents(sdk1.appending(component: "SDKSettings.json")) {
$0 <<< """
{
Expand All @@ -2601,7 +2601,7 @@ final class SwiftDriverTests: XCTestCase {
"""
}

let sdk2 = tmpDir.appending(component: "MacOSX10.15.4.versioned.sdk")
let sdk2 = tmpDir.appending(component: "MacOSX10.15.4.sdk")
try localFileSystem.writeFileContents(sdk2.appending(component: "SDKSettings.json")) {
$0 <<< """
{
Expand Down Expand Up @@ -2738,6 +2738,60 @@ final class SwiftDriverTests: XCTestCase {
}
}

func testDarwinSDKTooOld() throws {
func getSDKPath(sdkDirName: String) -> AbsolutePath {
let packageRootPath = AbsolutePath(String(URL(fileURLWithPath: #file).pathComponents
.prefix(while: { $0 != "Tests" }).joined(separator: "/").dropFirst()))
let testInputsPath = packageRootPath.appending(component: "TestInputs")
.appending(component: "SDKChecks")
return testInputsPath.appending(component: sdkDirName)
}
// Ensure an error is emitted for an unsupported SDK
func checkSDKUnsupported(sdkDirName: String)
throws {
let sdkPath = getSDKPath(sdkDirName: sdkDirName)
// Get around the check for SDK's existence
try localFileSystem.createDirectory(sdkPath)
let args = [ "swiftc", "foo.swift", "-sdk", sdkPath.pathString ]
try assertDriverDiagnostics(args: args) { driver, verifier in
verifier.expect(.error("Swift does not support the SDK \(sdkPath.pathString)"))
}
}

// Ensure no error is emitted for a supported SDK
func checkSDKOkay(sdkDirName: String) throws {
let sdkPath = getSDKPath(sdkDirName: sdkDirName)
try localFileSystem.createDirectory(sdkPath)
let args = [ "swiftc", "foo.swift", "-sdk", sdkPath.pathString ]
try assertNoDiagnostics { de in let _ = try Driver(args: args, diagnosticsEngine: de) }
}

// Ensure old/bogus SDK versions are caught
try checkSDKUnsupported(sdkDirName: "tvOS8.0.sdk")
try checkSDKUnsupported(sdkDirName: "MacOSX10.8.sdk")
try checkSDKUnsupported(sdkDirName: "MacOSX10.9.sdk")
try checkSDKUnsupported(sdkDirName: "MacOSX10.10.sdk")
try checkSDKUnsupported(sdkDirName: "MacOSX10.11.sdk")
try checkSDKUnsupported(sdkDirName: "MacOSX7.17.sdk")
try checkSDKUnsupported(sdkDirName: "MacOSX10.14.Internal.sdk")
try checkSDKUnsupported(sdkDirName: "iPhoneOS7.sdk")
try checkSDKUnsupported(sdkDirName: "iPhoneOS12.99.sdk")
try checkSDKUnsupported(sdkDirName: "watchOS2.0.sdk")
try checkSDKUnsupported(sdkDirName: "watchOS3.0.sdk")
try checkSDKUnsupported(sdkDirName: "watchOS3.0.Internal.sdk")

// Verify a selection of okay SDKs
try checkSDKOkay(sdkDirName: "MacOSX10.15.sdk")
try checkSDKOkay(sdkDirName: "MacOSX10.15.4.sdk")
try checkSDKOkay(sdkDirName: "MacOSX10.15.Internal.sdk")
try checkSDKOkay(sdkDirName: "iPhoneOS13.0.sdk")
try checkSDKOkay(sdkDirName: "tvOS13.0.sdk")
try checkSDKOkay(sdkDirName: "watchOS6.0.sdk")
try checkSDKOkay(sdkDirName: "iPhoneOS.sdk")
try checkSDKOkay(sdkDirName: "tvOS.sdk")
try checkSDKOkay(sdkDirName: "watchOS.sdk")
}

func testDarwinLinkerPlatformVersion() throws {
do {
var driver = try Driver(args: ["swiftc",
Expand Down