Skip to content

Commit 69a0270

Browse files
committed
Get compiler arguments for files in the Plugins folder
This uses the new API in SwiftPM introduced by swiftlang/swift-package-manager#6763 to get compiler arguments for a target instead of stitching them together in sourcekit-lsp. Fixes swiftlang#664 rdar://102213837
1 parent ace48d0 commit 69a0270

File tree

2 files changed

+83
-63
lines changed

2 files changed

+83
-63
lines changed

Sources/SKSwiftPMWorkspace/SwiftPMWorkspace.swift

Lines changed: 36 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import PackageModel
2222
import SKCore
2323
import SKSupport
2424
import SourceControl
25+
import SwiftPM
2526
import Workspace
2627

2728
import struct Basics.AbsolutePath
@@ -43,6 +44,20 @@ public enum ReloadPackageStatus {
4344
case end
4445
}
4546

47+
/// A build target in SwiftPM
48+
public typealias SwiftBuildTarget = SwiftPM.BuildTarget
49+
50+
/// A build target in `BuildServerProtocol`
51+
public typealias BuildServerTarget = BuildServerProtocol.BuildTarget
52+
53+
extension SwiftBuildTarget {
54+
func fixedCompileArguments() throws -> [String] {
55+
var args = try self.compileArguments()
56+
args += self.sources.map { $0.path }
57+
return args
58+
}
59+
}
60+
4661
/// Swift Package Manager build system and workspace support.
4762
///
4863
/// This class implements the `BuildSystem` interface to provide the build settings for a Swift
@@ -75,8 +90,8 @@ public actor SwiftPMWorkspace {
7590
public let buildParameters: BuildParameters
7691
let fileSystem: FileSystem
7792

78-
var fileToTarget: [AbsolutePath: TargetBuildDescription] = [:]
79-
var sourceDirToTarget: [AbsolutePath: TargetBuildDescription] = [:]
93+
var fileToTarget: [AbsolutePath: SwiftBuildTarget] = [:]
94+
var sourceDirToTarget: [AbsolutePath: SwiftBuildTarget] = [:]
8095

8196
/// The URIs for which the delegate has registered for change notifications,
8297
/// mapped to the language the delegate specified when registering for change notifications.
@@ -213,13 +228,13 @@ extension SwiftPMWorkspace {
213228
/// with only some properties modified.
214229
self.packageGraph = packageGraph
215230

216-
self.fileToTarget = [AbsolutePath: TargetBuildDescription](
231+
self.fileToTarget = [AbsolutePath: SwiftBuildTarget](
217232
packageGraph.allTargets.flatMap { target in
218233
return target.sources.paths.compactMap {
219-
guard let td = plan.targetMap[target] else {
234+
guard let buildTarget = BuildDescription(buildPlan: plan).getBuildTarget(for: target) else {
220235
return nil
221236
}
222-
return (key: $0, value: td)
237+
return (key: $0, value: buildTarget)
223238
}
224239
},
225240
uniquingKeysWith: { td, _ in
@@ -228,12 +243,12 @@ extension SwiftPMWorkspace {
228243
}
229244
)
230245

231-
self.sourceDirToTarget = [AbsolutePath: TargetBuildDescription](
232-
packageGraph.allTargets.compactMap { target in
233-
guard let td = plan.targetMap[target] else {
246+
self.sourceDirToTarget = [AbsolutePath: SwiftBuildTarget](
247+
packageGraph.allTargets.compactMap { (target) -> (AbsolutePath, SwiftBuildTarget)? in
248+
guard let buildTarget = BuildDescription(buildPlan: plan).getBuildTarget(for: target) else {
234249
return nil
235250
}
236-
return (key: target.sources.root, value: td)
251+
return (key: target.sources.root, value: buildTarget)
237252
},
238253
uniquingKeysWith: { td, _ in
239254
// FIXME: is there a preferred target?
@@ -284,8 +299,11 @@ extension SwiftPMWorkspace: SKCore.BuildSystem {
284299
return nil
285300
}
286301

287-
if let td = try targetDescription(for: path) {
288-
return try settings(for: path, language, td)
302+
if let buildTarget = try buildTarget(for: path) {
303+
return FileBuildSettings(
304+
compilerArguments: try buildTarget.fixedCompileArguments(),
305+
workingDirectory: workspacePath.pathString
306+
)
289307
}
290308

291309
if path.basename == "Package.swift" {
@@ -310,7 +328,7 @@ extension SwiftPMWorkspace: SKCore.BuildSystem {
310328
}
311329

312330
/// Returns the resolved target description for the given file, if one is known.
313-
private func targetDescription(for file: AbsolutePath) throws -> TargetBuildDescription? {
331+
private func buildTarget(for file: AbsolutePath) throws -> SwiftBuildTarget? {
314332
if let td = fileToTarget[file] {
315333
return td
316334
}
@@ -359,7 +377,7 @@ extension SwiftPMWorkspace: SKCore.BuildSystem {
359377
guard let fileUrl = uri.fileURL else {
360378
return .unhandled
361379
}
362-
if (try? targetDescription(for: AbsolutePath(validating: fileUrl.path))) != nil {
380+
if (try? buildTarget(for: AbsolutePath(validating: fileUrl.path))) != nil {
363381
return .handled
364382
} else {
365383
return .unhandled
@@ -371,24 +389,6 @@ extension SwiftPMWorkspace {
371389

372390
// MARK: Implementation details
373391

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-
392392
/// Retrieve settings for a package manifest (Package.swift).
393393
private func settings(forPackageManifest path: AbsolutePath) throws -> FileBuildSettings? {
394394
func impl(_ path: AbsolutePath) -> FileBuildSettings? {
@@ -412,8 +412,11 @@ extension SwiftPMWorkspace {
412412
func impl(_ path: AbsolutePath) throws -> FileBuildSettings? {
413413
var dir = path.parentDirectory
414414
while !dir.isRoot {
415-
if let td = sourceDirToTarget[dir] {
416-
return try settings(for: path, language, td)
415+
if let buildTarget = sourceDirToTarget[dir] {
416+
return FileBuildSettings(
417+
compilerArguments: try buildTarget.fixedCompileArguments(),
418+
workingDirectory: workspacePath.pathString
419+
)
417420
}
418421
dir = dir.parentDirectory
419422
}
@@ -428,36 +431,6 @@ extension SwiftPMWorkspace {
428431
return try canonicalPath == path ? nil : impl(canonicalPath)
429432
}
430433

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", buildPath.pathString]
453-
args += try td.compileArguments()
454-
455-
return FileBuildSettings(
456-
compilerArguments: args,
457-
workingDirectory: workspacePath.pathString
458-
)
459-
}
460-
461434
/// Retrieve settings for the given C-family language file, which is part of a known target build
462435
/// description.
463436
///

Tests/SKSwiftPMWorkspaceTests/SwiftPMWorkspaceTests.swift

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,53 @@ final class SwiftPMWorkspaceTests: XCTestCase {
694694
assertEqual(await ws._packageRoot, try resolveSymlinks(tempDir.appending(component: "pkg")))
695695
}
696696
}
697+
698+
func testPluginArgs() async throws {
699+
// FIXME: should be possible to use InMemoryFileSystem.
700+
let fs = localFileSystem
701+
try await withTemporaryDirectory(removeTreeOnDeinit: true) { tempDir in
702+
try fs.createFiles(
703+
root: tempDir,
704+
files: [
705+
"pkg/Plugins/MyPlugin/a.swift": "",
706+
"pkg/Sources/lib/lib.swift": "",
707+
"pkg/Package.swift": """
708+
// swift-tools-version:5.7
709+
import PackageDescription
710+
let package = Package(
711+
name: "a",
712+
products: [],
713+
dependencies: [],
714+
targets: [
715+
.target(name: "lib"),
716+
.plugin(name: "MyPlugin", capability: .buildTool)
717+
]
718+
)
719+
""",
720+
]
721+
)
722+
let packageRoot = try resolveSymlinks(tempDir.appending(component: "pkg"))
723+
let tr = ToolchainRegistry.shared
724+
let ws = try await SwiftPMWorkspace(
725+
workspacePath: packageRoot,
726+
toolchainRegistry: tr,
727+
fileSystem: fs,
728+
buildSetup: SourceKitServer.Options.testDefault.buildSetup
729+
)
730+
731+
let aswift = packageRoot.appending(components: "Plugins", "MyPlugin", "a.swift")
732+
let hostTriple = await ws.buildParameters.targetTriple
733+
let build = buildPath(root: packageRoot, platform: hostTriple.platformBuildPathComponent)
734+
735+
assertEqual(await ws.buildPath, build)
736+
assertNotNil(await ws.indexStorePath)
737+
let arguments = try await ws._settings(for: aswift.asURI, .swift)!.compilerArguments
738+
739+
check("-sdk", arguments: arguments)
740+
check("-package-description-version", "5.7.0", arguments: arguments)
741+
check(aswift.pathString, arguments: arguments)
742+
}
743+
}
697744
}
698745

699746
private func checkNot(

0 commit comments

Comments
 (0)