Skip to content

Commit ff80c0a

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

File tree

5 files changed

+66
-2
lines changed

5 files changed

+66
-2
lines changed

Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift

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

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

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
@@ -43,6 +43,9 @@ public struct ToolchainConfiguration {
4343
/// This is optional for example on macOS w/o Xcode.
4444
public var xctestPath: AbsolutePath?
4545

46+
/// Path to the Swift plugin server utility.
47+
public var swiftPluginServerPath: AbsolutePath?
48+
4649
/// Creates the set of manifest resources associated with a `swiftc` executable.
4750
///
4851
/// - Parameters:
@@ -53,14 +56,16 @@ public struct ToolchainConfiguration {
5356
/// - swiftPMLibrariesRootPath: Custom path for SwiftPM libraries. Computed based on the compiler path by default.
5457
/// - sdkRootPath: Optional path to SDK root.
5558
/// - xctestPath: Optional path to XCTest.
59+
/// - swiftPluginServerPath: Optional path to the Swift plugin server executable.
5660
public init(
5761
librarianPath: AbsolutePath,
5862
swiftCompilerPath: AbsolutePath,
5963
swiftCompilerFlags: [String] = [],
6064
swiftCompilerEnvironment: EnvironmentVariables = .process(),
6165
swiftPMLibrariesLocation: SwiftPMLibrariesLocation? = nil,
6266
sdkRootPath: AbsolutePath? = nil,
63-
xctestPath: AbsolutePath? = nil
67+
xctestPath: AbsolutePath? = nil,
68+
swiftPluginServerPath: AbsolutePath? = nil
6469
) {
6570
let swiftPMLibrariesLocation = swiftPMLibrariesLocation ?? {
6671
return .init(swiftCompilerPath: swiftCompilerPath)
@@ -73,6 +78,7 @@ public struct ToolchainConfiguration {
7378
self.swiftPMLibrariesLocation = swiftPMLibrariesLocation
7479
self.sdkRootPath = sdkRootPath
7580
self.xctestPath = xctestPath
81+
self.swiftPluginServerPath = swiftPluginServerPath
7682
}
7783
}
7884

Sources/PackageModel/UserToolchain.swift

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

6161
private let environment: EnvironmentVariables
6262

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

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

@@ -535,10 +553,13 @@ public final class UserToolchain: Toolchain {
535553
environment: environment
536554
)
537555

556+
let swiftPluginServerPath: AbsolutePath?
538557
let xctestPath: AbsolutePath?
539558
if case .custom(_, let useXcrun) = searchStrategy, !useXcrun {
559+
swiftPluginServerPath = nil
540560
xctestPath = nil
541561
} else {
562+
swiftPluginServerPath = try Self.derivePluginServerPath(triple: triple)
542563
xctestPath = try Self.deriveXCTestPath(
543564
destination: self.destination,
544565
triple: triple,
@@ -553,7 +574,8 @@ public final class UserToolchain: Toolchain {
553574
swiftCompilerEnvironment: environment,
554575
swiftPMLibrariesLocation: swiftPMLibrariesLocation,
555576
sdkRootPath: self.destination.pathsConfiguration.sdkRootPath,
556-
xctestPath: xctestPath
577+
xctestPath: xctestPath,
578+
swiftPluginServerPath: swiftPluginServerPath
557579
)
558580
}
559581

@@ -625,6 +647,17 @@ public final class UserToolchain: Toolchain {
625647
return .init(swiftCompilerPath: swiftCompilerPath)
626648
}
627649

650+
private static func derivePluginServerPath(triple: Triple) throws -> AbsolutePath? {
651+
if triple.isDarwin() {
652+
let xctestFindArgs = ["/usr/bin/xcrun", "--find", "swift-plugin-server"]
653+
if let path = try? TSCBasic.Process.checkNonZeroExit(arguments: xctestFindArgs, environment: [:])
654+
.spm_chomp() {
655+
return try AbsolutePath(validating: path)
656+
}
657+
}
658+
return .none
659+
}
660+
628661
// TODO: We should have some general utility to find tools.
629662
private static func deriveXCTestPath(
630663
destination: Destination,
@@ -747,4 +780,8 @@ public final class UserToolchain: Toolchain {
747780
public var xctestPath: AbsolutePath? {
748781
configuration.xctestPath
749782
}
783+
784+
public var swiftPluginServerPath: AbsolutePath? {
785+
configuration.swiftPluginServerPath
786+
}
750787
}

Tests/BuildTests/MockBuildTestHelper.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,15 @@ struct MockToolchain: PackageModel.Toolchain {
2929
let librarianPath = AbsolutePath("/fake/path/to/ar")
3030
#endif
3131
let swiftCompilerPath = AbsolutePath("/fake/path/to/swiftc")
32+
let isSwiftDevelopmentToolchain = false
33+
let swiftPluginServerPath: AbsolutePath? = nil
3234

3335
#if os(macOS)
3436
let extraFlags = BuildFlags(cxxCompilerFlags: ["-lc++"])
3537
#else
3638
let extraFlags = BuildFlags(cxxCompilerFlags: ["-lstdc++"])
3739
#endif
40+
3841
func getClangCompiler() throws -> AbsolutePath {
3942
return AbsolutePath(path: "/fake/path/to/clang")
4043
}

0 commit comments

Comments
 (0)