@@ -22,6 +22,7 @@ import PackageModel
22
22
import SKCore
23
23
import SKSupport
24
24
import SourceControl
25
+ import SourceKitLSPAPI
25
26
import Workspace
26
27
27
28
import struct Basics. AbsolutePath
@@ -43,6 +44,12 @@ public enum ReloadPackageStatus {
43
44
case end
44
45
}
45
46
47
+ /// A build target in SwiftPM
48
+ public typealias SwiftBuildTarget = SourceKitLSPAPI . BuildTarget
49
+
50
+ /// A build target in `BuildServerProtocol`
51
+ public typealias BuildServerTarget = BuildServerProtocol . BuildTarget
52
+
46
53
/// Same as `toolchainRegistry.default`.
47
54
///
48
55
/// Needed to work around a compiler crash that prevents us from accessing `toolchainRegistry.default` in
@@ -83,8 +90,8 @@ public actor SwiftPMWorkspace {
83
90
public let buildParameters : BuildParameters
84
91
let fileSystem : FileSystem
85
92
86
- var fileToTarget : [ AbsolutePath : TargetBuildDescription ] = [ : ]
87
- var sourceDirToTarget : [ AbsolutePath : TargetBuildDescription ] = [ : ]
93
+ var fileToTarget : [ AbsolutePath : SwiftBuildTarget ] = [ : ]
94
+ var sourceDirToTarget : [ AbsolutePath : SwiftBuildTarget ] = [ : ]
88
95
89
96
/// The URIs for which the delegate has registered for change notifications,
90
97
/// mapped to the language the delegate specified when registering for change notifications.
@@ -215,19 +222,20 @@ extension SwiftPMWorkspace {
215
222
fileSystem: fileSystem,
216
223
observabilityScope: observabilitySystem. topScope
217
224
)
225
+ let buildDescription = BuildDescription ( buildPlan: plan)
218
226
219
227
/// Make sure to execute any throwing statements before setting any
220
228
/// properties because otherwise we might end up in an inconsistent state
221
229
/// with only some properties modified.
222
230
self . packageGraph = packageGraph
223
231
224
- self . fileToTarget = [ AbsolutePath: TargetBuildDescription ] (
232
+ self . fileToTarget = [ AbsolutePath: SwiftBuildTarget ] (
225
233
packageGraph. allTargets. flatMap { target in
226
234
return target. sources. paths. compactMap {
227
- guard let td = plan . targetMap [ target. id ] else {
235
+ guard let buildTarget = buildDescription . getBuildTarget ( for : target) else {
228
236
return nil
229
237
}
230
- return ( key: $0, value: td )
238
+ return ( key: $0, value: buildTarget )
231
239
}
232
240
} ,
233
241
uniquingKeysWith: { td, _ in
@@ -236,12 +244,12 @@ extension SwiftPMWorkspace {
236
244
}
237
245
)
238
246
239
- self . sourceDirToTarget = [ AbsolutePath: TargetBuildDescription ] (
240
- packageGraph. allTargets. compactMap { target in
241
- guard let td = plan . targetMap [ target. id ] else {
247
+ self . sourceDirToTarget = [ AbsolutePath: SwiftBuildTarget ] (
248
+ packageGraph. allTargets. compactMap { ( target) -> ( AbsolutePath , SwiftBuildTarget ) ? in
249
+ guard let buildTarget = buildDescription . getBuildTarget ( for : target) else {
242
250
return nil
243
251
}
244
- return ( key: target. sources. root, value: td )
252
+ return ( key: target. sources. root, value: buildTarget )
245
253
} ,
246
254
uniquingKeysWith: { td, _ in
247
255
// FIXME: is there a preferred target?
@@ -284,8 +292,11 @@ extension SwiftPMWorkspace: SKCore.BuildSystem {
284
292
return nil
285
293
}
286
294
287
- if let td = try targetDescription ( for: path) {
288
- return try settings ( for: path, language, td)
295
+ if let buildTarget = try buildTarget ( for: path) {
296
+ return FileBuildSettings (
297
+ compilerArguments: try buildTarget. compileArguments ( for: path. asURL) ,
298
+ workingDirectory: workspacePath. pathString
299
+ )
289
300
}
290
301
291
302
if path. basename == " Package.swift " {
@@ -310,7 +321,7 @@ extension SwiftPMWorkspace: SKCore.BuildSystem {
310
321
}
311
322
312
323
/// Returns the resolved target description for the given file, if one is known.
313
- private func targetDescription ( for file: AbsolutePath ) throws -> TargetBuildDescription ? {
324
+ private func buildTarget ( for file: AbsolutePath ) throws -> SwiftBuildTarget ? {
314
325
if let td = fileToTarget [ file] {
315
326
return td
316
327
}
@@ -359,7 +370,7 @@ extension SwiftPMWorkspace: SKCore.BuildSystem {
359
370
guard let fileUrl = uri. fileURL else {
360
371
return . unhandled
361
372
}
362
- if ( try ? targetDescription ( for: AbsolutePath ( validating: fileUrl. path) ) ) != nil {
373
+ if ( try ? buildTarget ( for: AbsolutePath ( validating: fileUrl. path) ) ) != nil {
363
374
return . handled
364
375
} else {
365
376
return . unhandled
@@ -371,24 +382,6 @@ extension SwiftPMWorkspace {
371
382
372
383
// MARK: Implementation details
373
384
374
- /// Retrieve settings for the given file, which is part of a known target build description.
375
- public func settings(
376
- for path: AbsolutePath ,
377
- _ language: Language ,
378
- _ td: TargetBuildDescription
379
- ) throws -> FileBuildSettings ? {
380
- switch ( td, language) {
381
- case ( . swift( let td) , . swift) :
382
- return try settings ( forSwiftFile: path, td)
383
- case ( . clang, . swift) :
384
- return nil
385
- case ( . clang( let td) , _) :
386
- return try settings ( forClangFile: path, language, td)
387
- default :
388
- return nil
389
- }
390
- }
391
-
392
385
/// Retrieve settings for a package manifest (Package.swift).
393
386
private func settings( forPackageManifest path: AbsolutePath ) throws -> FileBuildSettings ? {
394
387
func impl( _ path: AbsolutePath ) -> FileBuildSettings ? {
@@ -408,12 +401,24 @@ extension SwiftPMWorkspace {
408
401
}
409
402
410
403
/// Retrieve settings for a given header file.
404
+ ///
405
+ /// This finds the target the header belongs to based on its location in the file system, retrieves the build settings
406
+ /// for any file within that target and generates compiler arguments by replacing that picked file with the header
407
+ /// file.
408
+ /// This is safe because all files within one target have the same build settings except for reference to the file
409
+ /// itself, which we are replacing.
411
410
private func settings( forHeader path: AbsolutePath , _ language: Language ) throws -> FileBuildSettings ? {
412
411
func impl( _ path: AbsolutePath ) throws -> FileBuildSettings ? {
413
412
var dir = path. parentDirectory
414
413
while !dir. isRoot {
415
- if let td = sourceDirToTarget [ dir] {
416
- return try settings ( for: path, language, td)
414
+ if let buildTarget = sourceDirToTarget [ dir] {
415
+ if let sourceFile = buildTarget. sources. first {
416
+ return FileBuildSettings (
417
+ compilerArguments: try buildTarget. compileArguments ( for: sourceFile) ,
418
+ workingDirectory: workspacePath. pathString
419
+ ) . patching ( newFile: path. pathString, originalFile: sourceFile. absoluteString)
420
+ }
421
+ return nil
417
422
}
418
423
dir = dir. parentDirectory
419
424
}
@@ -427,103 +432,6 @@ extension SwiftPMWorkspace {
427
432
let canonicalPath = try resolveSymlinks ( path)
428
433
return try canonicalPath == path ? nil : impl ( canonicalPath)
429
434
}
430
-
431
- /// Retrieve settings for the given swift file, which is part of a known target build description.
432
- public func settings(
433
- forSwiftFile path: AbsolutePath ,
434
- _ td: SwiftTargetBuildDescription
435
- ) throws -> FileBuildSettings {
436
- // FIXME: this is re-implementing llbuild's constructCommandLineArgs.
437
- var args : [ String ] = [
438
- " -module-name " ,
439
- td. target. c99name,
440
- " -incremental " ,
441
- " -emit-dependencies " ,
442
- " -emit-module " ,
443
- " -emit-module-path " ,
444
- buildPath. appending ( component: " \( td. target. c99name) .swiftmodule " ) . pathString,
445
- // -output-file-map <path>
446
- ]
447
- if td. target. type == . library || td. target. type == . test {
448
- args += [ " -parse-as-library " ]
449
- }
450
- args += [ " -c " ]
451
- args += td. sources. map { $0. pathString }
452
- args += [ " -I " , td. moduleOutputPath. parentDirectory. pathString]
453
- args += try td. compileArguments ( )
454
-
455
- return FileBuildSettings (
456
- compilerArguments: args,
457
- workingDirectory: workspacePath. pathString
458
- )
459
- }
460
-
461
- /// Retrieve settings for the given C-family language file, which is part of a known target build
462
- /// description.
463
- ///
464
- /// - Note: language must be a C-family language.
465
- public func settings(
466
- forClangFile path: AbsolutePath ,
467
- _ language: Language ,
468
- _ td: ClangTargetBuildDescription
469
- ) throws -> FileBuildSettings {
470
- // FIXME: this is re-implementing things from swiftpm's createClangCompileTarget
471
-
472
- var args = try td. basicArguments ( )
473
-
474
- let nativePath : AbsolutePath =
475
- try URL ( fileURLWithPath: path. pathString) . withUnsafeFileSystemRepresentation {
476
- try AbsolutePath ( validating: String ( cString: $0!) )
477
- }
478
- let compilePath = try td. compilePaths ( ) . first ( where: { $0. source == nativePath } )
479
- if let compilePath = compilePath {
480
- args += [
481
- " -MD " ,
482
- " -MT " ,
483
- " dependencies " ,
484
- " -MF " ,
485
- compilePath. deps. pathString,
486
- ]
487
- }
488
-
489
- switch language {
490
- case . c:
491
- if let std = td. clangTarget. cLanguageStandard {
492
- args += [ " -std= \( std) " ]
493
- }
494
- case . cpp:
495
- if let std = td. clangTarget. cxxLanguageStandard {
496
- args += [ " -std= \( std) " ]
497
- }
498
- default :
499
- break
500
- }
501
-
502
- if let compilePath = compilePath {
503
- args += [
504
- " -c " ,
505
- compilePath. source. pathString,
506
- " -o " ,
507
- compilePath. object. pathString,
508
- ]
509
- } else if path. extension == " h " {
510
- args += [ " -c " ]
511
- if let xflag = language. xflagHeader {
512
- args += [ " -x " , xflag]
513
- }
514
- args += [ path. pathString]
515
- } else {
516
- args += [
517
- " -c " ,
518
- path. pathString,
519
- ]
520
- }
521
-
522
- return FileBuildSettings (
523
- compilerArguments: args,
524
- workingDirectory: workspacePath. pathString
525
- )
526
- }
527
435
}
528
436
529
437
/// Find a Swift Package root directory that contains the given path, if any.
0 commit comments