Skip to content

Commit e53c79b

Browse files
committed
ADD - look for tools relative to the executable path.
Once swift-driver is installed in the Toolchain, we can look for tools right next to it's executable path, this help us to be more platform agnostic while locating the toolchain. This is the first step in this direction, we will need to make this more robust to get rid of xcrun if possible, and get a proper linux implementation.
1 parent c393e30 commit e53c79b

File tree

3 files changed

+50
-31
lines changed

3 files changed

+50
-31
lines changed

Sources/SwiftDriver/Toolchains/DarwinToolchain.swift

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,38 +20,25 @@ fileprivate func envVarName(forExecutable toolName: String) -> String {
2020
/// FIXME: This class is not thread-safe.
2121
public final class DarwinToolchain: Toolchain {
2222
public let env: [String: String]
23-
24-
func xcrunFind(exec: String) throws -> AbsolutePath {
25-
if let overrideString = env[envVarName(forExecutable: exec)] {
26-
return try AbsolutePath(validating: overrideString)
27-
}
28-
29-
#if os(macOS)
30-
let path = try Process.checkNonZeroExit(
31-
arguments: ["xcrun", "-sdk", "macosx", "--find", exec],
32-
environment: env
33-
).spm_chomp()
34-
return AbsolutePath(path)
35-
#else
36-
// This is a hack so our tests work on linux. We need a better way for looking up tools in general.
37-
return AbsolutePath("/usr/bin/" + exec)
38-
#endif
23+
24+
public init(env: [String: String]) {
25+
self.env = env
3926
}
40-
27+
4128
/// Retrieve the absolute path for a given tool.
4229
public func getToolPath(_ tool: Tool) throws -> AbsolutePath {
4330
switch tool {
4431
case .swiftCompiler:
45-
return try xcrunFind(exec: "swift")
32+
return try lookup(exec: "swift")
4633

4734
case .dynamicLinker:
48-
return try xcrunFind(exec: "ld")
35+
return try lookup(exec: "ld")
4936

5037
case .staticLinker:
51-
return try xcrunFind(exec: "libtool")
38+
return try lookup(exec: "libtool")
5239

5340
case .dsymutil:
54-
return try xcrunFind(exec: "dsymutil")
41+
return try lookup(exec: "dsymutil")
5542

5643
case .clang:
5744
let result = try Process.checkNonZeroExit(
@@ -60,13 +47,13 @@ public final class DarwinToolchain: Toolchain {
6047
).spm_chomp()
6148
return AbsolutePath(result)
6249
case .swiftAutolinkExtract:
63-
return try xcrunFind(exec: "swift-autolink-extract")
50+
return try lookup(exec: "swift-autolink-extract")
6451
}
6552
}
6653

6754
/// Swift compiler path.
6855
public lazy var swiftCompiler: Result<AbsolutePath, Swift.Error> = Result {
69-
try xcrunFind(exec: "swift")
56+
try lookup(exec: "swift")
7057
}
7158

7259
/// SDK path.
@@ -88,11 +75,6 @@ public final class DarwinToolchain: Toolchain {
8875
return swiftCompiler.map{ $0.appending(RelativePath("../../lib/swift/macosx")) }
8976
}
9077

91-
92-
public init(env: [String: String]) {
93-
self.env = env
94-
}
95-
9678
public func makeLinkerOutputFilename(moduleName: String, type: LinkOutputType) -> String {
9779
switch type {
9880
case .executable: return moduleName
@@ -137,4 +119,29 @@ public final class DarwinToolchain: Toolchain {
137119
\(isShared ? "_dynamic.dylib" : ".a")
138120
"""
139121
}
122+
123+
/// Looks for the executable in the `SWIFT_DRIVER_TOOLNAME_EXEC` enviroment variable, if found nothing,
124+
/// looks in the executable path; finally, fallback to xcrunFind.
125+
/// - Parameter exec: executable to look for [i.e. `swift`].
126+
func lookup(exec: String) throws -> AbsolutePath {
127+
if let overrideString = env[envVarName(forExecutable: exec)] {
128+
return try AbsolutePath(validating: overrideString)
129+
} else if let path = lookupExecutablePath(filename: exec, searchPaths: [executableDir]) {
130+
return path
131+
}
132+
return try xcrunFind(exec: exec)
133+
}
134+
135+
private func xcrunFind(exec: String) throws -> AbsolutePath {
136+
#if os(macOS)
137+
let path = try Process.checkNonZeroExit(
138+
arguments: ["xcrun", "-sdk", "macosx", "--find", exec],
139+
environment: env
140+
).spm_chomp()
141+
return AbsolutePath(path)
142+
#else
143+
// This is a hack so our tests work on linux. We need a better way for looking up tools in general.
144+
return AbsolutePath("/usr/bin/" + exec)
145+
#endif
146+
}
140147
}

Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,22 @@ public final class GenericUnixToolchain: Toolchain {
2626
self.searchPaths = getEnvSearchPaths(pathString: env["PATH"], currentWorkingDirectory: localFileSystem.currentWorkingDirectory)
2727
}
2828

29+
/// Looks in the `executablePath`, if found nothing, looks in the enviroment search paths.
30+
/// - Parameter exec: executable to look for [i.e. `swift`].
2931
private func lookup(exec: String) throws -> AbsolutePath {
30-
if let path = lookupExecutablePath(filename: exec, searchPaths: searchPaths) {
32+
if let path = lookupExecutablePath(filename: exec, searchPaths: [executableDir]) {
33+
return path
34+
} else if let path = lookupExecutablePath(filename: exec, searchPaths: searchPaths) {
3135
return path
3236
}
3337

3438
// If we happen to be on a macOS host, some tools might not be in our
3539
// PATH, so we'll just use xcrun to find them too.
3640
#if os(macOS)
37-
return try DarwinToolchain(env: self.env).xcrunFind(exec: exec)
41+
return try DarwinToolchain(env: self.env).lookup(exec: exec)
3842
#else
3943
throw Error.unableToFind(tool: exec)
4044
#endif
41-
4245
}
4346

4447
public func makeLinkerOutputFilename(moduleName: String, type: LinkOutputType) -> String {

Sources/SwiftDriver/Toolchains/Toolchain.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12+
import Foundation
1213
import TSCBasic
1314

1415
public enum Tool {
@@ -74,4 +75,12 @@ extension Toolchain {
7475
).spm_chomp()
7576
return Triple(triple)
7677
}
78+
79+
/// Returns the `executablePath`'s directory.
80+
public var executableDir: AbsolutePath {
81+
guard let path = Bundle.main.executablePath else {
82+
fatalError("Could not find executable path.")
83+
}
84+
return AbsolutePath(path).parentDirectory
85+
}
7786
}

0 commit comments

Comments
 (0)