Skip to content

Commit 28cc7d5

Browse files
authored
Merge pull request #818 from xedin/select-configured-targets-for-index
Add a request to find a most appropriate configured target for indexi…
2 parents b3f9992 + 0bd0383 commit 28cc7d5

File tree

5 files changed

+184
-0
lines changed

5 files changed

+184
-0
lines changed

Sources/SWBBuildService/BuildDescriptionMessages.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ private protocol BuildDescriptionMessage: SessionMessage {
3030
}
3131

3232
extension BuildDescriptionConfiguredTargetsRequest: BuildDescriptionMessage {}
33+
extension BuildDescriptionSelectConfiguredTargetsForIndexRequest: BuildDescriptionMessage {}
3334
extension BuildDescriptionConfiguredTargetSourcesRequest: BuildDescriptionMessage {}
3435
extension IndexBuildSettingsRequest: BuildDescriptionMessage {}
3536

@@ -147,6 +148,50 @@ fileprivate extension SourceLanguage {
147148
}
148149
}
149150

151+
struct BuildDescriptionSelectConfiguredTargetsForIndexMsg: MessageHandler {
152+
private struct FailedToFindTargetForGUID: Error {
153+
var guid: String
154+
}
155+
156+
private struct FailedToSelectConfiguredTarget: Error {
157+
var guid: String
158+
}
159+
160+
func handle(request: Request, message: BuildDescriptionSelectConfiguredTargetsForIndexRequest) async throws -> BuildDescriptionSelectConfiguredTargetsForIndexResponse {
161+
let buildDescription = try await request.buildDescription(for: message)
162+
163+
let session = try request.session(for: message)
164+
guard let workspaceContext = session.workspaceContext else { throw MsgParserError.missingWorkspaceContext }
165+
let buildRequest = try BuildRequest(from: message.request, workspace: workspaceContext.workspace)
166+
let buildRequestContext = BuildRequestContext(workspaceContext: workspaceContext)
167+
168+
let uniqueTargets = OrderedSet(message.targets.map(\.rawValue))
169+
170+
let targets: Dictionary<String, ConfiguredTarget?> = Dictionary(buildDescription.allConfiguredTargets.lazy.filter { uniqueTargets.contains($0.target.guid) }.map {
171+
($0.target.guid, $0)
172+
}, uniquingKeysWith: {
173+
buildRequestContext.selectConfiguredTargetForIndex($0, $1, hasEnabledIndexBuildArena: buildRequest.enableIndexBuildArena, runDestination: message.request.parameters.activeRunDestination)
174+
})
175+
176+
let configuredTargets = try uniqueTargets.map { target in
177+
guard let configuredTarget = targets[target] else {
178+
throw FailedToFindTargetForGUID(guid: target)
179+
}
180+
181+
guard let configuredTarget else {
182+
throw FailedToSelectConfiguredTarget(guid: target)
183+
}
184+
185+
return ConfiguredTargetIdentifier(
186+
rawGUID: configuredTarget.guid.stringValue,
187+
targetGUID: TargetGUID(rawValue: configuredTarget.target.guid)
188+
)
189+
}
190+
191+
return BuildDescriptionSelectConfiguredTargetsForIndexResponse(configuredTargets: configuredTargets)
192+
}
193+
}
194+
150195
struct BuildDescriptionConfiguredTargetSourcesMsg: MessageHandler {
151196
private struct UnknownConfiguredTargetIDError: Error, CustomStringConvertible {
152197
let configuredTarget: ConfiguredTargetIdentifier

Sources/SWBBuildService/Messages.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1624,6 +1624,7 @@ package struct ServiceMessageHandlers: ServiceExtension {
16241624
service.registerMessageHandler(DumpBuildDependencyInfoMsg.self)
16251625

16261626
service.registerMessageHandler(BuildDescriptionConfiguredTargetsMsg.self)
1627+
service.registerMessageHandler(BuildDescriptionSelectConfiguredTargetsForIndexMsg.self)
16271628
service.registerMessageHandler(BuildDescriptionConfiguredTargetSourcesMsg.self)
16281629
service.registerMessageHandler(IndexBuildSettingsMsg.self)
16291630
service.registerMessageHandler(ReleaseBuildDescriptionMsg.self)

Sources/SWBProtocol/BuildDescriptionMessages.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,41 @@ public struct BuildDescriptionConfiguredTargetSourcesResponse: Message, Serializ
168168
}
169169
}
170170

171+
/// Select a configured target for each provided target GUID in the pre-generated build description to be used by the index.
172+
public struct BuildDescriptionSelectConfiguredTargetsForIndexRequest: SessionMessage, RequestMessage, SerializableCodable, Equatable {
173+
public typealias ResponseMessage = BuildDescriptionSelectConfiguredTargetsForIndexResponse
174+
175+
public static let name = "BUILD_DESCRIPTION_SELECT_CONFIGURED_TARGETS_FOR_INDEX_REQUEST"
176+
177+
public let sessionHandle: String
178+
179+
/// The ID of the build description from which to load the configured targets
180+
public let buildDescriptionID: BuildDescriptionID
181+
182+
/// The build request that was used to generate the build description with the given ID.
183+
public let request: BuildRequestMessagePayload
184+
185+
/// The targets for which to select configured targets.
186+
public let targets: [TargetGUID]
187+
188+
public init(sessionHandle: String, buildDescriptionID: BuildDescriptionID, request: BuildRequestMessagePayload, targets: [TargetGUID]) {
189+
self.sessionHandle = sessionHandle
190+
self.buildDescriptionID = buildDescriptionID
191+
self.request = request
192+
self.targets = targets
193+
}
194+
}
195+
196+
public struct BuildDescriptionSelectConfiguredTargetsForIndexResponse: Message, SerializableCodable, Equatable {
197+
public static let name = "BUILD_DESCRIPTION_SELECT_CONFIGURED_TARGETS_FOR_INDEX_RESPONSE"
198+
199+
public let configuredTargets: [ConfiguredTargetIdentifier]
200+
201+
public init(configuredTargets: [ConfiguredTargetIdentifier]) {
202+
self.configuredTargets = configuredTargets
203+
}
204+
}
205+
171206
/// Load the build settings that should be used to index a source file in a given configured target
172207
public struct IndexBuildSettingsRequest: SessionMessage, RequestMessage, SerializableCodable, Equatable {
173208
public typealias ResponseMessage = IndexBuildSettingsResponse
@@ -241,6 +276,8 @@ let buildDescriptionMessages: [any Message.Type] = [
241276
BuildDescriptionConfiguredTargetsResponse.self,
242277
BuildDescriptionConfiguredTargetSourcesRequest.self,
243278
BuildDescriptionConfiguredTargetSourcesResponse.self,
279+
BuildDescriptionSelectConfiguredTargetsForIndexRequest.self,
280+
BuildDescriptionSelectConfiguredTargetsForIndexResponse.self,
244281
IndexBuildSettingsRequest.self,
245282
IndexBuildSettingsResponse.self,
246283
ReleaseBuildDescriptionRequest.self,

Sources/SwiftBuild/SWBBuildServiceSession.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,24 @@ public final class SWBBuildServiceSession: Sendable {
433433
return buildSettings.compilerArguments
434434
}
435435

436+
public func selectConfiguredTargetsForIndex(targets: [SWBTargetGUID], buildDescription: SWBBuildDescriptionID, buildRequest: SWBBuildRequest) async throws -> [SWBConfiguredTargetIdentifier] {
437+
let response = try await service.send(
438+
request: BuildDescriptionSelectConfiguredTargetsForIndexRequest(
439+
sessionHandle: uid,
440+
buildDescriptionID: BuildDescriptionID(buildDescription),
441+
request: buildRequest.messagePayloadRepresentation,
442+
targets: targets.map { TargetGUID(rawValue: $0.rawValue) }
443+
)
444+
)
445+
446+
return response.configuredTargets.map {
447+
SWBConfiguredTargetIdentifier(
448+
rawGUID: $0.rawGUID,
449+
targetGUID: .init($0.targetGUID)
450+
)
451+
}
452+
}
453+
436454
// MARK: Macro evaluation
437455

438456

Tests/SwiftBuildTests/InspectBuildDescriptionTests.swift

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,89 @@ fileprivate struct InspectBuildDescriptionTests {
306306
}
307307
}
308308
}
309+
310+
@Test(.requireSDKs(.macOS))
311+
func selectConfiguredTargets() async throws {
312+
try await withTemporaryDirectory { (temporaryDirectory: NamedTemporaryDirectory) in
313+
try await withAsyncDeferrable { deferrable in
314+
let tmpDir = temporaryDirectory.path
315+
let testSession = try await TestSWBSession(temporaryDirectory: temporaryDirectory)
316+
await deferrable.addBlock {
317+
await #expect(throws: Never.self) {
318+
try await testSession.close()
319+
}
320+
}
321+
322+
let macOSAppTarget = TestStandardTarget(
323+
"MyApp1",
324+
type: .application,
325+
buildConfigurations: [TestBuildConfiguration("Debug", buildSettings: ["SDKROOT": "macosx", "SUPPORTED_PLATFORMS": "macosx"])],
326+
buildPhases: [TestSourcesBuildPhase([TestBuildFile("MyApp1.swift")])]
327+
)
328+
329+
let iOSAppTarget = TestStandardTarget(
330+
"MyApp2",
331+
type: .application,
332+
buildConfigurations: [TestBuildConfiguration("Debug", buildSettings: ["SDKROOT": "iphoneos", "SUPPORTED_PLATFORMS": "macosx iphoneos"])],
333+
buildPhases: [TestSourcesBuildPhase([TestBuildFile("MyApp2.swift")])],
334+
dependencies: [TestTargetDependency("MyFramework")]
335+
)
336+
337+
let project = TestProject(
338+
"Test",
339+
groupTree: TestGroup("Test", children: [TestFile("MyFramework.swift"), TestFile("MyApp1.swift"), TestFile("MyApp2.swift")]),
340+
targets: [macOSAppTarget, iOSAppTarget]
341+
342+
)
343+
344+
let workspace = TestWorkspace("MyWorkspace", projects: [project])
345+
346+
try await testSession.sendPIF(TestWorkspace("Test", sourceRoot: tmpDir, projects: [project]))
347+
348+
let buildDescriptionID = try await createIndexBuildDescription(workspace, session: testSession)
349+
350+
func configuredTarget(for target: TestStandardTarget, using runDestination: SWBRunDestinationInfo? = nil) async throws -> SWBConfiguredTargetIdentifier {
351+
let result = try await configuredTargets(for: [target], using: runDestination)
352+
return try #require(result.only)
353+
}
354+
355+
func configuredTargets(for targets: [TestStandardTarget], using runDestination: SWBRunDestinationInfo? = nil) async throws -> [SWBConfiguredTargetIdentifier] {
356+
var request = SWBBuildRequest()
357+
request.parameters.activeRunDestination = runDestination
358+
request.enableIndexBuildArena = true
359+
360+
return try await testSession.session.selectConfiguredTargetsForIndex(targets: targets.map { SWBTargetGUID(rawValue: $0.guid) }, buildDescription: .init(buildDescriptionID), buildRequest: request)
361+
}
362+
363+
let macOSAppForMacOSRef = try await configuredTarget(for: macOSAppTarget, using: .macOS)
364+
#expect(macOSAppForMacOSRef.rawGUID.contains("macosx"))
365+
366+
let macOSAppForiOSRef = try await configuredTarget(for: macOSAppTarget, using: .iOS)
367+
#expect(macOSAppForiOSRef.rawGUID.contains("macosx"))
368+
369+
let iOSAppRefNoDestination = try await configuredTarget(for: iOSAppTarget)
370+
#expect(iOSAppRefNoDestination.rawGUID.contains("macosx"))
371+
372+
let iOSAppForMacOSRef = try await configuredTarget(for: iOSAppTarget, using: .macOS)
373+
#expect(iOSAppForMacOSRef.rawGUID.contains("macosx"))
374+
375+
let iOSAppForiOSRef = try await configuredTarget(for: iOSAppTarget, using: .iOS)
376+
#expect(iOSAppForiOSRef.rawGUID.contains("iphoneos"))
377+
378+
let iOSAppForUnsupportedRef = try await configuredTarget(for: iOSAppTarget, using: .watchOS)
379+
#expect(iOSAppForUnsupportedRef.rawGUID.contains("macosx"))
380+
381+
let multiple = try await configuredTargets(for: [macOSAppTarget, iOSAppTarget], using: .macOS)
382+
#expect(multiple.count == 2)
383+
do {
384+
let macOSAppGUID = try #require(multiple.first?.targetGUID.rawValue)
385+
let iOSAppGUID = try #require(multiple.last?.targetGUID.rawValue)
386+
#expect(macOSAppGUID == macOSAppTarget.guid)
387+
#expect(iOSAppGUID == iOSAppTarget.guid)
388+
}
389+
}
390+
}
391+
}
309392
}
310393

311394
fileprivate extension SWBBuildServiceSession {

0 commit comments

Comments
 (0)