diff --git a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift index aae05f9b4..fe638b2dd 100644 --- a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift +++ b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift @@ -261,22 +261,11 @@ extension Driver { try commandLine.appendLast(.emitMacroExpansionFiles, from: &parsedOptions) } - if isFrontendArgSupported(.pluginPath) { - try commandLine.appendAll(.pluginPath, from: &parsedOptions) - - let defaultPluginPath = try toolchain.executableDir.parentDirectory - .appending(components: "lib", "swift", "host", "plugins") - commandLine.appendFlag(.pluginPath) - commandLine.appendPath(defaultPluginPath) - - let localPluginPath = try toolchain.executableDir.parentDirectory - .appending(components: "local", "lib", "swift", "host", "plugins") - commandLine.appendFlag(.pluginPath) - commandLine.appendPath(localPluginPath) - } - + // Emit user-provided plugin paths, in order. if isFrontendArgSupported(.externalPluginPath) { - try commandLine.appendAll(.externalPluginPath, from: &parsedOptions) + try commandLine.appendAll(.pluginPath, .externalPluginPath, .loadPluginLibrary, .loadPluginExecutable, from: &parsedOptions) + } else if isFrontendArgSupported(.pluginPath) { + try commandLine.appendAll(.pluginPath, .loadPluginLibrary, from: &parsedOptions) } if isFrontendArgSupported(.blockListFile) { @@ -394,6 +383,18 @@ extension Driver { inputs: &inputs, frontendTargetInfo: frontendTargetInfo, driver: &self) + + // Platform-agnostic options that need to happen after platform-specific ones. + if isFrontendArgSupported(.pluginPath) { + // Default paths for compiler plugins found within the toolchain + // (loaded as shared libraries). + let pluginPathRoot = VirtualPath.absolute(try toolchain.executableDir.parentDirectory) + commandLine.appendFlag(.pluginPath) + commandLine.appendPath(pluginPathRoot.pluginPath) + + commandLine.appendFlag(.pluginPath) + commandLine.appendPath(pluginPathRoot.localPluginPath) + } } mutating func addFrontendSupplementaryOutputArguments(commandLine: inout [Job.ArgTemplate], diff --git a/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift b/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift index 8b8bce051..7fc3b01a5 100644 --- a/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift @@ -421,6 +421,30 @@ public final class DarwinToolchain: Toolchain { commandLine.appendFlag(.clangTarget) commandLine.appendFlag(clangTargetTriple) } + + if driver.isFrontendArgSupported(.externalPluginPath) { + // Default paths for compiler plugins found within an SDK (accessed via + // that SDK's plugin server). + let sdkPathRoot = VirtualPath.lookup(sdkPath).appending(components: "usr") + commandLine.appendFlag(.externalPluginPath) + commandLine.appendFlag("\(sdkPathRoot.pluginPath.name)#\(sdkPathRoot.pluginServerPath.name.spm_shellEscaped())") + + commandLine.appendFlag(.externalPluginPath) + commandLine.appendFlag("\(sdkPathRoot.localPluginPath.name)#\(sdkPathRoot.pluginServerPath.name.spm_shellEscaped())") + + // Default paths for compiler plugins within the platform (accessed via that + // platform's plugin server). + let platformPathRoot = VirtualPath.lookup(sdkPath) + .parentDirectory + .parentDirectory + .parentDirectory + .appending(components: "Developer", "usr") + commandLine.appendFlag(.externalPluginPath) + commandLine.appendFlag("\(platformPathRoot.pluginPath.name)#\(platformPathRoot.pluginServerPath.name.spm_shellEscaped())") + + commandLine.appendFlag(.externalPluginPath) + commandLine.appendFlag("\(platformPathRoot.localPluginPath.name)#\(platformPathRoot.pluginServerPath.name.spm_shellEscaped())") + } } } @@ -441,3 +465,23 @@ private extension Version { return self.description } } + +extension VirtualPath { + // Given a virtual path pointing into a toolchain/SDK/platform, produce the + // path to `swift-plugin-server`. + fileprivate var pluginServerPath: VirtualPath { + self.appending(components: "bin", "swift-plugin-server") + } + + // Given a virtual path pointing into a toolchain/SDK/platform, produce the + // path to the plugins. + var pluginPath: VirtualPath { + self.appending(components: "lib", "swift", "host", "plugins") + } + + // Given a virtual path pointing into a toolchain/SDK/platform, produce the + // path to the plugins. + var localPluginPath: VirtualPath { + self.appending(component: "local").pluginPath + } +} diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index a1b9abfff..f0d26d3e4 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -6798,14 +6798,64 @@ final class SwiftDriverTests: XCTestCase { } func testPluginPaths() throws { - var driver = try Driver(args: ["swiftc", "-typecheck", "foo.swift"]) - guard driver.isFrontendArgSupported(.pluginPath) else { + let sdkRoot = testInputsPath.appending(component: "SDKChecks").appending(component: "iPhoneOS.sdk") + var driver = try Driver(args: ["swiftc", "-typecheck", "foo.swift", "-sdk", VirtualPath.absolute(sdkRoot).name, "-plugin-path", "PluginA", "-external-plugin-path", "PluginB#Bexe", "-load-plugin-library", "PluginB2", "-plugin-path", "PluginC"]) + guard driver.isFrontendArgSupported(.pluginPath) && driver.isFrontendArgSupported(.externalPluginPath) else { return } let jobs = try driver.planBuild().removingAutolinkExtractJobs() XCTAssertEqual(jobs.count, 1) let job = jobs.first! + + // Check that the we have the plugin paths we expect, in the order we expect. + let pluginAIndex = job.commandLine.firstIndex(of: .path(VirtualPath.relative(.init("PluginA")))) + XCTAssertNotNil(pluginAIndex) + + let pluginBIndex = job.commandLine.firstIndex(of: .path(VirtualPath.relative(.init("PluginB#Bexe")))) + XCTAssertNotNil(pluginBIndex) + XCTAssertLessThan(pluginAIndex!, pluginBIndex!) + + let pluginB2Index = job.commandLine.firstIndex(of: .path(VirtualPath.relative(.init("PluginB2")))) + XCTAssertNotNil(pluginB2Index) + XCTAssertLessThan(pluginBIndex!, pluginB2Index!) + + let pluginCIndex = job.commandLine.firstIndex(of: .path(VirtualPath.relative(.init("PluginC")))) + XCTAssertNotNil(pluginCIndex) + XCTAssertLessThan(pluginB2Index!, pluginCIndex!) + + #if os(macOS) + XCTAssertTrue(job.commandLine.contains(.flag("-external-plugin-path"))) + let sdkServerPath = sdkRoot.appending(components: "usr", "bin", "swift-plugin-server").pathString + let sdkPluginPath = sdkRoot.appending(components: "usr", "lib", "swift", "host", "plugins").pathString + + let sdkPluginPathIndex = job.commandLine.firstIndex(of: .flag("\(sdkPluginPath)#\(sdkServerPath)")) + XCTAssertNotNil(sdkPluginPathIndex) + XCTAssertLessThan(pluginCIndex!, sdkPluginPathIndex!) + + let sdkLocalPluginPath = sdkRoot.appending(components: "usr", "local", "lib", "swift", "host", "plugins").pathString + let sdkLocalPluginPathIndex = job.commandLine.firstIndex(of: .flag("\(sdkLocalPluginPath)#\(sdkServerPath)")) + XCTAssertNotNil(sdkLocalPluginPathIndex) + XCTAssertLessThan(sdkPluginPathIndex!, sdkLocalPluginPathIndex!) + + let platformPath = sdkRoot.parentDirectory.parentDirectory.parentDirectory.appending(components: "Developer", "usr") + let platformServerPath = platformPath.appending(components: "bin", "swift-plugin-server").pathString + + let platformPluginPath = platformPath.appending(components: "lib", "swift", "host", "plugins") + let platformPluginPathIndex = job.commandLine.firstIndex(of: .flag("\(platformPluginPath)#\(platformServerPath)")) + XCTAssertNotNil(platformPluginPathIndex) + XCTAssertLessThan(sdkLocalPluginPathIndex!, platformPluginPathIndex!) + + let platformLocalPluginPath = platformPath.appending(components: "local", "lib", "swift", "host", "plugins") + let platformLocalPluginPathIndex = job.commandLine.firstIndex(of: .flag("\(platformLocalPluginPath)#\(platformServerPath)")) + XCTAssertNotNil(platformLocalPluginPathIndex) + XCTAssertLessThan(platformPluginPathIndex!, platformLocalPluginPathIndex!) + + let toolchainPluginPathIndex = job.commandLine.firstIndex(of: .path(.absolute(try driver.toolchain.executableDir.parentDirectory.appending(components: "lib", "swift", "host", "plugins")))) + XCTAssertNotNil(toolchainPluginPathIndex) + XCTAssertLessThan(platformLocalPluginPathIndex!, toolchainPluginPathIndex!) + #endif + XCTAssertTrue(job.commandLine.contains(.flag("-plugin-path"))) XCTAssertTrue(job.commandLine.contains(.path(.absolute(try driver.toolchain.executableDir.parentDirectory.appending(components: "lib", "swift", "host", "plugins"))))) XCTAssertTrue(job.commandLine.contains(.path(.absolute(try driver.toolchain.executableDir.parentDirectory.appending(components: "local", "lib", "swift", "host", "plugins")))))