Skip to content

Commit 72d5b34

Browse files
authored
rdar://109108066 (Derive '-external-plugin-path' compiler arguments in SwiftPM) (#6560)
This derives the required `-external-plugin-path` arguments when using an OSS toolchain with SwiftPM.
1 parent a5081d9 commit 72d5b34

File tree

5 files changed

+65
-2
lines changed

5 files changed

+65
-2
lines changed

Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,18 @@ public final class SwiftTargetBuildDescription {
392392
}
393393
#endif
394394

395+
// If we're using an OSS toolchain, add the required arguments bringing in the plugin server from the default toolchain if available.
396+
if self.buildParameters.toolchain.isSwiftDevelopmentToolchain, driverSupport.checkSupportedFrontendFlags(flags: ["-external-plugin-path"], toolchain: self.buildParameters.toolchain, fileSystem: self.fileSystem), let pluginServer = self.buildParameters.toolchain.swiftPluginServerPath {
397+
let toolchainUsrPath = pluginServer.parentDirectory.parentDirectory
398+
let pluginPathComponents = ["lib", "swift", "host", "plugins"]
399+
400+
let pluginPath = toolchainUsrPath.appending(components: pluginPathComponents)
401+
args += ["-Xfrontend", "-external-plugin-path", "-Xfrontend", "\(pluginPath)#\(pluginServer.pathString)"]
402+
403+
let localPluginPath = toolchainUsrPath.appending(components: ["local"] + pluginPathComponents)
404+
args += ["-Xfrontend", "-external-plugin-path", "-Xfrontend", "\(localPluginPath)#\(pluginServer.pathString)"]
405+
}
406+
395407
return args
396408
}
397409

