Skip to content

Commit 5326852

Browse files
committed
Support building SourceKit-LSP without a dependency on SwiftPM
1 parent 718c0ee commit 5326852

File tree

10 files changed

+209
-109
lines changed

10 files changed

+209
-109
lines changed

Package.swift

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,12 @@ var targets: [Target] = [
8080
"SwiftExtensions",
8181
"ToolchainRegistry",
8282
"TSCExtensions",
83-
.product(name: "SwiftPM-auto", package: "swift-package-manager"),
84-
.product(name: "SwiftPMDataModel-auto", package: "swift-package-manager"),
8583
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
86-
],
84+
]
85+
+ swiftPMDependency([
86+
.product(name: "SwiftPM-auto", package: "swift-package-manager"),
87+
.product(name: "SwiftPMDataModel-auto", package: "swift-package-manager"),
88+
]),
8789
exclude: ["CMakeLists.txt"],
8890
swiftSettings: globalSwiftSettings
8991
),
@@ -387,8 +389,10 @@ var targets: [Target] = [
387389
.product(name: "IndexStoreDB", package: "indexstore-db"),
388390
.product(name: "Crypto", package: "swift-crypto"),
389391
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
390-
.product(name: "SwiftPM-auto", package: "swift-package-manager"),
391392
]
393+
+ swiftPMDependency([
394+
.product(name: "SwiftPM-auto", package: "swift-package-manager")
395+
])
392396
+ swiftSyntaxDependencies([
393397
"SwiftBasicFormat", "SwiftDiagnostics", "SwiftIDEUtils", "SwiftParser", "SwiftParserDiagnostics",
394398
"SwiftRefactor", "SwiftSyntax",
@@ -449,8 +453,6 @@ var targets: [Target] = [
449453
"SKUtilities",
450454
"SwiftExtensions",
451455
"TSCExtensions",
452-
.product(name: "SwiftPMDataModel-auto", package: "swift-package-manager"),
453-
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
454456
],
455457
exclude: ["CMakeLists.txt"],
456458
swiftSettings: globalSwiftSettings
@@ -461,8 +463,6 @@ var targets: [Target] = [
461463
dependencies: [
462464
"SKTestSupport",
463465
"ToolchainRegistry",
464-
.product(name: "SwiftPMDataModel-auto", package: "swift-package-manager"),
465-
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
466466
],
467467
swiftSettings: globalSwiftSettings
468468
),
@@ -524,6 +524,13 @@ func swiftSyntaxDependencies(_ names: [String]) -> [Target.Dependency] {
524524
}
525525
}
526526

527+
func swiftPMDependency<T>(_ values: [T]) -> [T] {
528+
if noSwiftPMDependency {
529+
return []
530+
}
531+
return values
532+
}
533+
527534
// MARK: - Parse build arguments
528535

529536
func hasEnvironmentVariable(_ name: String) -> Bool {
@@ -558,6 +565,9 @@ var buildDynamicSwiftSyntaxLibrary: Bool { hasEnvironmentVariable("SWIFTSYNTAX_B
558565
/// the `swift test` invocation so that all pre-built modules can be found.
559566
var buildOnlyTests: Bool { hasEnvironmentVariable("SOURCEKIT_LSP_BUILD_ONLY_TESTS") }
560567

568+
/// Build SourceKit-LSP without a dependency on SwiftPM, ie. without support for SwiftPM projects.
569+
var noSwiftPMDependency: Bool { hasEnvironmentVariable("SOURCEKIT_LSP_NO_SWIFTPM_DEPENDENCY") }
570+
561571
// MARK: - Dependencies
562572

563573
// When building with the swift build-script, use local dependencies whose contents are controlled
@@ -570,25 +580,26 @@ var dependencies: [Package.Dependency] {
570580
} else if useLocalDependencies {
571581
return [
572582
.package(path: "../indexstore-db"),
573-
.package(name: "swift-package-manager", path: "../swiftpm"),
574583
.package(path: "../swift-tools-support-core"),
575584
.package(path: "../swift-argument-parser"),
576585
.package(path: "../swift-syntax"),
577586
.package(path: "../swift-crypto"),
578-
]
587+
] + swiftPMDependency([.package(name: "swift-package-manager", path: "../swiftpm")])
579588
} else {
580589
let relatedDependenciesBranch = "main"
581590

582591
return [
583592
.package(url: "https://github.com/swiftlang/indexstore-db.git", branch: relatedDependenciesBranch),
584-
.package(url: "https://github.com/swiftlang/swift-package-manager.git", branch: relatedDependenciesBranch),
585593
.package(url: "https://github.com/apple/swift-tools-support-core.git", branch: relatedDependenciesBranch),
586594
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.4.0"),
587595
.package(url: "https://github.com/swiftlang/swift-syntax.git", branch: relatedDependenciesBranch),
588596
.package(url: "https://github.com/apple/swift-crypto.git", from: "3.0.0"),
589597
// Not a build dependency. Used so the "Format Source Code" command plugin can be used to format sourcekit-lsp
590598
.package(url: "https://github.com/swiftlang/swift-format.git", branch: relatedDependenciesBranch),
591599
]
600+
+ swiftPMDependency([
601+
.package(url: "https://github.com/swiftlang/swift-package-manager.git", branch: relatedDependenciesBranch)
602+
])
592603
}
593604
}
594605

Sources/BuildSystemIntegration/BuildSystemManager.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ private extension BuildSystemSpec {
210210
)
211211
}
212212
case .swiftPM:
213+
#if canImport(PackageModel)
213214
return await Self.createBuiltInBuildSystemAdapter(
214215
projectRoot: projectRoot,
215216
messagesToSourceKitLSPHandler: messagesToSourceKitLSPHandler,
@@ -223,6 +224,9 @@ private extension BuildSystemSpec {
223224
testHooks: testHooks.swiftPMTestHooks
224225
)
225226
}
227+
#else
228+
return nil
229+
#endif
226230
case .testBuildSystem:
227231
return await Self.createBuiltInBuildSystemAdapter(
228232
projectRoot: projectRoot,

Sources/BuildSystemIntegration/BuildSystemTestHooks.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@ package import LanguageServerProtocol
1616
import LanguageServerProtocol
1717
#endif
1818

19+
package struct SwiftPMTestHooks: Sendable {
20+
package var reloadPackageDidStart: (@Sendable () async -> Void)?
21+
package var reloadPackageDidFinish: (@Sendable () async -> Void)?
22+
23+
package init(
24+
reloadPackageDidStart: (@Sendable () async -> Void)? = nil,
25+
reloadPackageDidFinish: (@Sendable () async -> Void)? = nil
26+
) {
27+
self.reloadPackageDidStart = reloadPackageDidStart
28+
self.reloadPackageDidFinish = reloadPackageDidFinish
29+
}
30+
}
31+
1932
package struct BuildSystemTestHooks: Sendable {
2033
package var swiftPMTestHooks: SwiftPMTestHooks
2134

Sources/BuildSystemIntegration/BuildTargetIdentifierExtensions.swift

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,92 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#if compiler(>=6)
14-
package import BuildServerProtocol
13+
import Foundation
1514
import LanguageServerProtocol
1615
import SKLogging
16+
17+
#if compiler(>=6)
18+
package import BuildServerProtocol
1719
#else
1820
import BuildServerProtocol
19-
import LanguageServerProtocol
20-
import SKLogging
2121
#endif
2222

2323
extension BuildTargetIdentifier {
2424
package static let dummy: BuildTargetIdentifier = BuildTargetIdentifier(uri: try! URI(string: "dummy://dummy"))
2525
}
2626

27+
package enum BuildDestinationIdentifier {
28+
case host
29+
case target
30+
31+
/// A string that can be used to identify the build triple in a `BuildTargetIdentifier`.
32+
///
33+
/// `BuildSystemManager.canonicalBuildTargetIdentifier` picks the canonical target based on alphabetical
34+
/// ordering. We rely on the string "destination" being ordered before "tools" so that we prefer a
35+
/// `destination` (or "target") target over a `tools` (or "host") target.
36+
var id: String {
37+
switch self {
38+
case .host:
39+
return "tools"
40+
case .target:
41+
return "destination"
42+
}
43+
}
44+
}
45+
46+
extension BuildTargetIdentifier {
47+
/// - Important: *For testing only*
48+
package init(target: String, destination: BuildDestinationIdentifier) throws {
49+
var components = URLComponents()
50+
components.scheme = "swiftpm"
51+
components.host = "target"
52+
components.queryItems = [
53+
URLQueryItem(name: "target", value: target),
54+
URLQueryItem(name: "destination", value: destination.id),
55+
]
56+
57+
struct FailedToConvertSwiftBuildTargetToUrlError: Swift.Error, CustomStringConvertible {
58+
var target: String
59+
var destination: String
60+
61+
var description: String {
62+
return "Failed to generate URL for target: \(target), destination: \(destination)"
63+
}
64+
}
65+
66+
guard let url = components.url else {
67+
throw FailedToConvertSwiftBuildTargetToUrlError(target: target, destination: destination.id)
68+
}
69+
70+
self.init(uri: URI(url))
71+
}
72+
73+
fileprivate static let forPackageManifest = BuildTargetIdentifier(uri: try! URI(string: "swiftpm://package-manifest"))
74+
75+
fileprivate var targetProperties: (target: String, runDestination: String) {
76+
get throws {
77+
struct InvalidTargetIdentifierError: Swift.Error, CustomStringConvertible {
78+
var target: BuildTargetIdentifier
79+
80+
var description: String {
81+
return "Invalid target identifier \(target)"
82+
}
83+
}
84+
guard let components = URLComponents(url: self.uri.arbitrarySchemeURL, resolvingAgainstBaseURL: false) else {
85+
throw InvalidTargetIdentifierError(target: self)
86+
}
87+
let target = components.queryItems?.last(where: { $0.name == "target" })?.value
88+
let runDestination = components.queryItems?.last(where: { $0.name == "destination" })?.value
89+
90+
guard let target, let runDestination else {
91+
throw InvalidTargetIdentifierError(target: self)
92+
}
93+
94+
return (target, runDestination)
95+
}
96+
}
97+
}
98+
2799
#if compiler(>=6)
28100
extension BuildTargetIdentifier: CustomLogStringConvertible {
29101
package var description: String {

Sources/BuildSystemIntegration/DetermineBuildSystem.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,13 @@ package func determineBuildSystem(
5959
return BuildSystemSpec(kind: .compilationDatabase, projectRoot: projectRoot)
6060
}
6161
case .swiftPM:
62+
#if canImport(PackageModel)
6263
if let projectRoot = SwiftPMBuildSystem.projectRoot(for: workspaceFolderUrl, options: options) {
6364
return BuildSystemSpec(kind: .swiftPM, projectRoot: projectRoot)
6465
}
66+
#else
67+
return nil
68+
#endif
6569
}
6670
}
6771

Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift

Lines changed: 19 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -10,53 +10,41 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#if compiler(>=6)
13+
#if canImport(PackageModel)
1414
import Basics
1515
@preconcurrency import Build
16-
package import BuildServerProtocol
1716
import Dispatch
18-
package import Foundation
19-
package import LanguageServerProtocol
2017
import LanguageServerProtocolExtensions
2118
@preconcurrency import PackageGraph
2219
import PackageLoading
2320
import PackageModel
2421
import SKLogging
25-
package import SKOptions
2622
@preconcurrency package import SPMBuildCore
2723
import SourceControl
28-
package import SourceKitLSPAPI
2924
import SwiftExtensions
30-
package import ToolchainRegistry
3125
import TSCExtensions
3226
@preconcurrency import Workspace
3327

3428
import struct TSCBasic.AbsolutePath
3529
import class TSCBasic.Process
30+
31+
#if compiler(>=6)
32+
package import BuildServerProtocol
33+
package import BuildSystemIntegration
34+
package import Foundation
35+
package import LanguageServerProtocol
36+
package import SKOptions
37+
package import SourceKitLSPAPI
38+
package import ToolchainRegistry
3639
package import class ToolchainRegistry.Toolchain
3740
#else
38-
import Basics
39-
@preconcurrency import Build
4041
import BuildServerProtocol
41-
import Dispatch
42+
import BuildSystemIntegration
4243
import Foundation
4344
import LanguageServerProtocol
44-
import LanguageServerProtocolExtensions
45-
@preconcurrency import PackageGraph
46-
import PackageLoading
47-
import PackageModel
48-
import SKLogging
4945
import SKOptions
50-
@preconcurrency import SPMBuildCore
51-
import SourceControl
5246
import SourceKitLSPAPI
53-
import SwiftExtensions
5447
import ToolchainRegistry
55-
import TSCExtensions
56-
@preconcurrency import Workspace
57-
58-
import struct TSCBasic.AbsolutePath
59-
import class TSCBasic.Process
6048
import class ToolchainRegistry.Toolchain
6149
#endif
6250

@@ -78,51 +66,18 @@ fileprivate extension Basics.Diagnostic.Severity {
7866
}
7967
}
8068

81-
fileprivate extension BuildDestination {
82-
/// A string that can be used to identify the build triple in a `BuildTargetIdentifier`.
83-
///
84-
/// `BuildSystemManager.canonicalBuildTargetIdentifier` picks the canonical target based on alphabetical
85-
/// ordering. We rely on the string "destination" being ordered before "tools" so that we prefer a
86-
/// `destination` (or "target") target over a `tools` (or "host") target.
87-
var id: String {
88-
switch self {
89-
case .host:
90-
return "tools"
91-
case .target:
92-
return "destination"
69+
extension BuildDestinationIdentifier {
70+
init(_ destination: BuildDestination) {
71+
switch destination {
72+
case .target: self = .target
73+
case .host: self = .host
9374
}
9475
}
9576
}
9677

9778
extension BuildTargetIdentifier {
9879
fileprivate init(_ buildTarget: any SwiftBuildTarget) throws {
99-
try self.init(target: buildTarget.name, destination: buildTarget.destination)
100-
}
101-
102-
/// - Important: *For testing only*
103-
package init(target: String, destination: BuildDestination) throws {
104-
var components = URLComponents()
105-
components.scheme = "swiftpm"
106-
components.host = "target"
107-
components.queryItems = [
108-
URLQueryItem(name: "target", value: target),
109-
URLQueryItem(name: "destination", value: destination.id),
110-
]
111-
112-
struct FailedToConvertSwiftBuildTargetToUrlError: Swift.Error, CustomStringConvertible {
113-
var target: String
114-
var destination: String
115-
116-
var description: String {
117-
return "Failed to generate URL for target: \(target), destination: \(destination)"
118-
}
119-
}
120-
121-
guard let url = components.url else {
122-
throw FailedToConvertSwiftBuildTargetToUrlError(target: target, destination: destination.id)
123-
}
124-
125-
self.init(uri: URI(url))
80+
try self.init(target: buildTarget.name, destination: BuildDestinationIdentifier(buildTarget.destination))
12681
}
12782

12883
fileprivate static let forPackageManifest = BuildTargetIdentifier(uri: try! URI(string: "swiftpm://package-manifest"))
@@ -159,19 +114,6 @@ fileprivate extension TSCBasic.AbsolutePath {
159114

160115
fileprivate let preparationTaskID: AtomicUInt32 = AtomicUInt32(initialValue: 0)
161116

162-
package struct SwiftPMTestHooks: Sendable {
163-
package var reloadPackageDidStart: (@Sendable () async -> Void)?
164-
package var reloadPackageDidFinish: (@Sendable () async -> Void)?
165-
166-
package init(
167-
reloadPackageDidStart: (@Sendable () async -> Void)? = nil,
168-
reloadPackageDidFinish: (@Sendable () async -> Void)? = nil
169-
) {
170-
self.reloadPackageDidStart = reloadPackageDidStart
171-
self.reloadPackageDidFinish = reloadPackageDidFinish
172-
}
173-
}
174-
175117
/// Swift Package Manager build system and workspace support.
176118
///
177119
/// This class implements the `BuiltInBuildSystem` interface to provide the build settings for a Swift
@@ -793,3 +735,5 @@ fileprivate extension URL {
793735
(try? resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory == true
794736
}
795737
}
738+
739+
#endif

0 commit comments

Comments
 (0)