From 14cd7abcf217517bb8111481d5f5d67071b46204 Mon Sep 17 00:00:00 2001 From: Boris Buegling Date: Thu, 6 Nov 2025 14:01:37 -0800 Subject: [PATCH] Add an `--allTargets` option to the console build command Since the console command doesn't allow a fine grained selection of targets but relies on names only, it is currently sometimes not possible to build certain targets at all using that. As a simple mitigation, add an option that will simply build all targets (minus dynamic variants). --- Sources/SWBBuildService/Messages.swift | 2 +- Sources/SWBProtocol/Message.swift | 4 ++- .../SWBServiceConsoleBuildCommand.swift | 26 ++++++++++++++++--- Sources/SwiftBuild/SWBWorkspaceInfo.swift | 3 ++- .../MessageSerializationTests.swift | 2 +- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/Sources/SWBBuildService/Messages.swift b/Sources/SWBBuildService/Messages.swift index d014b03c..e22dc0a8 100644 --- a/Sources/SWBBuildService/Messages.swift +++ b/Sources/SWBBuildService/Messages.swift @@ -465,7 +465,7 @@ private struct WorkspaceInfoMsg: MessageHandler { return WorkspaceInfoResponse(sessionHandle: session.UID, workspaceInfo: .init(targetInfos: workspaceContext.workspace.projects.flatMap { project in return project.targets.map { target in - return .init(guid: target.guid, targetName: target.name, projectName: project.name) + return .init(guid: target.guid, targetName: target.name, projectName: project.name, dynamicTargetVariantGuid: target.dynamicTargetVariantGuid) } })) } diff --git a/Sources/SWBProtocol/Message.swift b/Sources/SWBProtocol/Message.swift index 8299c71c..71df549f 100644 --- a/Sources/SWBProtocol/Message.swift +++ b/Sources/SWBProtocol/Message.swift @@ -1049,11 +1049,13 @@ public struct WorkspaceInfoResponse: Message, Equatable { public let guid: String public let targetName: String public let projectName: String + public let dynamicTargetVariantGuid: String? - public init(guid: String, targetName: String, projectName: String) { + public init(guid: String, targetName: String, projectName: String, dynamicTargetVariantGuid: String?) { self.guid = guid self.targetName = targetName self.projectName = projectName + self.dynamicTargetVariantGuid = dynamicTargetVariantGuid } } diff --git a/Sources/SwiftBuild/ConsoleCommands/SWBServiceConsoleBuildCommand.swift b/Sources/SwiftBuild/ConsoleCommands/SWBServiceConsoleBuildCommand.swift index 682c2332..e3f50afa 100644 --- a/Sources/SwiftBuild/ConsoleCommands/SWBServiceConsoleBuildCommand.swift +++ b/Sources/SwiftBuild/ConsoleCommands/SWBServiceConsoleBuildCommand.swift @@ -57,6 +57,7 @@ class SWBServiceConsoleBuildCommand: SWBServiceConsoleCommand { var buildRequestFile: Path? = nil var buildParametersFile: Path? = nil var derivedDataPath: Path? = nil + var buildAllTargets: Bool = false var iterator = invocation.commandLine.makeIterator() _ = iterator.next() @@ -69,6 +70,9 @@ class SWBServiceConsoleBuildCommand: SWBServiceConsoleCommand { actionName = name + case "--allTargets": + buildAllTargets = true + case "--target": guard let name = iterator.next() else { return .failure(.invalidCommandError(description: "error: missing argument for \(arg)")) @@ -120,6 +124,10 @@ class SWBServiceConsoleBuildCommand: SWBServiceConsoleCommand { let containerPath = Path(positionalArgs[0]) + if !configuredTargetNames.isEmpty, buildAllTargets { + return .failure(.invalidCommandError(description: "error: pass either --allTargets or --target")) + } + return await invocation.console.service.withSession(sessionName: containerPath.str) { session, diagnostics in let baseDirectory: AbsolutePath do { @@ -165,7 +173,7 @@ class SWBServiceConsoleBuildCommand: SWBServiceConsoleCommand { let configuredTargets: [SWBConfiguredTarget] do { let workspaceInfo = try await session.workspaceInfo() - configuredTargets = try workspaceInfo.configuredTargets(targetNames: configuredTargetNames, parameters: parameters) + configuredTargets = try workspaceInfo.configuredTargets(targetNames: configuredTargetNames, parameters: parameters, buildAllTargets: buildAllTargets) } catch { return .failure(.failedCommandError(description: error.localizedDescription)) } @@ -303,11 +311,11 @@ class SWBServiceConsolePrepareForIndexCommand: SWBServiceConsoleCommand { var prepareTargets: [String]? do { let workspaceInfo = try await session.workspaceInfo() - configuredTargets = try workspaceInfo.configuredTargets(targetNames: configuredTargetNames, parameters: parameters) + configuredTargets = try workspaceInfo.configuredTargets(targetNames: configuredTargetNames, parameters: parameters, buildAllTargets: false) if !prepareTargetNames.isEmpty { do { - prepareTargets = try workspaceInfo.configuredTargets(targetNames: configuredTargetNames, parameters: parameters).map(\.guid) + prepareTargets = try workspaceInfo.configuredTargets(targetNames: configuredTargetNames, parameters: parameters, buildAllTargets: false).map(\.guid) } catch { return .failure(.failedCommandError(description: error.localizedDescription)) } @@ -375,7 +383,17 @@ fileprivate func generateDependencyInfo(startInfo: SwiftBuildMessage.BuildStarte } extension SWBWorkspaceInfo { - func configuredTargets(targetNames: [String], parameters: SWBBuildParameters) throws -> [SWBConfiguredTarget] { + func configuredTargets(targetNames: [String], parameters: SWBBuildParameters, buildAllTargets: Bool) throws -> [SWBConfiguredTarget] { + if buildAllTargets { + // Filter all dynamic targets to avoid building the same content multiple times. + let dynamicTargetVariantGuids = targetInfos.compactMap { $0.dynamicTargetVariantGuid } + let targets = targetInfos.filter { + !dynamicTargetVariantGuids.contains($0.guid) + }.map { + SWBConfiguredTarget(guid: $0.guid, parameters: parameters) + } + return targets + } return try targetNames.map { targetName in let infos = targetInfos.filter { $0.targetName == targetName } switch infos.count { diff --git a/Sources/SwiftBuild/SWBWorkspaceInfo.swift b/Sources/SwiftBuild/SWBWorkspaceInfo.swift index 8eb4fc11..3e5e01b4 100644 --- a/Sources/SwiftBuild/SWBWorkspaceInfo.swift +++ b/Sources/SwiftBuild/SWBWorkspaceInfo.swift @@ -22,10 +22,11 @@ public struct SWBTargetInfo: Sendable { public let guid: String public let targetName: String public let projectName: String + public let dynamicTargetVariantGuid: String? } extension SWBWorkspaceInfo { init(_ workspaceInfo: WorkspaceInfoResponse.WorkspaceInfo) { - self = .init(targetInfos: workspaceInfo.targetInfos.map { .init(guid: $0.guid, targetName: $0.targetName, projectName: $0.projectName) }) + self = .init(targetInfos: workspaceInfo.targetInfos.map { .init(guid: $0.guid, targetName: $0.targetName, projectName: $0.projectName, dynamicTargetVariantGuid: $0.dynamicTargetVariantGuid) }) } } diff --git a/Tests/SWBProtocolTests/MessageSerializationTests.swift b/Tests/SWBProtocolTests/MessageSerializationTests.swift index e3ba3878..17445420 100644 --- a/Tests/SWBProtocolTests/MessageSerializationTests.swift +++ b/Tests/SWBProtocolTests/MessageSerializationTests.swift @@ -94,7 +94,7 @@ import Testing assertMsgPackMessageRoundTrip(AuditSessionPIFRequest(sessionHandle: "theSession", pifContents: [4, 7, 9, 13])) assertMsgPackMessageRoundTrip(IncrementalPIFLookupFailureRequest(sessionHandle: "theSession", diagnostic: "everything went wrong")) assertMsgPackMessageRoundTrip(WorkspaceInfoRequest(sessionHandle: "theSession")) - assertMsgPackMessageRoundTrip(WorkspaceInfoResponse(sessionHandle: "theSession", workspaceInfo: .init(targetInfos: [.init(guid: "theGuid", targetName: "aTarget", projectName: "aProject")]))) + assertMsgPackMessageRoundTrip(WorkspaceInfoResponse(sessionHandle: "theSession", workspaceInfo: .init(targetInfos: [.init(guid: "theGuid", targetName: "aTarget", projectName: "aProject", dynamicTargetVariantGuid: nil)]))) assertMsgPackMessageRoundTrip(ErrorResponse("everything went wrong")) assertMsgPackMessageRoundTrip(BoolResponse(true))