Skip to content

Commit 4a56528

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

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

Sources/SwiftDriver/Toolchains/Toolchain.swift

Lines changed: 31 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
@@ -221,33 +222,47 @@ extension Toolchain {
221222
/// looks in the `executableDir`, `xcrunFind` or in the `searchPaths`.
222223
/// - Parameter executable: executable to look for [i.e. `swift`]. Executable suffix (eg. `.exe`) should be omitted.
223224
func lookup(executable: String) throws -> AbsolutePath {
225+
// 1. Check the `SWIFT_DRIVER_<TOOLNAME>_EXEC` override.
224226
if let overrideString = envVar(forExecutable: executable),
225227
let path = try? AbsolutePath(validating: overrideString) {
228+
if !fallbackToExecutableDefaultPath && !fileSystem.isExecutableFile(path) {
229+
throw ToolchainError.notAValidExecutablePath(path.pathString)
230+
}
226231
return path
232+
// 2. If `-tools-directory` is set, check there.
227233
} else if let toolDir = toolDirectory,
228234
let path = lookupExecutablePath(filename: executableName(executable), currentWorkingDirectory: nil, searchPaths: [toolDir]) {
229-
// Looking for tools from the tools directory.
230235
return path
236+
// 3. Perform lookup relative to the driver's executable
231237
} else if let path = lookupExecutablePath(filename: executableName(executable), currentWorkingDirectory: fileSystem.currentWorkingDirectory, searchPaths: [try executableDir]) {
232238
return path
233239
}
240+
241+
// 4. Attempt lookup with `xcrun --find`.
234242
#if canImport(Darwin)
235243
if let path = try? xcrunFind(executable: executableName(executable)) {
236244
return path
237245
}
238246
#endif
247+
248+
// 5. If querying not the compiler frontend itself and the above attempts failed,
249+
// attempt to resolve adjacent to the compiler frontend.
239250
if !["swift-frontend", "swift"].contains(executable),
240251
let parentDirectory = try? getToolPath(.swiftCompiler).parentDirectory,
241252
try parentDirectory != executableDir,
242253
let path = lookupExecutablePath(filename: executableName(executable), searchPaths: [parentDirectory]) {
243254
// If the driver library's client and the frontend are in different directories,
244255
// try looking for tools next to the frontend.
245256
return path
257+
// 6. Perform lookup in the toolchain search paths (e.g. $PATH)
246258
} else if let path = lookupExecutablePath(filename: executableName(executable), searchPaths: searchPaths) {
247259
return path
260+
// 7. Attempt lookup of `swift` for the compiler frontned
261+
// FIXME: we should remove this now
248262
} else if executable == "swift-frontend" {
249263
// Temporary shim: fall back to looking for "swift" before failing.
250264
return try lookup(executable: "swift")
265+
// 8. For testing purposes, attempt lookup in the system "default" paths
251266
} else if fallbackToExecutableDefaultPath {
252267
if self is WindowsToolchain {
253268
return try getToolPath(.swiftCompiler)
@@ -258,7 +273,7 @@ extension Toolchain {
258273
}
259274
}
260275

261-
throw ToolchainError.unableToFind(tool: executable)
276+
throw ToolchainError.unableToFind(executable)
262277
}
263278

264279
/// Looks for the executable in the `SWIFT_DRIVER_SWIFTSCAN_LIB` environment variable, if found nothing,
@@ -311,7 +326,7 @@ extension Toolchain {
311326
private func xcrunFind(executable: String) throws -> AbsolutePath {
312327
let xcrun = "xcrun"
313328
guard lookupExecutablePath(filename: xcrun, searchPaths: searchPaths) != nil else {
314-
throw ToolchainError.unableToFind(tool: xcrun)
329+
throw ToolchainError.unableToFind(xcrun)
315330
}
316331

317332
let path = try executor.checkNonZeroExit(
@@ -378,6 +393,17 @@ extension Toolchain {
378393
}
379394
}
380395

381-
@_spi(Testing) public enum ToolchainError: Swift.Error {
382-
case unableToFind(tool: String)
396+
@_spi(Testing) public enum ToolchainError: Swift.Error, Equatable, DiagnosticData {
397+
case unableToFind(String)
398+
case notAValidExecutablePath(String)
399+
400+
public var description: String {
401+
switch self {
402+
case .unableToFind(let tool):
403+
return "unable to locate tool: '\(tool)'"
404+
case .notAValidExecutablePath(let path):
405+
return "not a valid executable: \(path)"
406+
407+
}
408+
}
383409
}

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ final class SwiftDriverTests: XCTestCase {
8282
// so there is no swift-help in the toolchain yet. Set the environment variable
8383
// as if we had found it for the purposes of testing build planning.
8484
var env = ProcessEnv.block
85+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
8586
env["SWIFT_DRIVER_SWIFT_HELP_EXEC"] = "/tmp/.test-swift-help"
8687
return env
8788
}
@@ -2504,6 +2505,7 @@ final class SwiftDriverTests: XCTestCase {
25042505

25052506
func testWebAssemblyUnsupportedFeatures() throws {
25062507
var env = ProcessEnv.block
2508+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
25072509
env["SWIFT_DRIVER_SWIFT_AUTOLINK_EXTRACT_EXEC"] = "/garbage/swift-autolink-extract"
25082510
do {
25092511
var driver = try Driver(args: ["swift", "-target", "wasm32-unknown-wasi", "foo.swift"], env: env)
@@ -4841,6 +4843,7 @@ final class SwiftDriverTests: XCTestCase {
48414843
// Drop SWIFT_DRIVER_CLANG_EXEC from the environment so it doesn't
48424844
// interfere with tool lookup.
48434845
var env = ProcessEnv.block
4846+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
48444847
env.removeValue(forKey: "SWIFT_DRIVER_CLANG_EXEC")
48454848

48464849
var driver = try Driver(args: ["swiftc",
@@ -5248,6 +5251,7 @@ final class SwiftDriverTests: XCTestCase {
52485251
// As per Unix conventions, /var/empty is expected to exist and be empty.
52495252
// This gives us a non-existent path that we can use for libtool which
52505253
// allows us to run this this on non-Darwin platforms.
5254+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
52515255
env["SWIFT_DRIVER_LIBTOOL_EXEC"] = "/var/empty/libtool"
52525256

52535257
// No dSYM generation (-g -emit-library -static)
@@ -6760,6 +6764,7 @@ final class SwiftDriverTests: XCTestCase {
67606764

67616765
func testEmbeddedSwiftOptions() throws {
67626766
var env = ProcessEnv.block
6767+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
67636768
env["SWIFT_DRIVER_SWIFT_AUTOLINK_EXTRACT_EXEC"] = "/garbage/swift-autolink-extract"
67646769

67656770
do {
@@ -6916,6 +6921,7 @@ final class SwiftDriverTests: XCTestCase {
69166921
// better override.
69176922
var env = ProcessEnv.block
69186923
let swiftHelp: AbsolutePath = try AbsolutePath(validating: "/usr/bin/nonexistent-swift-help")
6924+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
69196925
env["SWIFT_DRIVER_SWIFT_HELP_EXEC"] = swiftHelp.pathString
69206926
env["SWIFT_DRIVER_CLANG_EXEC"] = "/usr/bin/clang"
69216927
var driver = try Driver(
@@ -6929,6 +6935,7 @@ final class SwiftDriverTests: XCTestCase {
69296935
func testSwiftClangOverride() throws {
69306936
var env = ProcessEnv.block
69316937
let swiftClang = try AbsolutePath(validating: "/A/Path/swift-clang")
6938+
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"
69326939
env["SWIFT_DRIVER_CLANG_EXEC"] = swiftClang.pathString
69336940

69346941
var driver = try Driver(

0 commit comments

Comments
 (0)