@@ -24,44 +24,44 @@ import var TSCBasic.localFileSystem
24
24
///
25
25
/// This can be an explicit toolchain, such as an xctoolchain directory on Darwin, or an implicit
26
26
/// toolchain, such as the contents from `/usr/bin`.
27
- public final class Toolchain {
27
+ public final class Toolchain : Sendable {
28
28
29
29
/// The unique toolchain identifier.
30
30
///
31
31
/// For an xctoolchain, this is a reverse domain name e.g. "com.apple.dt.toolchain.XcodeDefault".
32
32
/// Otherwise, it is typically derived from `path`.
33
- public var identifier : String
33
+ public let identifier : String
34
34
35
35
/// The human-readable name for the toolchain.
36
- public var displayName : String
36
+ public let displayName : String
37
37
38
38
/// The path to this toolchain, if applicable.
39
39
///
40
40
/// For example, this may be the path to an ".xctoolchain" directory.
41
- public var path : AbsolutePath ? = nil
41
+ public let path : AbsolutePath ?
42
42
43
43
// MARK: Tool Paths
44
44
45
45
/// The path to the Clang compiler if available.
46
- public var clang : AbsolutePath ?
46
+ public let clang : AbsolutePath ?
47
47
48
48
/// The path to the Swift driver if available.
49
- public var swift : AbsolutePath ?
49
+ public let swift : AbsolutePath ?
50
50
51
51
/// The path to the Swift compiler if available.
52
- public var swiftc : AbsolutePath ?
52
+ public let swiftc : AbsolutePath ?
53
53
54
54
/// The path to the swift-format executable, if available.
55
- public var swiftFormat : AbsolutePath ?
55
+ public let swiftFormat : AbsolutePath ?
56
56
57
57
/// The path to the clangd language server if available.
58
- public var clangd : AbsolutePath ?
58
+ public let clangd : AbsolutePath ?
59
59
60
60
/// The path to the Swift language server if available.
61
- public var sourcekitd : AbsolutePath ?
61
+ public let sourcekitd : AbsolutePath ?
62
62
63
63
/// The path to the indexstore library if available.
64
- public var libIndexStore : AbsolutePath ?
64
+ public let libIndexStore : AbsolutePath ?
65
65
66
66
public init (
67
67
identifier: String ,
@@ -135,101 +135,123 @@ extension Toolchain {
135
135
/// If `path` contains an ".xctoolchain", we try to read an Info.plist file to provide the
136
136
/// toolchain identifier, etc. Otherwise this information is derived from the path.
137
137
convenience public init ? ( _ path: AbsolutePath , _ fileSystem: FileSystem = localFileSystem) {
138
+ // Properties that need to be initialized
139
+ let identifier : String
140
+ let displayName : String
141
+ let toolchainPath : AbsolutePath ?
142
+ var clang : AbsolutePath ? = nil
143
+ var clangd : AbsolutePath ? = nil
144
+ var swift : AbsolutePath ? = nil
145
+ var swiftc : AbsolutePath ? = nil
146
+ var swiftFormat : AbsolutePath ? = nil
147
+ var sourcekitd : AbsolutePath ? = nil
148
+ var libIndexStore : AbsolutePath ? = nil
149
+
138
150
if let ( infoPlist, xctoolchainPath) = containingXCToolchain ( path, fileSystem) {
139
- let displayName = infoPlist. displayName ?? xctoolchainPath. basenameWithoutExt
140
- self . init ( identifier: infoPlist. identifier, displayName: displayName, path: xctoolchainPath)
151
+ identifier = infoPlist. identifier
152
+ displayName = infoPlist. displayName ?? xctoolchainPath. basenameWithoutExt
153
+ toolchainPath = xctoolchainPath
141
154
} else {
142
- self . init ( identifier: path. pathString, displayName: path. basename, path: path)
155
+ identifier = path. pathString
156
+ displayName = path. basename
157
+ toolchainPath = path
143
158
}
144
159
145
- if !searchForTools( path, fileSystem) {
146
- return nil
147
- }
148
- }
160
+ // Find tools in the toolchain
149
161
150
- /// Search `path` for tools, returning true if any are found.
151
- @discardableResult
152
- func searchForTools( _ path: AbsolutePath , _ fs: FileSystem = localFileSystem) -> Bool {
153
- return
154
- searchForTools ( binPath: path, fs) || searchForTools ( binPath: path. appending ( components: " bin " ) , fs)
155
- || searchForTools ( binPath: path. appending ( components: " usr " , " bin " ) , fs)
156
- }
157
-
158
- private func searchForTools( binPath: AbsolutePath , _ fs: FileSystem ) -> Bool {
159
-
160
- let libPath = binPath. parentDirectory. appending ( component: " lib " )
162
+ var foundAny = false
163
+ let searchPaths = [ path, path. appending ( components: " bin " ) , path. appending ( components: " usr " , " bin " ) ]
164
+ for binPath in searchPaths {
165
+ let libPath = binPath. parentDirectory. appending ( component: " lib " )
161
166
162
- guard fs . isDirectory ( binPath) || fs . isDirectory ( libPath) else { return false }
167
+ guard fileSystem . isDirectory ( binPath) || fileSystem . isDirectory ( libPath) else { continue }
163
168
164
- var foundAny = false
169
+ let execExt = Platform . current ? . executableExtension ?? " "
165
170
166
- let execExt = Platform . current? . executableExtension ?? " "
171
+ let clangPath = binPath. appending ( component: " clang \( execExt) " )
172
+ if fileSystem. isExecutableFile ( clangPath) {
173
+ clang = clangPath
174
+ foundAny = true
175
+ }
176
+ let clangdPath = binPath. appending ( component: " clangd \( execExt) " )
177
+ if fileSystem. isExecutableFile ( clangdPath) {
178
+ clangd = clangdPath
179
+ foundAny = true
180
+ }
167
181
168
- let clangPath = binPath. appending ( component: " clang \( execExt) " )
169
- if fs. isExecutableFile ( clangPath) {
170
- self . clang = clangPath
171
- foundAny = true
172
- }
173
- let clangdPath = binPath. appending ( component: " clangd \( execExt) " )
174
- if fs. isExecutableFile ( clangdPath) {
175
- self . clangd = clangdPath
176
- foundAny = true
177
- }
182
+ let swiftPath = binPath. appending ( component: " swift \( execExt) " )
183
+ if fileSystem. isExecutableFile ( swiftPath) {
184
+ swift = swiftPath
185
+ foundAny = true
186
+ }
178
187
179
- let swiftPath = binPath. appending ( component: " swift \( execExt) " )
180
- if fs . isExecutableFile ( swiftPath ) {
181
- self . swift = swiftPath
182
- foundAny = true
183
- }
188
+ let swiftcPath = binPath. appending ( component: " swiftc \( execExt) " )
189
+ if fileSystem . isExecutableFile ( swiftcPath ) {
190
+ swiftc = swiftcPath
191
+ foundAny = true
192
+ }
184
193
185
- let swiftcPath = binPath. appending ( component: " swiftc \( execExt) " )
186
- if fs . isExecutableFile ( swiftcPath ) {
187
- self . swiftc = swiftcPath
188
- foundAny = true
189
- }
194
+ let swiftFormatPath = binPath. appending ( component: " swift-format \( execExt) " )
195
+ if fileSystem . isExecutableFile ( swiftFormatPath ) {
196
+ swiftFormat = swiftFormatPath
197
+ foundAny = true
198
+ }
190
199
191
- let swiftFormatPath = binPath. appending ( component: " swift-format \( execExt) " )
192
- if fs. isExecutableFile ( swiftFormatPath) {
193
- self . swiftFormat = swiftFormatPath
194
- foundAny = true
195
- }
200
+ // If 'currentPlatform' is nil it's most likely an unknown linux flavor.
201
+ let dylibExt : String
202
+ if let dynamicLibraryExtension = Platform . current? . dynamicLibraryExtension {
203
+ dylibExt = dynamicLibraryExtension
204
+ } else {
205
+ logger. fault ( " Could not determine host OS. Falling back to using '.so' as dynamic library extension " )
206
+ dylibExt = " .so "
207
+ }
196
208
197
- // If 'currentPlatform' is nil it's most likely an unknown linux flavor.
198
- let dylibExt : String
199
- if let dynamicLibraryExtension = Platform . current? . dynamicLibraryExtension {
200
- dylibExt = dynamicLibraryExtension
201
- } else {
202
- logger. fault ( " Could not determine host OS. Falling back to using '.so' as dynamic library extension " )
203
- dylibExt = " .so "
204
- }
209
+ let sourcekitdPath = libPath. appending ( components: " sourcekitd.framework " , " sourcekitd " )
210
+ if fileSystem. isFile ( sourcekitdPath) {
211
+ sourcekitd = sourcekitdPath
212
+ foundAny = true
213
+ } else {
214
+ #if os(Windows)
215
+ let sourcekitdPath = binPath. appending ( component: " sourcekitdInProc \( dylibExt) " )
216
+ #else
217
+ let sourcekitdPath = libPath. appending ( component: " libsourcekitdInProc \( dylibExt) " )
218
+ #endif
219
+ if fileSystem. isFile ( sourcekitdPath) {
220
+ sourcekitd = sourcekitdPath
221
+ foundAny = true
222
+ }
223
+ }
205
224
206
- let sourcekitdPath = libPath. appending ( components: " sourcekitd.framework " , " sourcekitd " )
207
- if fs. isFile ( sourcekitdPath) {
208
- self . sourcekitd = sourcekitdPath
209
- foundAny = true
210
- } else {
211
225
#if os(Windows)
212
- let sourcekitdPath = binPath. appending ( component : " sourcekitdInProc \( dylibExt) " )
226
+ let libIndexStorePath = binPath. appending ( components : " libIndexStore \( dylibExt) " )
213
227
#else
214
- let sourcekitdPath = libPath. appending ( component : " libsourcekitdInProc \( dylibExt) " )
228
+ let libIndexStorePath = libPath. appending ( components : " libIndexStore \( dylibExt) " )
215
229
#endif
216
- if fs . isFile ( sourcekitdPath ) {
217
- self . sourcekitd = sourcekitdPath
230
+ if fileSystem . isFile ( libIndexStorePath ) {
231
+ libIndexStore = libIndexStorePath
218
232
foundAny = true
219
233
}
220
- }
221
234
222
- #if os(Windows)
223
- let libIndexStore = binPath. appending ( components: " libIndexStore \( dylibExt) " )
224
- #else
225
- let libIndexStore = libPath. appending ( components: " libIndexStore \( dylibExt) " )
226
- #endif
227
- if fs. isFile ( libIndexStore) {
228
- self . libIndexStore = libIndexStore
229
- foundAny = true
235
+ if foundAny {
236
+ break
237
+ }
238
+ }
239
+ if !foundAny {
240
+ return nil
230
241
}
231
242
232
- return foundAny
243
+ self . init (
244
+ identifier: identifier,
245
+ displayName: displayName,
246
+ path: toolchainPath,
247
+ clang: clang,
248
+ swift: swift,
249
+ swiftc: swiftc,
250
+ swiftFormat: swiftFormat,
251
+ clangd: clangd,
252
+ sourcekitd: sourcekitd,
253
+ libIndexStore: libIndexStore
254
+ )
233
255
}
234
256
}
235
257
0 commit comments