Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions Sources/SWBBuildService/BuildDescriptionMessages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ private protocol BuildDescriptionMessage: SessionMessage {
}

extension BuildDescriptionConfiguredTargetsRequest: BuildDescriptionMessage {}
extension BuildDescriptionSelectConfiguredTargetsForIndexRequest: BuildDescriptionMessage {}
extension BuildDescriptionConfiguredTargetSourcesRequest: BuildDescriptionMessage {}
extension IndexBuildSettingsRequest: BuildDescriptionMessage {}

Expand Down Expand Up @@ -147,6 +148,50 @@ fileprivate extension SourceLanguage {
}
}

struct BuildDescriptionSelectConfiguredTargetsForIndexMsg: MessageHandler {
private struct FailedToFindTargetForGUID: Error {
var guid: String
}

private struct FailedToSelectConfiguredTarget: Error {
var guid: String
}

func handle(request: Request, message: BuildDescriptionSelectConfiguredTargetsForIndexRequest) async throws -> BuildDescriptionSelectConfiguredTargetsForIndexResponse {
let buildDescription = try await request.buildDescription(for: message)

let session = try request.session(for: message)
guard let workspaceContext = session.workspaceContext else { throw MsgParserError.missingWorkspaceContext }
let buildRequest = try BuildRequest(from: message.request, workspace: workspaceContext.workspace)
let buildRequestContext = BuildRequestContext(workspaceContext: workspaceContext)

let uniqueTargets = OrderedSet(message.targets.map(\.rawValue))

let targets: Dictionary<String, ConfiguredTarget?> = Dictionary(buildDescription.allConfiguredTargets.lazy.filter { uniqueTargets.contains($0.target.guid) }.map {
($0.target.guid, $0)
}, uniquingKeysWith: {
buildRequestContext.selectConfiguredTargetForIndex($0, $1, hasEnabledIndexBuildArena: buildRequest.enableIndexBuildArena, runDestination: message.request.parameters.activeRunDestination)
})

let configuredTargets = try uniqueTargets.map { target in
guard let configuredTarget = targets[target] else {
throw FailedToFindTargetForGUID(guid: target)
}

guard let configuredTarget else {
throw FailedToSelectConfiguredTarget(guid: target)
}

return ConfiguredTargetIdentifier(
rawGUID: configuredTarget.guid.stringValue,
targetGUID: TargetGUID(rawValue: configuredTarget.target.guid)
)
}

return BuildDescriptionSelectConfiguredTargetsForIndexResponse(configuredTargets: configuredTargets)
}
}

