Skip to content

Commit 8093c96

Browse files
committed
Fail compilation with an error diagnostic when specified 'SWIFT_DRIVER_<tool>_EXEC' argument does not exist
Resolves rdar://128636621
1 parent dd5bbca commit 8093c96

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

Sources/SwiftDriver/Toolchains/Toolchain.swift

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import class Foundation.Bundle
1515

1616
import func TSCBasic.getEnvSearchPaths
1717
import func TSCBasic.lookupExecutablePath
18+
import protocol TSCBasic.DiagnosticData
1819
import class TSCBasic.DiagnosticsEngine
1920
import protocol TSCBasic.FileSystem
2021
import struct TSCBasic.AbsolutePath
@@ -215,29 +216,41 @@ extension Toolchain {
215216
/// looks in the `executableDir`, `xcrunFind` or in the `searchPaths`.
216217
/// - Parameter executable: executable to look for [i.e. `swift`]. Executable suffix (eg. `.exe`) should be omitted.
217218
func lookup(executable: String) throws -> AbsolutePath {
219+
// 1. Check the `SWIFT_DRIVER_<TOOLNAME>_EXEC` override.
218220
if let overrideString = envVar(forExecutable: executable),
219221
let path = try? AbsolutePath(validating: overrideString) {
222+
if !fallbackToExecutableDefaultPath && !fileSystem.isExecutableFile(path) {
223+
throw ToolchainError.notAValidExecutablePath(path.pathString)
224+
}
220225
return path
226+
// 2. If `-tools-directory` is set, check there.
221227
} else if let toolDir = toolDirectory,
222228
let path = lookupExecutablePath(filename: executableName(executable), currentWorkingDirectory: nil, searchPaths: [toolDir]) {
223-
// Looking for tools from the tools directory.
224229
return path
230+
// 3. Perform lookup relative to the driver's executable
225231
} else if let path = lookupExecutablePath(filename: executableName(executable), currentWorkingDirectory: nil, searchPaths: [try executableDir]) {
226232
return path
233+
// 4. Attempt lookup with `xcrun --find`.
227234
} else if let path = try? xcrunFind(executable: executableName(executable)) {
228235
return path
236+
// 5. If querying not the compiler frontend itself and the above attempts failed,
237+
// attempt to resolve adjacent to the compiler frontend.
229238
} else if !["swift-frontend", "swift"].contains(executable),
230239
let parentDirectory = try? getToolPath(.swiftCompiler).parentDirectory,
231240
try parentDirectory != executableDir,
232241
let path = lookupExecutablePath(filename: executableName(executable), searchPaths: [parentDirectory]) {
233242
// If the driver library's client and the frontend are in different directories,
234243
// try looking for tools next to the frontend.
235244
return path
245+
// 6. Perform lookup in the toolchain search paths (e.g. $PATH)
236246
} else if let path = lookupExecutablePath(filename: executableName(executable), searchPaths: searchPaths) {
237247
return path
248+
// 7. Attempt lookup of `swift` for the compiler frontned
249+
// FIXME: we should remove this now
238250
} else if executable == "swift-frontend" {
239251
// Temporary shim: fall back to looking for "swift" before failing.
240252
return try lookup(executable: "swift")
253+
// 8. For testing purposes, attempt lookup in the system "default" paths
241254
} else if fallbackToExecutableDefaultPath {
242255
if self is WindowsToolchain {
243256
return try getToolPath(.swiftCompiler)
@@ -247,7 +260,7 @@ extension Toolchain {
247260
return try AbsolutePath(validating: "/usr/bin/" + executable)
248261
}
249262
} else {
250-
throw ToolchainError.unableToFind(tool: executable)
263+
throw ToolchainError.unableToFind(executable)
251264
}
252265
}
253266

@@ -302,7 +315,7 @@ extension Toolchain {
302315
private func xcrunFind(executable: String) throws -> AbsolutePath {
303316
let xcrun = "xcrun"
304317
guard lookupExecutablePath(filename: xcrun, searchPaths: searchPaths) != nil else {
305-
throw ToolchainError.unableToFind(tool: xcrun)
318+
throw ToolchainError.unableToFind(xcrun)
306319
}
307320

308321
let path = try executor.checkNonZeroExit(
@@ -368,6 +381,17 @@ extension Toolchain {
368381
}
369382
}
370383

371-
@_spi(Testing) public enum ToolchainError: Swift.Error {
372-
case unableToFind(tool: String)
384+
@_spi(Testing) public enum ToolchainError: Swift.Error, Equatable, DiagnosticData {
385+
case unableToFind(String)
386+
case notAValidExecutablePath(String)
387+
388+
public var description: String {
389+
switch self {
390+
case .unableToFind(let tool):
391+
return "unable to locate tool: '\(tool)'"
392+
case .notAValidExecutablePath(let path):
393+
return "not a valid executable: \(path)"
394+
395+
}
396+
}
373397
}

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ final class SwiftDriverTests: XCTestCase {
7979
// so there is no swift-help in the toolchain yet. Set the environment variable
8080
// as if we had found it for the purposes of testing build planning.
8181
var env = ProcessEnv.vars
82+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
8283
env["SWIFT_DRIVER_SWIFT_HELP_EXEC"] = "/tmp/.test-swift-help"
8384
return env
8485
}
@@ -2387,6 +2388,7 @@ final class SwiftDriverTests: XCTestCase {
23872388

23882389
func testWebAssemblyUnsupportedFeatures() throws {
23892390
var env = ProcessEnv.vars
2391+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
23902392
env["SWIFT_DRIVER_SWIFT_AUTOLINK_EXTRACT_EXEC"] = "/garbage/swift-autolink-extract"
23912393
do {
23922394
var driver = try Driver(args: ["swift", "-target", "wasm32-unknown-wasi", "foo.swift"], env: env)
@@ -3140,7 +3142,7 @@ final class SwiftDriverTests: XCTestCase {
31403142
"-emit-library", "-driver-filelist-threshold=0"
31413143
])
31423144

3143-
var jobs = try driver.planBuild()
3145+
let jobs = try driver.planBuild()
31443146
XCTAssertEqual(jobs.count, 4)
31453147
XCTAssertEqual(getFileListElements(for: "-filelist", job: jobs[2]),
31463148
[.temporary(try .init(validating: "hello-1.o"))])
@@ -4433,6 +4435,7 @@ final class SwiftDriverTests: XCTestCase {
44334435
// Drop SWIFT_DRIVER_CLANG_EXEC from the environment so it doesn't
44344436
// interfere with tool lookup.
44354437
var env = ProcessEnv.vars
4438+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
44364439
env.removeValue(forKey: "SWIFT_DRIVER_CLANG_EXEC")
44374440

44384441
var driver = try Driver(args: ["swiftc",
@@ -4837,6 +4840,7 @@ final class SwiftDriverTests: XCTestCase {
48374840
// As per Unix conventions, /var/empty is expected to exist and be empty.
48384841
// This gives us a non-existent path that we can use for libtool which
48394842
// allows us to run this this on non-Darwin platforms.
4843+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
48404844
env["SWIFT_DRIVER_LIBTOOL_EXEC"] = "/var/empty/libtool"
48414845

48424846
// No dSYM generation (-g -emit-library -static)
@@ -6696,6 +6700,7 @@ final class SwiftDriverTests: XCTestCase {
66966700

66976701
func testEmbeddedSwiftOptions() throws {
66986702
var env = ProcessEnv.vars
6703+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
66996704
env["SWIFT_DRIVER_SWIFT_AUTOLINK_EXTRACT_EXEC"] = "/garbage/swift-autolink-extract"
67006705

67016706
do {
@@ -6813,6 +6818,7 @@ final class SwiftDriverTests: XCTestCase {
68136818
// better override.
68146819
var env = ProcessEnv.vars
68156820
let swiftHelp: AbsolutePath = try AbsolutePath(validating: "/usr/bin/nonexistent-swift-help")
6821+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
68166822
env["SWIFT_DRIVER_SWIFT_HELP_EXEC"] = swiftHelp.pathString
68176823
env["SWIFT_DRIVER_CLANG_EXEC"] = "/usr/bin/clang"
68186824
var driver = try Driver(
@@ -6826,6 +6832,7 @@ final class SwiftDriverTests: XCTestCase {
68266832
func testSwiftClangOverride() throws {
68276833
var env = ProcessEnv.vars
68286834
let swiftClang = try AbsolutePath(validating: "/A/Path/swift-clang")
6835+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
68296836
env["SWIFT_DRIVER_CLANG_EXEC"] = swiftClang.pathString
68306837

68316838
var driver = try Driver(

0 commit comments

Comments
 (0)