Skip to content

Commit 4bc1e80

Browse files
committed
Make SKSwiftPMWorkspace build with strict concurrency
1 parent 7e861f5 commit 4bc1e80

File tree

4 files changed

+113
-88
lines changed

4 files changed

+113
-88
lines changed

Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,8 @@ let package = Package(
226226
.product(name: "SwiftPM-auto", package: "swift-package-manager"),
227227
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
228228
],
229-
exclude: ["CMakeLists.txt"]
229+
exclude: ["CMakeLists.txt"],
230+
swiftSettings: [.enableExperimentalFeature("StrictConcurrency")]
230231
),
231232

232233
.testTarget(

Sources/LSPLogging/OrLog.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import os
1515
#endif
1616

17-
private func logError(prefix: String, error: Error, level: LogLevel) {
17+
public func logError(prefix: String, error: Error, level: LogLevel = .error) {
1818
logger.log(
1919
level: level,
2020
"\(prefix, privacy: .public)\(prefix.isEmpty ? "" : ": ", privacy: .public)\(error.forLogging)"

Sources/SKCore/Toolchain.swift

Lines changed: 106 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -24,44 +24,44 @@ import var TSCBasic.localFileSystem
2424
///
2525
/// This can be an explicit toolchain, such as an xctoolchain directory on Darwin, or an implicit
2626
/// toolchain, such as the contents from `/usr/bin`.
27-
public final class Toolchain {
27+
public final class Toolchain: Sendable {
2828

2929
/// The unique toolchain identifier.
3030
///
3131
/// For an xctoolchain, this is a reverse domain name e.g. "com.apple.dt.toolchain.XcodeDefault".
3232
/// Otherwise, it is typically derived from `path`.
33-
public var identifier: String
33+
public let identifier: String
3434

3535
/// The human-readable name for the toolchain.
36-
public var displayName: String
36+
public let displayName: String
3737

3838
/// The path to this toolchain, if applicable.
3939
///
4040
/// For example, this may be the path to an ".xctoolchain" directory.
41-
public var path: AbsolutePath? = nil
41+
public let path: AbsolutePath?
4242

4343
// MARK: Tool Paths
4444

4545
/// The path to the Clang compiler if available.
46-
public var clang: AbsolutePath?
46+
public let clang: AbsolutePath?
4747

4848
/// The path to the Swift driver if available.
49-
public var swift: AbsolutePath?
49+
public let swift: AbsolutePath?
5050

5151
/// The path to the Swift compiler if available.
52-
public var swiftc: AbsolutePath?
52+
public let swiftc: AbsolutePath?
5353

5454
/// The path to the swift-format executable, if available.
55-
public var swiftFormat: AbsolutePath?
55+
public let swiftFormat: AbsolutePath?
5656

5757
/// The path to the clangd language server if available.
58-
public var clangd: AbsolutePath?
58+
public let clangd: AbsolutePath?
5959

6060
/// The path to the Swift language server if available.
61-
public var sourcekitd: AbsolutePath?
61+
public let sourcekitd: AbsolutePath?
6262

6363
/// The path to the indexstore library if available.
64-
public var libIndexStore: AbsolutePath?
64+
public let libIndexStore: AbsolutePath?
6565

6666
public init(
6767
identifier: String,
@@ -135,101 +135,123 @@ extension Toolchain {
135135
/// If `path` contains an ".xctoolchain", we try to read an Info.plist file to provide the
136136
/// toolchain identifier, etc. Otherwise this information is derived from the path.
137137
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+
138150
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
141154
} else {
142-
self.init(identifier: path.pathString, displayName: path.basename, path: path)
155+
identifier = path.pathString
156+
displayName = path.basename
157+
toolchainPath = path
143158
}
144159

145-
if !searchForTools(path, fileSystem) {
146-
return nil
147-
}
148-
}
160+
// Find tools in the toolchain
149161

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")
161166

162-
guard fs.isDirectory(binPath) || fs.isDirectory(libPath) else { return false }
167+
guard fileSystem.isDirectory(binPath) || fileSystem.isDirectory(libPath) else { continue }
163168

164-
var foundAny = false
169+
let execExt = Platform.current?.executableExtension ?? ""
165170

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+
}
167181

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+
}
178187

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+
}
184193

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+
}
190199

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+
}
196208

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+
}
205224

206-
let sourcekitdPath = libPath.appending(components: "sourcekitd.framework", "sourcekitd")
207-
if fs.isFile(sourcekitdPath) {
208-
self.sourcekitd = sourcekitdPath
209-
foundAny = true
210-
} else {
211225
#if os(Windows)
212-
let sourcekitdPath = binPath.appending(component: "sourcekitdInProc\(dylibExt)")
226+
let libIndexStorePath = binPath.appending(components: "libIndexStore\(dylibExt)")
213227
#else
214-
let sourcekitdPath = libPath.appending(component: "libsourcekitdInProc\(dylibExt)")
228+
let libIndexStorePath = libPath.appending(components: "libIndexStore\(dylibExt)")
215229
#endif
216-
if fs.isFile(sourcekitdPath) {
217-
self.sourcekitd = sourcekitdPath
230+
if fileSystem.isFile(libIndexStorePath) {
231+
libIndexStore = libIndexStorePath
218232
foundAny = true
219233
}
220-
}
221234

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
230241
}
231242

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+
)
233255
}
234256
}
235257

Sources/SKSwiftPMWorkspace/SwiftPMBuildSystem.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import SPMBuildCore
3939
/// Parameter of `reloadPackageStatusCallback` in ``SwiftPMWorkspace``.
4040
///
4141
/// Informs the callback about whether `reloadPackage` started or finished executing.
42-
public enum ReloadPackageStatus {
42+
public enum ReloadPackageStatus: Sendable {
4343
case start
4444
case end
4545
}
@@ -363,9 +363,11 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
363363
public func filesDidChange(_ events: [FileEvent]) async {
364364
if events.contains(where: { self.fileEventShouldTriggerPackageReload(event: $0) }) {
365365
logger.log("Reloading package because of file change")
366-
await orLog("Reloading package") {
366+
do {
367367
// TODO: It should not be necessary to reload the entire package just to get build settings for one file.
368368
try await self.reloadPackage()
369+
} catch {
370+
logError(prefix: "Reloading package", error: error)
369371
}
370372
}
371373
}

0 commit comments

Comments
 (0)