struct BuildDescriptionConfiguredTargetSourcesMsg: MessageHandler {
private struct UnknownConfiguredTargetIDError: Error, CustomStringConvertible {
let configuredTarget: ConfiguredTargetIdentifier
Expand Down
1 change: 1 addition & 0 deletions Sources/SWBBuildService/Messages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1624,6 +1624,7 @@ package struct ServiceMessageHandlers: ServiceExtension {
service.registerMessageHandler(DumpBuildDependencyInfoMsg.self)

service.registerMessageHandler(BuildDescriptionConfiguredTargetsMsg.self)
service.registerMessageHandler(BuildDescriptionSelectConfiguredTargetsForIndexMsg.self)
service.registerMessageHandler(BuildDescriptionConfiguredTargetSourcesMsg.self)
service.registerMessageHandler(IndexBuildSettingsMsg.self)
service.registerMessageHandler(ReleaseBuildDescriptionMsg.self)
Expand Down
37 changes: 37 additions & 0 deletions Sources/SWBProtocol/BuildDescriptionMessages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,41 @@ public struct BuildDescriptionConfiguredTargetSourcesResponse: Message, Serializ
}
}

/// Select a configured target for each provided target GUID in the pre-generated build description to be used by the index.
public struct BuildDescriptionSelectConfiguredTargetsForIndexRequest: SessionMessage, RequestMessage, SerializableCodable, Equatable {
public typealias ResponseMessage = BuildDescriptionSelectConfiguredTargetsForIndexResponse

public static let name = "BUILD_DESCRIPTION_SELECT_CONFIGURED_TARGETS_FOR_INDEX_REQUEST"

public let sessionHandle: String

/// The ID of the build description from which to load the configured targets
public let buildDescriptionID: BuildDescriptionID

/// The build request that was used to generate the build description with the given ID.
public let request: BuildRequestMessagePayload

/// The targets for which to select configured targets.
public let targets: [TargetGUID]

public init(sessionHandle: String, buildDescriptionID: BuildDescriptionID, request: BuildRequestMessagePayload, targets: [TargetGUID]) {
self.sessionHandle = sessionHandle
self.buildDescriptionID = buildDescriptionID
self.request = request
self.targets = targets
}
}

public struct BuildDescriptionSelectConfiguredTargetsForIndexResponse: Message, SerializableCodable, Equatable {
public static let name = "BUILD_DESCRIPTION_SELECT_CONFIGURED_TARGETS_FOR_INDEX_RESPONSE"

public let configuredTargets: [ConfiguredTargetIdentifier]

public init(configuredTargets: [ConfiguredTargetIdentifier]) {
self.configuredTargets = configuredTargets
}
}

/// Load the build settings that should be used to index a source file in a given configured target
public struct IndexBuildSettingsRequest: SessionMessage, RequestMessage, SerializableCodable, Equatable {
public typealias ResponseMessage = IndexBuildSettingsResponse
Expand Down Expand Up @@ -241,6 +276,8 @@ let buildDescriptionMessages: [any Message.Type] = [
BuildDescriptionConfiguredTargetsResponse.self,
BuildDescriptionConfiguredTargetSourcesRequest.self,
BuildDescriptionConfiguredTargetSourcesResponse.self,
BuildDescriptionSelectConfiguredTargetsForIndexRequest.self,
BuildDescriptionSelectConfiguredTargetsForIndexResponse.self,
IndexBuildSettingsRequest.self,
IndexBuildSettingsResponse.self,
ReleaseBuildDescriptionRequest.self,
Expand Down
18 changes: 18 additions & 0 deletions Sources/SwiftBuild/SWBBuildServiceSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,24 @@ public final class SWBBuildServiceSession: Sendable {
return buildSettings.compilerArguments
}

public func selectConfiguredTargetsForIndex(targets: [SWBTargetGUID], buildDescription: SWBBuildDescriptionID, buildRequest: SWBBuildRequest) async throws -> [SWBConfiguredTargetIdentifier] {
let response = try await service.send(
request: BuildDescriptionSelectConfiguredTargetsForIndexRequest(
sessionHandle: uid,
buildDescriptionID: BuildDescriptionID(buildDescription),
request: buildRequest.messagePayloadRepresentation,
targets: targets.map { TargetGUID(rawValue: $0.rawValue) }
)
)

return response.configuredTargets.map {
SWBConfiguredTargetIdentifier(
rawGUID: $0.rawGUID,
targetGUID: .init($0.targetGUID)
)
}
}

// MARK: Macro evaluation


Expand Down
83 changes: 83 additions & 0 deletions Tests/SwiftBuildTests/InspectBuildDescriptionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,89 @@ fileprivate struct InspectBuildDescriptionTests {
}
}
}

@Test(.requireSDKs(.macOS))
func selectConfiguredTargets() async throws {
try await withTemporaryDirectory { (temporaryDirectory: NamedTemporaryDirectory) in
try await withAsyncDeferrable { deferrable in
let tmpDir = temporaryDirectory.path
let testSession = try await TestSWBSession(temporaryDirectory: temporaryDirectory)
await deferrable.addBlock {
await #expect(throws: Never.self) {
try await testSession.close()
}
}

let macOSAppTarget = TestStandardTarget(
"MyApp1",
type: .application,
buildConfigurations: [TestBuildConfiguration("Debug", buildSettings: ["SDKROOT": "macosx", "SUPPORTED_PLATFORMS": "macosx"])],
buildPhases: [TestSourcesBuildPhase([TestBuildFile("MyApp1.swift")])]
)

let iOSAppTarget = TestStandardTarget(
"MyApp2",
type: .application,
buildConfigurations: [TestBuildConfiguration("Debug", buildSettings: ["SDKROOT": "iphoneos", "SUPPORTED_PLATFORMS": "macosx iphoneos"])],
buildPhases: [TestSourcesBuildPhase([TestBuildFile("MyApp2.swift")])],
dependencies: [TestTargetDependency("MyFramework")]
)

let project = TestProject(
"Test",
groupTree: TestGroup("Test", children: [TestFile("MyFramework.swift"), TestFile("MyApp1.swift"), TestFile("MyApp2.swift")]),
targets: [macOSAppTarget, iOSAppTarget]

)

let workspace = TestWorkspace("MyWorkspace", projects: [project])

try await testSession.sendPIF(TestWorkspace("Test", sourceRoot: tmpDir, projects: [project]))

let buildDescriptionID = try await createIndexBuildDescription(workspace, session: testSession)

func configuredTarget(for target: TestStandardTarget, using runDestination: SWBRunDestinationInfo? = nil) async throws -> SWBConfiguredTargetIdentifier {
let result = try await configuredTargets(for: [target], using: runDestination)
return try #require(result.only)
}

func configuredTargets(for targets: [TestStandardTarget], using runDestination: SWBRunDestinationInfo? = nil) async throws -> [SWBConfiguredTargetIdentifier] {
var request = SWBBuildRequest()
request.parameters.activeRunDestination = runDestination
request.enableIndexBuildArena = true

return try await testSession.session.selectConfiguredTargetsForIndex(targets: targets.map { SWBTargetGUID(rawValue: $0.guid) }, buildDescription: .init(buildDescriptionID), buildRequest: request)
}

let macOSAppForMacOSRef = try await configuredTarget(for: macOSAppTarget, using: .macOS)
#expect(macOSAppForMacOSRef.rawGUID.contains("macosx"))

let macOSAppForiOSRef = try await configuredTarget(for: macOSAppTarget, using: .iOS)
#expect(macOSAppForiOSRef.rawGUID.contains("macosx"))

let iOSAppRefNoDestination = try await configuredTarget(for: iOSAppTarget)
#expect(iOSAppRefNoDestination.rawGUID.contains("macosx"))

let iOSAppForMacOSRef = try await configuredTarget(for: iOSAppTarget, using: .macOS)
#expect(iOSAppForMacOSRef.rawGUID.contains("macosx"))

let iOSAppForiOSRef = try await configuredTarget(for: iOSAppTarget, using: .iOS)
#expect(iOSAppForiOSRef.rawGUID.contains("iphoneos"))

let iOSAppForUnsupportedRef = try await configuredTarget(for: iOSAppTarget, using: .watchOS)
#expect(iOSAppForUnsupportedRef.rawGUID.contains("macosx"))

let multiple = try await configuredTargets(for: [macOSAppTarget, iOSAppTarget], using: .macOS)
#expect(multiple.count == 2)
do {
let macOSAppGUID = try #require(multiple.first?.targetGUID.rawValue)
let iOSAppGUID = try #require(multiple.last?.targetGUID.rawValue)
#expect(macOSAppGUID == macOSAppTarget.guid)
#expect(iOSAppGUID == iOSAppTarget.guid)
}
}
}
}
}

fileprivate extension SWBBuildServiceSession {
Expand Down
Loading