From 5e31b0560af6ac1d724b8194dc4e24aefbb6a791 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Mon, 2 Jun 2025 15:06:37 -0400 Subject: [PATCH 1/4] Enable contributed test plugin test case --- Tests/FunctionalTests/PluginTests.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Tests/FunctionalTests/PluginTests.swift b/Tests/FunctionalTests/PluginTests.swift index 6eb296f7149..10e8ebe0792 100644 --- a/Tests/FunctionalTests/PluginTests.swift +++ b/Tests/FunctionalTests/PluginTests.swift @@ -204,15 +204,12 @@ final class PluginTests: XCTestCase { XCTAssert(stdout.contains("Build of product 'MyLocalTool' complete!"), "stdout:\n\(stdout)") } -/* -FIXME: Determine the cause of the compile error. #if os(macOS) // See https://github.com/swiftlang/swift-package-manager/issues/8416 for errors running build tools on Linux try await fixture(name: "Miscellaneous/Plugins") { fixturePath in let (stdout, _) = try await executeSwiftBuild(fixturePath.appending("ContrivedTestPlugin"), configuration: .Debug, extraArgs: ["--build-system", "swiftbuild", "--product", "MyLocalTool", "--disable-sandbox"]) XCTAssert(stdout.contains("Build complete!"), "stdout:\n\(stdout)") } #endif -*/ } func testPluginScriptSandbox() async throws { From 824a23cf70aa835e42bb3bab4aade7960797d609 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 3 Jun 2025 11:08:18 -0400 Subject: [PATCH 2/4] Add multiple plugin invocation results to a target if there are multiple --- Sources/SwiftBuildSupport/PIFBuilder.swift | 8 ++- .../SwiftBuildSupport/PackagePIFBuilder.swift | 4 +- .../PackagePIFProjectBuilder.swift | 54 +++++++++++-------- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/Sources/SwiftBuildSupport/PIFBuilder.swift b/Sources/SwiftBuildSupport/PIFBuilder.swift index 3250a1a76b1..1274f17d129 100644 --- a/Sources/SwiftBuildSupport/PIFBuilder.swift +++ b/Sources/SwiftBuildSupport/PIFBuilder.swift @@ -257,7 +257,7 @@ public final class PIFBuilder { var packagesAndProjects: [(ResolvedPackage, ProjectModel.Project)] = [] for package in sortedPackages { - var buildToolPluginResultsByTargetName: [String: PackagePIFBuilder.BuildToolPluginInvocationResult] = [:] + var buildToolPluginResultsByTargetName: [String: [PackagePIFBuilder.BuildToolPluginInvocationResult]] = [:] for module in package.modules { // Apply each build tool plugin used by the target in order, @@ -388,7 +388,11 @@ public final class PIFBuilder { // Add a BuildToolPluginInvocationResult to the mapping. buildToolPluginResults.append(result2) - buildToolPluginResultsByTargetName[module.name] = result2 + if var existingResults = buildToolPluginResultsByTargetName[module.name] { + existingResults.append(result2) + } else { + buildToolPluginResultsByTargetName[module.name] = [result2] + } } } diff --git a/Sources/SwiftBuildSupport/PackagePIFBuilder.swift b/Sources/SwiftBuildSupport/PackagePIFBuilder.swift index a4769ca3140..914f4d6167c 100644 --- a/Sources/SwiftBuildSupport/PackagePIFBuilder.swift +++ b/Sources/SwiftBuildSupport/PackagePIFBuilder.swift @@ -159,7 +159,7 @@ public final class PackagePIFBuilder { } /// Records the results of applying build tool plugins to modules in the package. - let buildToolPluginResultsByTargetName: [String: PackagePIFBuilder.BuildToolPluginInvocationResult] + let buildToolPluginResultsByTargetName: [String: [PackagePIFBuilder.BuildToolPluginInvocationResult]] /// Whether to create dynamic libraries for dynamic products. /// @@ -192,7 +192,7 @@ public final class PackagePIFBuilder { resolvedPackage: ResolvedPackage, packageManifest: PackageModel.Manifest, delegate: PackagePIFBuilder.BuildDelegate, - buildToolPluginResultsByTargetName: [String: BuildToolPluginInvocationResult], + buildToolPluginResultsByTargetName: [String: [BuildToolPluginInvocationResult]], createDylibForDynamicProducts: Bool = false, packageDisplayVersion: String?, fileSystem: FileSystem, diff --git a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder.swift b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder.swift index 2239072df56..a92797d6808 100644 --- a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder.swift +++ b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder.swift @@ -380,28 +380,36 @@ struct PackagePIFProjectBuilder { targetKeyPath: WritableKeyPath, addBuildToolPluginCommands: Bool ) -> (sourceFilePaths: [AbsolutePath], resourceFilePaths: [String]) { - guard let pluginResult = pifBuilder.buildToolPluginResultsByTargetName[module.name] else { + guard let pluginResults = pifBuilder.buildToolPluginResultsByTargetName[module.name] else { // We found no results for the target. return (sourceFilePaths: [], resourceFilePaths: []) } - // Process the results of applying any build tool plugins on the target. - // If we've been asked to add build tool commands for the result, we do so now. - if addBuildToolPluginCommands { - for command in pluginResult.buildCommands { - self.addBuildToolCommand(command, to: targetKeyPath) + var sourceFilePaths: [AbsolutePath] = [] + var resourceFilePaths: [AbsolutePath] = [] + + for pluginResult in pluginResults { + // Process the results of applying any build tool plugins on the target. + // If we've been asked to add build tool commands for the result, we do so now. + if addBuildToolPluginCommands { + for command in pluginResult.buildCommands { + self.addBuildToolCommand(command, to: targetKeyPath) + } } - } - // Process all the paths of derived output paths using the same rules as for source. - let result = self.process( - pluginGeneratedFilePaths: pluginResult.allDerivedOutputPaths, - forModule: module, - toolsVersion: self.package.manifest.toolsVersion - ) + // Process all the paths of derived output paths using the same rules as for source. + let result = self.process( + pluginGeneratedFilePaths: pluginResult.allDerivedOutputPaths, + forModule: module, + toolsVersion: self.package.manifest.toolsVersion + ) + + sourceFilePaths.append(contentsOf: result.sourceFilePaths) + resourceFilePaths.append(contentsOf: result.resourceFilePaths.map(\.path)) + } return ( - sourceFilePaths: result.sourceFilePaths, - resourceFilePaths: result.resourceFilePaths.map(\.path.pathString) + sourceFilePaths: sourceFilePaths, + resourceFilePaths: resourceFilePaths.map(\.pathString) ) } @@ -414,17 +422,19 @@ struct PackagePIFProjectBuilder { sourceFilePaths: [AbsolutePath], resourceFilePaths: [String] ) { - guard let pluginResult = pifBuilder.buildToolPluginResultsByTargetName[module.name] else { + guard let pluginResults = pifBuilder.buildToolPluginResultsByTargetName[module.name] else { return } - for command in pluginResult.buildCommands { - let producesResources = Set(command.outputPaths).intersection(resourceFilePaths).hasContent + for pluginResult in pluginResults { + for command in pluginResult.buildCommands { + let producesResources = Set(command.outputPaths).intersection(resourceFilePaths).hasContent - if producesResources { - self.addBuildToolCommand(command, to: resourceBundleTargetKeyPath) - } else { - self.addBuildToolCommand(command, to: sourceModuleTargetKeyPath) + if producesResources { + self.addBuildToolCommand(command, to: resourceBundleTargetKeyPath) + } else { + self.addBuildToolCommand(command, to: sourceModuleTargetKeyPath) + } } } } From 3fed75c3bcc361ecccee228b06e1673cca66e28d Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 3 Jun 2025 11:29:14 -0400 Subject: [PATCH 3/4] Enable the dependent plugins test case --- Tests/FunctionalTests/PluginTests.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Tests/FunctionalTests/PluginTests.swift b/Tests/FunctionalTests/PluginTests.swift index 10e8ebe0792..35f7e5b170b 100644 --- a/Tests/FunctionalTests/PluginTests.swift +++ b/Tests/FunctionalTests/PluginTests.swift @@ -1332,5 +1332,12 @@ final class PluginTests: XCTestCase { let (stdout, _) = try await executeSwiftBuild(fixturePath) XCTAssert(stdout.contains("Build complete!"), "stdout:\n\(stdout)") } + +#if os(macOS) // See https://github.com/swiftlang/swift-package-manager/issues/8416 for errors running build tools on Linux + try await fixture(name: "Miscellaneous/Plugins/DependentPlugins") { fixturePath in + let (stdout, _) = try await executeSwiftBuild(fixturePath, extraArgs: ["--build-system", "swiftbuild"]) + XCTAssert(stdout.contains("Build complete!"), "stdout:\n\(stdout)") + } +#endif } } From 4efbd7e029c75e5e848a217d34242782baed9b9d Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 3 Jun 2025 15:46:07 -0400 Subject: [PATCH 4/4] Provide a compatible constructor for build tool plugin results by target --- .../SwiftBuildSupport/PackagePIFBuilder.swift | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Sources/SwiftBuildSupport/PackagePIFBuilder.swift b/Sources/SwiftBuildSupport/PackagePIFBuilder.swift index 914f4d6167c..27ca56e19e4 100644 --- a/Sources/SwiftBuildSupport/PackagePIFBuilder.swift +++ b/Sources/SwiftBuildSupport/PackagePIFBuilder.swift @@ -209,6 +209,28 @@ public final class PackagePIFBuilder { self.observabilityScope = observabilityScope } + public init( + modulesGraph: ModulesGraph, + resolvedPackage: ResolvedPackage, + packageManifest: PackageModel.Manifest, + delegate: PackagePIFBuilder.BuildDelegate, + buildToolPluginResultsByTargetName: [String: BuildToolPluginInvocationResult], + createDylibForDynamicProducts: Bool = false, + packageDisplayVersion: String?, + fileSystem: FileSystem, + observabilityScope: ObservabilityScope + ) { + self.package = resolvedPackage + self.packageManifest = packageManifest + self.modulesGraph = modulesGraph + self.delegate = delegate + self.buildToolPluginResultsByTargetName = buildToolPluginResultsByTargetName.mapValues { [$0] } + self.createDylibForDynamicProducts = createDylibForDynamicProducts + self.packageDisplayVersion = packageDisplayVersion + self.fileSystem = fileSystem + self.observabilityScope = observabilityScope + } + /// Build an empty PIF project. public func buildEmptyPIF() { self._pifProject = PackagePIFBuilder.buildEmptyPIF(package: self.package.underlying)