Sources/PackageModel/Toolchain.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ public protocol Toolchain {
1919
/// Path of the `swiftc` compiler.
2020
var swiftCompilerPath: AbsolutePath { get }
2121

22+
/// Whether the used compiler is from a open source development toolchain.
23+
var isSwiftDevelopmentToolchain: Bool { get }
24+
25+
/// Path to the Swift plugin server utility.
26+
var swiftPluginServerPath: AbsolutePath? { get }
27+
2228
/// Path containing the macOS Swift stdlib.
2329
var macosSwiftStdlib: AbsolutePath { get throws }
2430

Sources/PackageModel/ToolchainConfiguration.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ public struct ToolchainConfiguration {
4242
/// This is optional for example on macOS w/o Xcode.
4343
public var xctestPath: AbsolutePath?
4444

45+
/// Path to the Swift plugin server utility.
46+
public var swiftPluginServerPath: AbsolutePath?
47+
4548
/// Creates the set of manifest resources associated with a `swiftc` executable.
4649
///
4750
/// - Parameters:
@@ -52,14 +55,16 @@ public struct ToolchainConfiguration {
5255
/// - swiftPMLibrariesRootPath: Custom path for SwiftPM libraries. Computed based on the compiler path by default.
5356
/// - sdkRootPath: Optional path to SDK root.
5457
/// - xctestPath: Optional path to XCTest.
58+
/// - swiftPluginServerPath: Optional path to the Swift plugin server executable.
5559
public init(
5660
librarianPath: AbsolutePath,
5761
swiftCompilerPath: AbsolutePath,
5862
swiftCompilerFlags: [String] = [],
5963
swiftCompilerEnvironment: EnvironmentVariables = .process(),
6064
swiftPMLibrariesLocation: SwiftPMLibrariesLocation? = nil,
6165
sdkRootPath: AbsolutePath? = nil,
62-
xctestPath: AbsolutePath? = nil
66+
xctestPath: AbsolutePath? = nil,
67+
swiftPluginServerPath: AbsolutePath? = nil
6368
) {
6469
let swiftPMLibrariesLocation = swiftPMLibrariesLocation ?? {
6570
return .init(swiftCompilerPath: swiftCompilerPath)
@@ -72,6 +77,7 @@ public struct ToolchainConfiguration {
7277
self.swiftPMLibrariesLocation = swiftPMLibrariesLocation
7378
self.sdkRootPath = sdkRootPath
7479
self.xctestPath = xctestPath
80+
self.swiftPluginServerPath = swiftPluginServerPath
7581
}
7682
}
7783

Sources/PackageModel/UserToolchain.swift

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ public final class UserToolchain: Toolchain {
6161

6262
private let environment: EnvironmentVariables
6363

64+
public let isSwiftDevelopmentToolchain: Bool
65+
6466
/// Returns the runtime library for the given sanitizer.
6567
public func runtimeLibrary(for sanitizer: Sanitizer) throws -> AbsolutePath {
6668
// FIXME: This is only for SwiftPM development time support. It is OK
@@ -453,6 +455,22 @@ public final class UserToolchain: Toolchain {
453455
self.swiftCompilerPath = swiftCompilers.compile
454456
self.architectures = destination.architectures
455457

458+
#if canImport(Darwin)
459+
let toolchainPlistPath = self.swiftCompilerPath.parentDirectory.parentDirectory.parentDirectory
460+
.appending(component: "Info.plist")
461+
if localFileSystem.exists(toolchainPlistPath), let toolchainPlist = try? NSDictionary(
462+
contentsOf: URL(fileURLWithPath: toolchainPlistPath.pathString),
463+
error: ()
464+
), let overrideBuildSettings = toolchainPlist["OverrideBuildSettings"] as? NSDictionary,
465+
let isSwiftDevelopmentToolchainStringValue = overrideBuildSettings["SWIFT_DEVELOPMENT_TOOLCHAIN"] as? String {
466+
self.isSwiftDevelopmentToolchain = isSwiftDevelopmentToolchainStringValue == "YES"
467+
} else {
468+
self.isSwiftDevelopmentToolchain = false
469+
}
470+
#else
471+
self.isSwiftDevelopmentToolchain = false
472+
#endif
473+
456474
// Use the triple from destination or compute the host triple using swiftc.
457475
var triple = try destination.targetTriple ?? Triple.getHostTriple(usingSwiftCompiler: swiftCompilers.compile)
458476

@@ -532,10 +550,13 @@ public final class UserToolchain: Toolchain {
532550
environment: environment
533551
)
534552

553+
let swiftPluginServerPath: AbsolutePath?
535554
let xctestPath: AbsolutePath?
536555
if case .custom(_, let useXcrun) = searchStrategy, !useXcrun {
556+
swiftPluginServerPath = nil
537557
xctestPath = nil
538558
} else {
559+
swiftPluginServerPath = try Self.derivePluginServerPath(triple: triple)
539560
xctestPath = try Self.deriveXCTestPath(
540561
destination: self.destination,
541562
triple: triple,
@@ -550,7 +571,8 @@ public final class UserToolchain: Toolchain {
550571
swiftCompilerEnvironment: environment,
551572
swiftPMLibrariesLocation: swiftPMLibrariesLocation,
552573
sdkRootPath: self.destination.pathsConfiguration.sdkRootPath,
553-
xctestPath: xctestPath
574+
xctestPath: xctestPath,
575+
swiftPluginServerPath: swiftPluginServerPath
554576
)
555577
}
556578

@@ -622,6 +644,17 @@ public final class UserToolchain: Toolchain {
622644
return .init(swiftCompilerPath: swiftCompilerPath)
623645
}
624646

647+
private static func derivePluginServerPath(triple: Triple) throws -> AbsolutePath? {
648+
if triple.isDarwin() {
649+
let xctestFindArgs = ["/usr/bin/xcrun", "--find", "swift-plugin-server"]
650+
if let path = try? TSCBasic.Process.checkNonZeroExit(arguments: xctestFindArgs, environment: [:])
651+
.spm_chomp() {
652+
return try AbsolutePath(validating: path)
653+
}
654+
}
655+
return .none
656+
}
657+
625658
// TODO: We should have some general utility to find tools.
626659
private static func deriveXCTestPath(
627660
destination: Destination,
@@ -744,4 +777,8 @@ public final class UserToolchain: Toolchain {
744777
public var xctestPath: AbsolutePath? {
745778
configuration.xctestPath
746779
}
780+
781+
public var swiftPluginServerPath: AbsolutePath? {
782+
configuration.swiftPluginServerPath
783+
}
747784
}

Tests/BuildTests/MockBuildTestHelper.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ struct MockToolchain: PackageModel.Toolchain {
2828
let librarianPath = AbsolutePath("/fake/path/to/ar")
2929
#endif
3030
let swiftCompilerPath = AbsolutePath("/fake/path/to/swiftc")
31+
let isSwiftDevelopmentToolchain = false
32+
let swiftPluginServerPath: AbsolutePath? = nil
3133
let extraFlags = PackageModel.BuildFlags()
3234

3335
func getClangCompiler() throws -> AbsolutePath {

0 commit comments

Comments
 (0)