10
10
//
11
11
//===----------------------------------------------------------------------===//
12
12
13
- import struct Foundation. URL
14
-
15
- private import struct Basics. AbsolutePath
16
- private import func Basics. resolveSymlinks
17
-
18
- internal import SPMBuildCore
19
-
20
- // FIXME: should import these module with `private` or `internal` access control
21
- import class Build. BuildPlan
22
- import class Build. ClangModuleBuildDescription
23
- import class Build. SwiftModuleBuildDescription
24
- import struct PackageGraph. ResolvedModule
25
- import struct PackageGraph. ModulesGraph
26
- internal import class PackageModel. UserToolchain
13
+ import Foundation
14
+ import TSCBasic
15
+
16
+ // Ideally wouldn't expose these (it defeats the purpose of this module), but we should replace this entire API with
17
+ // a BSP server, so this is good enough for now (and LSP is using all these types internally anyway).
18
+ import Basics
19
+ import Build
20
+ import PackageGraph
21
+ internal import PackageLoading
22
+ internal import PackageModel
23
+ import SPMBuildCore
27
24
28
25
public enum BuildDestination {
29
26
case host
@@ -90,7 +87,13 @@ private struct WrappedClangTargetBuildDescription: BuildTarget {
90
87
}
91
88
92
89
var others : [ URL ] {
93
- return description. others. map ( \. asURL)
90
+ var others = Set ( description. others)
91
+ for pluginResult in description. buildToolPluginInvocationResults {
92
+ for buildCommand in pluginResult. buildCommands {
93
+ others. formUnion ( buildCommand. inputFiles)
94
+ }
95
+ }
96
+ return others. map ( \. asURL)
94
97
}
95
98
96
99
public var name : String {
@@ -102,7 +105,7 @@ private struct WrappedClangTargetBuildDescription: BuildTarget {
102
105
}
103
106
104
107
public func compileArguments( for fileURL: URL ) throws -> [ String ] {
105
- let filePath = try resolveSymlinks ( try AbsolutePath ( validating: fileURL. path) )
108
+ let filePath = try resolveSymlinks ( try Basics . AbsolutePath ( validating: fileURL. path) )
106
109
let commandLine = try description. emitCommandLine ( for: filePath)
107
110
// First element on the command line is the compiler itself, not an argument.
108
111
return Array ( commandLine. dropFirst ( ) )
@@ -143,7 +146,13 @@ private struct WrappedSwiftTargetBuildDescription: BuildTarget {
143
146
}
144
147
145
148
var others : [ URL ] {
146
- return description. others. map ( \. asURL)
149
+ var others = Set ( description. others)
150
+ for pluginResult in description. buildToolPluginInvocationResults {
151
+ for buildCommand in pluginResult. buildCommands {
152
+ others. formUnion ( buildCommand. inputFiles)
153
+ }
154
+ }
155
+ return others. map ( \. asURL)
147
156
}
148
157
149
158
func compileArguments( for fileURL: URL ) throws -> [ String ] {
@@ -160,14 +169,52 @@ public struct BuildDescription {
160
169
161
170
/// The inputs of the build plan so we don't need to re-compute them on every call to
162
171
/// `fileAffectsSwiftOrClangBuildSettings`.
163
- private let inputs : [ BuildPlan . Input ]
172
+ private let inputs : [ Build . BuildPlan . Input ]
164
173
165
- // FIXME: should not use `BuildPlan` in the public interface
174
+ /// Wrap an already constructed build plan.
166
175
public init ( buildPlan: Build . BuildPlan ) {
167
176
self . buildPlan = buildPlan
168
177
self . inputs = buildPlan. inputs
169
178
}
170
179
180
+ /// Construct a build description, compiling build tool plugins and generating their output when necessary.
181
+ public static func load(
182
+ destinationBuildParameters: BuildParameters ,
183
+ toolsBuildParameters: BuildParameters ,
184
+ packageGraph: ModulesGraph ,
185
+ pluginConfiguration: PluginConfiguration ,
186
+ traitConfiguration: TraitConfiguration ,
187
+ disableSandbox: Bool ,
188
+ scratchDirectory: URL ,
189
+ fileSystem: any FileSystem ,
190
+ observabilityScope: ObservabilityScope
191
+ ) async throws -> ( description: BuildDescription , errors: String ) {
192
+ let bufferedOutput = BufferedOutputByteStream ( )
193
+ let threadSafeOutput = ThreadSafeOutputByteStream ( bufferedOutput)
194
+
195
+ // This is quite an abuse of `BuildOperation`, building plugins should really be refactored out of it. Though
196
+ // even better would be to have a BSP server that handles both preparing and getting settings.
197
+ // https://github.com/swiftlang/swift-package-manager/issues/8287
198
+ let operation = BuildOperation (
199
+ productsBuildParameters: destinationBuildParameters,
200
+ toolsBuildParameters: toolsBuildParameters,
201
+ cacheBuildManifest: true ,
202
+ packageGraphLoader: { packageGraph } ,
203
+ pluginConfiguration: pluginConfiguration,
204
+ scratchDirectory: try Basics . AbsolutePath ( validating: scratchDirectory. path) ,
205
+ traitConfiguration: traitConfiguration,
206
+ additionalFileRules: FileRuleDescription . swiftpmFileTypes,
207
+ pkgConfigDirectories: [ ] ,
208
+ outputStream: threadSafeOutput,
209
+ logLevel: . error,
210
+ fileSystem: fileSystem,
211
+ observabilityScope: observabilityScope
212
+ )
213
+
214
+ let plan = try await operation. generatePlan ( )
215
+ return ( BuildDescription ( buildPlan: plan) , bufferedOutput. bytes. description)
216
+ }
217
+
171
218
func getBuildTarget(
172
219
for module: ResolvedModule ,
173
220
destination: BuildParameters . Destination
@@ -219,7 +266,7 @@ public struct BuildDescription {
219
266
/// Returns `true` if the file at the given path might influence build settings for a `swiftc` or `clang` invocation
220
267
/// generated by SwiftPM.
221
268
public func fileAffectsSwiftOrClangBuildSettings( _ url: URL ) -> Bool {
222
- guard let filePath = try ? AbsolutePath ( validating: url. path) else {
269
+ guard let filePath = try ? Basics . AbsolutePath ( validating: url. path) else {
223
270
return false
224
271
}
225
272
0 commit comments