@@ -28,10 +28,14 @@ import Workspace
28
28
import struct Basics. AbsolutePath
29
29
import struct Basics. TSCAbsolutePath
30
30
import struct Foundation. URL
31
+ import struct TSCBasic. AbsolutePath
31
32
import protocol TSCBasic. FileSystem
33
+ import class TSCBasic. Process
32
34
import var TSCBasic. localFileSystem
33
35
import func TSCBasic. resolveSymlinks
34
36
37
+ typealias AbsolutePath = Basics . AbsolutePath
38
+
35
39
#if canImport(SPMBuildCore)
36
40
import SPMBuildCore
37
41
#endif
@@ -91,9 +95,11 @@ public actor SwiftPMBuildSystem {
91
95
let workspace : Workspace
92
96
public let buildParameters : BuildParameters
93
97
let fileSystem : FileSystem
98
+ private let toolchainRegistry : ToolchainRegistry
94
99
95
100
var fileToTarget : [ AbsolutePath : SwiftBuildTarget ] = [ : ]
96
101
var sourceDirToTarget : [ AbsolutePath : SwiftBuildTarget ] = [ : ]
102
+ var targets : [ SwiftBuildTarget ] = [ ]
97
103
98
104
/// The URIs for which the delegate has registered for change notifications,
99
105
/// mapped to the language the delegate specified when registering for change notifications.
@@ -129,6 +135,7 @@ public actor SwiftPMBuildSystem {
129
135
) async throws {
130
136
self . workspacePath = workspacePath
131
137
self . fileSystem = fileSystem
138
+ self . toolchainRegistry = toolchainRegistry
132
139
133
140
guard let packageRoot = findPackageDirectory ( containing: workspacePath, fileSystem) else {
134
141
throw Error . noManifest ( workspacePath: workspacePath)
@@ -259,6 +266,8 @@ extension SwiftPMBuildSystem {
259
266
/// with only some properties modified.
260
267
self . modulesGraph = modulesGraph
261
268
269
+ self . targets = try buildDescription. allTargetsInTopologicalOrder ( in: modulesGraph)
270
+
262
271
self . fileToTarget = [ AbsolutePath: SwiftBuildTarget] (
263
272
modulesGraph. allTargets. flatMap { target in
264
273
return target. sources. paths. compactMap {
@@ -314,43 +323,72 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
314
323
315
324
public var indexPrefixMappings : [ PathPrefixMapping ] { return [ ] }
316
325
317
- public func buildSettings( for uri: DocumentURI , language: Language ) throws -> FileBuildSettings ? {
318
- // SwiftPMBuildSystem doesn't respect the langue specified by the editor.
319
- return try buildSettings ( for: uri)
320
- }
321
-
322
- private func buildSettings( for uri: DocumentURI ) throws -> FileBuildSettings ? {
323
- guard let url = uri. fileURL else {
326
+ public func buildSettings(
327
+ for uri: DocumentURI ,
328
+ in configuredTarget: ConfiguredTarget ,
329
+ language: Language
330
+ ) throws -> FileBuildSettings ? {
331
+ guard let url = uri. fileURL, let path = try ? AbsolutePath ( validating: url. path) else {
324
332
// We can't determine build settings for non-file URIs.
325
333
return nil
326
334
}
327
- guard let path = try ? AbsolutePath ( validating: url. path) else {
328
- return nil
329
- }
330
335
331
- if let buildTarget = try buildTarget ( for: path) {
332
- return FileBuildSettings (
333
- compilerArguments: try buildTarget. compileArguments ( for: path. asURL) ,
334
- workingDirectory: workspacePath. pathString
335
- )
336
+ if configuredTarget. targetID == " " {
337
+ return try settings ( forPackageManifest: path)
336
338
}
337
339
338
- if path. basename == " Package.swift " {
339
- return try settings ( forPackageManifest: path)
340
+ let buildTargets = self . targets. filter ( { $0. name == configuredTarget. targetID } )
341
+ if buildTargets. count > 1 {
342
+ logger. error ( " Found multiple targets with name \( configuredTarget. targetID) . Picking the first one " )
343
+ }
344
+ guard let buildTarget = buildTargets. first else {
345
+ if buildTargets. isEmpty {
346
+ logger. error ( " Did not find target with name \( configuredTarget. targetID) " )
347
+ }
348
+ return nil
340
349
}
341
350
342
- if path. extension == " h " {
343
- return try settings ( forHeader: path)
351
+ if url. pathExtension == " h " , let substituteFile = buildTarget. sources. first {
352
+ return FileBuildSettings (
353
+ compilerArguments: try buildTarget. compileArguments ( for: substituteFile) ,
354
+ workingDirectory: workspacePath. pathString
355
+ ) . patching ( newFile: try resolveSymlinks ( path) . pathString, originalFile: substituteFile. absoluteString)
344
356
}
345
357
346
- return nil
358
+ return FileBuildSettings (
359
+ compilerArguments: try buildTarget. compileArguments ( for: url) ,
360
+ workingDirectory: workspacePath. pathString
361
+ )
347
362
}
348
363
349
364
public func defaultLanguage( for document: DocumentURI ) async -> Language ? {
350
365
// TODO (indexing): Query The SwiftPM build system for the document's language
351
366
return nil
352
367
}
353
368
369
+ public func configuredTargets( for uri: DocumentURI ) -> [ ConfiguredTarget ] {
370
+ guard let url = uri. fileURL, let path = try ? AbsolutePath ( validating: url. path) else {
371
+ // We can't determine targets for non-file URIs.
372
+ return [ ]
373
+ }
374
+
375
+ if let target = try ? buildTarget ( for: path) {
376
+ return [ ConfiguredTarget ( targetID: target. name, runDestinationID: " dummy " ) ]
377
+ }
378
+
379
+ if path. basename == " Package.swift " {
380
+ // We use an empty target name to represent the package manifest since an empty target name is not valid for any
381
+ // user-defined target.
382
+ return [ ConfiguredTarget ( targetID: " " , runDestinationID: " dummy " ) ]
383
+ }
384
+
385
+ if url. pathExtension == " h " , let target = try ? target ( forHeader: path) {
386
+ return [ target]
387
+ }
388
+
389
+ return [ ]
390
+ }
391
+
354
392
public func registerForChangeNotifications( for uri: DocumentURI ) async {
355
393
self . watchedFiles. insert ( uri)
356
394
}
@@ -437,10 +475,10 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
437
475
}
438
476
439
477
public func fileHandlingCapability( for uri: DocumentURI ) -> FileHandlingCapability {
440
- if ( try ? buildSettings ( for: uri) ) != nil {
441
- return . handled
478
+ if configuredTargets ( for: uri) . isEmpty {
479
+ return . unhandled
442
480
}
443
- return . unhandled
481
+ return . handled
444
482
}
445
483
446
484
public func sourceFiles( ) -> [ SourceFileInfo ] {
@@ -485,25 +523,13 @@ extension SwiftPMBuildSystem {
485
523
return canonicalPath == path ? nil : impl ( canonicalPath)
486
524
}
487
525
488
- /// Retrieve settings for a given header file.
489
- ///
490
- /// This finds the target the header belongs to based on its location in the file system, retrieves the build settings
491
- /// for any file within that target and generates compiler arguments by replacing that picked file with the header
492
- /// file.
493
- /// This is safe because all files within one target have the same build settings except for reference to the file
494
- /// itself, which we are replacing.
495
- private func settings( forHeader path: AbsolutePath ) throws -> FileBuildSettings ? {
496
- func impl( _ path: AbsolutePath ) throws -> FileBuildSettings ? {
526
+ /// This finds the target the header belongs to based on its location in the file system.
527
+ private func target( forHeader path: AbsolutePath ) throws -> ConfiguredTarget ? {
528
+ func impl( _ path: AbsolutePath ) throws -> ConfiguredTarget ? {
497
529
var dir = path. parentDirectory
498
530
while !dir. isRoot {
499
531
if let buildTarget = sourceDirToTarget [ dir] {
500
- if let sourceFile = buildTarget. sources. first {
501
- return FileBuildSettings (
502
- compilerArguments: try buildTarget. compileArguments ( for: sourceFile) ,
503
- workingDirectory: workspacePath. pathString
504
- ) . patching ( newFile: path. pathString, originalFile: sourceFile. absoluteString)
505
- }
506
- return nil
532
+ return ConfiguredTarget ( targetID: buildTarget. name, runDestinationID: " dummy " )
507
533
}
508
534
dir = dir. parentDirectory
509
535
}
0 commit comments