diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index ef354e81f00..8da505c9567 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -394,6 +394,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS let prebuildCommandResults: [ResolvedTarget: [PrebuildCommandResult]] // Invoke any build tool plugins in the graph to generate prebuild commands and build commands. if let pluginConfiguration = self.pluginConfiguration { + let buildOperationForPluginDependencies = try BuildOperation(buildParameters: self.buildParameters.withDestination(self.buildParameters.hostTriple), cacheBuildManifest: false, packageGraphLoader: { return graph }, additionalFileRules: self.additionalFileRules, pkgConfigDirectories: self.pkgConfigDirectories, outputStream: self.outputStream, logLevel: self.logLevel, fileSystem: self.fileSystem, observabilityScope: self.observabilityScope) buildToolPluginInvocationResults = try graph.invokeBuildToolPlugins( outputDir: pluginConfiguration.workDirectory.appending(component: "outputs"), builtToolsDir: self.buildParameters.buildPath, @@ -403,7 +404,14 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS pluginScriptRunner: pluginConfiguration.scriptRunner, observabilityScope: self.observabilityScope, fileSystem: self.fileSystem - ) + ) { name, path in + try buildOperationForPluginDependencies.build(subset: .product(name)) + if let builtTool = try buildOperationForPluginDependencies.buildPlan.buildProducts.first(where: { $0.product.name == name}) { + return builtTool.binaryPath + } else { + return nil + } + } // Surface any diagnostics from build tool plugins. diff --git a/Sources/SPMBuildCore/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters.swift index 2c0774c4c49..25e51297abc 100644 --- a/Sources/SPMBuildCore/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters.swift @@ -293,6 +293,50 @@ public struct BuildParameters: Encodable { self.verboseOutput = verboseOutput } + public func withDestination(_ destinationTriple: Triple) throws -> BuildParameters { + let forceTestDiscovery: Bool + let testEntryPointPath: AbsolutePath? + switch self.testProductStyle { + case .entryPointExecutable(let explicitlyEnabledDiscovery, let explicitlySpecifiedPath): + forceTestDiscovery = explicitlyEnabledDiscovery + testEntryPointPath = explicitlySpecifiedPath + case .loadableBundle: + forceTestDiscovery = false + testEntryPointPath = nil + } + + return .init( + dataPath: self.dataPath.parentDirectory.appending(components: ["plugins", "tools"]), + configuration: self.configuration, + toolchain: try UserToolchain(destination: Destination.hostDestination()), + hostTriple: self.hostTriple, + destinationTriple: destinationTriple, + flags: BuildFlags(), + pkgConfigDirectories: self.pkgConfigDirectories, + architectures: nil, + workers: self.workers, + shouldLinkStaticSwiftStdlib: self.shouldLinkStaticSwiftStdlib, + shouldEnableManifestCaching: self.shouldEnableManifestCaching, + canRenameEntrypointFunctionName: self.canRenameEntrypointFunctionName, + shouldCreateDylibForDynamicProducts: self.shouldCreateDylibForDynamicProducts, + sanitizers: self.sanitizers, + enableCodeCoverage: self.enableCodeCoverage, + indexStoreMode: self.indexStoreMode, + enableParseableModuleInterfaces: self.enableParseableModuleInterfaces, + emitSwiftModuleSeparately: self.emitSwiftModuleSeparately, + useIntegratedSwiftDriver: self.useIntegratedSwiftDriver, + useExplicitModuleBuild: self.useExplicitModuleBuild, + isXcodeBuildSystemEnabled: self.isXcodeBuildSystemEnabled, + enableTestability: self.enableTestability, + forceTestDiscovery: forceTestDiscovery, + testEntryPointPath: testEntryPointPath, + explicitTargetDependencyImportCheckingMode: self.explicitTargetDependencyImportCheckingMode, + linkerDeadStrip: self.linkerDeadStrip, + colorizedOutput: self.colorizedOutput, + verboseOutput: self.verboseOutput + ) + } + /// The path to the build directory (inside the data directory). public var buildPath: AbsolutePath { if isXcodeBuildSystemEnabled { diff --git a/Sources/SPMBuildCore/PluginInvocation.swift b/Sources/SPMBuildCore/PluginInvocation.swift index 4eab2515899..b9ebba13fb3 100644 --- a/Sources/SPMBuildCore/PluginInvocation.swift +++ b/Sources/SPMBuildCore/PluginInvocation.swift @@ -333,7 +333,8 @@ extension PackageGraph { pkgConfigDirectories: [AbsolutePath], pluginScriptRunner: PluginScriptRunner, observabilityScope: ObservabilityScope, - fileSystem: FileSystem + fileSystem: FileSystem, + builtToolHandler: (_ name: String, _ path: RelativePath) throws -> AbsolutePath? = { _, _ in return nil } ) throws -> [ResolvedTarget: [BuildToolPluginInvocationResult]] { var pluginResultsByTarget: [ResolvedTarget: [BuildToolPluginInvocationResult]] = [:] for target in self.reachableTargets.sorted(by: { $0.name < $1.name }) { @@ -373,7 +374,11 @@ extension PackageGraph { var builtToolNames: [String] = [] let accessibleTools = try pluginTarget.processAccessibleTools(packageGraph: self, fileSystem: fileSystem, environment: buildEnvironment, for: try pluginScriptRunner.hostTriple) { name, path in builtToolNames.append(name) - return builtToolsDir.appending(path) + if let result = try builtToolHandler(name, path) { + return result + } else { + return builtToolsDir.appending(path) + } } // Determine additional input dependencies for any plugin commands, based on any executables the plugin target depends on.