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