diff --git a/Sources/SWBBuildService/BuildDescriptionMessages.swift b/Sources/SWBBuildService/BuildDescriptionMessages.swift index e6c4a3e5..547e0468 100644 --- a/Sources/SWBBuildService/BuildDescriptionMessages.swift +++ b/Sources/SWBBuildService/BuildDescriptionMessages.swift @@ -95,6 +95,11 @@ struct BuildDescriptionConfiguredTargetsMsg: MessageHandler { func handle(request: Request, message: BuildDescriptionConfiguredTargetsRequest) async throws -> BuildDescriptionConfiguredTargetsResponse { let buildDescription = try await request.buildDescription(for: message) + var configuredTargetIdentifiersByGUID: [String: ConfiguredTargetIdentifier] = [:] + for configuredTarget in buildDescription.allConfiguredTargets { + configuredTargetIdentifiersByGUID[configuredTarget.guid.stringValue] = ConfiguredTargetIdentifier(rawGUID: configuredTarget.guid.stringValue, targetGUID: TargetGUID(rawValue: configuredTarget.target.guid)) + } + let dependencyRelationships = Dictionary( buildDescription.targetDependencies.map { (ConfiguredTarget.GUID(id: $0.target.guid), [$0]) }, uniquingKeysWith: { $0 + $1 } @@ -116,10 +121,9 @@ struct BuildDescriptionConfiguredTargetsMsg: MessageHandler { let dependencyRelationships = dependencyRelationships[configuredTarget.guid] return BuildDescriptionConfiguredTargetsResponse.ConfiguredTargetInfo( - guid: ConfiguredTargetGUID(configuredTarget.guid.stringValue), - target: TargetGUID(rawValue: configuredTarget.target.guid), + identifier: ConfiguredTargetIdentifier(rawGUID: configuredTarget.guid.stringValue, targetGUID: TargetGUID(rawValue: configuredTarget.target.guid)), name: configuredTarget.target.name, - dependencies: Set(dependencyRelationships?.flatMap(\.targetDependencies).map { ConfiguredTargetGUID($0.guid) } ?? []), + dependencies: Set(dependencyRelationships?.flatMap(\.targetDependencies).compactMap { configuredTargetIdentifiersByGUID[$0.guid] } ?? []), toolchain: toolchain ) } @@ -143,7 +147,7 @@ fileprivate extension SourceLanguage { struct BuildDescriptionConfiguredTargetSourcesMsg: MessageHandler { private struct UnknownConfiguredTargetIDError: Error, CustomStringConvertible { - let configuredTarget: ConfiguredTargetGUID + let configuredTarget: ConfiguredTargetIdentifier var description: String { "Unknown configured target: \(configuredTarget)" } } @@ -161,9 +165,9 @@ struct BuildDescriptionConfiguredTargetSourcesMsg: MessageHandler { } let indexingInfoInput = TaskGenerateIndexingInfoInput(requestedSourceFile: nil, outputPathOnly: true, enableIndexBuildArena: false) - let sourcesItems = try message.configuredTargets.map { configuredTargetGuid in - guard let target = configuredTargetsByID[ConfiguredTarget.GUID(id: configuredTargetGuid.rawValue)] else { - throw UnknownConfiguredTargetIDError(configuredTarget: configuredTargetGuid) + let sourcesItems = try message.configuredTargets.map { configuredTargetIdentifier in + guard let target = configuredTargetsByID[ConfiguredTarget.GUID(id: configuredTargetIdentifier.rawGUID)] else { + throw UnknownConfiguredTargetIDError(configuredTarget: configuredTargetIdentifier) } let sourceFiles = buildDescription.taskStore.tasksForTarget(target).flatMap { task in task.generateIndexingInfo(input: indexingInfoInput).compactMap { (entry) -> SourceFileInfo? in @@ -174,7 +178,7 @@ struct BuildDescriptionConfiguredTargetSourcesMsg: MessageHandler { ) } } - return ConfiguredTargetSourceFilesInfo(configuredTarget: configuredTargetGuid, sourceFiles: sourceFiles) + return ConfiguredTargetSourceFilesInfo(configuredTarget: configuredTargetIdentifier, sourceFiles: sourceFiles) } return BuildDescriptionConfiguredTargetSourcesResponse(targetSourceFileInfos: sourcesItems) } @@ -190,7 +194,7 @@ struct IndexBuildSettingsMsg: MessageHandler { func handle(request: Request, message: IndexBuildSettingsRequest) async throws -> IndexBuildSettingsResponse { let (buildRequest, buildDescription) = try await request.buildRequestAndDescription(for: message) - let configuredTarget = buildDescription.allConfiguredTargets.filter { $0.guid.stringValue == message.configuredTarget.rawValue }.only + let configuredTarget = buildDescription.allConfiguredTargets.filter { $0.guid.stringValue == message.configuredTarget.rawGUID }.only let indexingInfoInput = TaskGenerateIndexingInfoInput( requestedSourceFile: message.file, diff --git a/Sources/SWBProtocol/BuildDescriptionMessages.swift b/Sources/SWBProtocol/BuildDescriptionMessages.swift index 36cace79..2859a885 100644 --- a/Sources/SWBProtocol/BuildDescriptionMessages.swift +++ b/Sources/SWBProtocol/BuildDescriptionMessages.swift @@ -14,11 +14,13 @@ public import SWBUtil // MARK: Support types -public struct ConfiguredTargetGUID: Hashable, Sendable, Codable { - public var rawValue: String +public struct ConfiguredTargetIdentifier: Hashable, Sendable, Codable { + public var rawGUID: String + public var targetGUID: TargetGUID - public init(_ rawValue: String) { - self.rawValue = rawValue + public init(rawGUID: String, targetGUID: TargetGUID) { + self.rawGUID = rawGUID + self.targetGUID = targetGUID } } @@ -61,25 +63,21 @@ public struct BuildDescriptionConfiguredTargetsResponse: Message, SerializableCo public struct ConfiguredTargetInfo: SerializableCodable, Equatable, Sendable { /// The GUID of this configured target - public let guid: ConfiguredTargetGUID - - /// The GUID of the target from which this configured target was created - public let target: TargetGUID + public let identifier: ConfiguredTargetIdentifier /// A name of the target that may be displayed to the user public let name: String /// The configured targets that this target depends on - public let dependencies: Set + public let dependencies: Set /// The path of the toolchain that should be used to build this target. /// /// `nil` if the toolchain for this target could not be determined due to an error. public let toolchain: Path? - public init(guid: ConfiguredTargetGUID, target: TargetGUID, name: String, dependencies: Set, toolchain: Path?) { - self.guid = guid - self.target = target + public init(identifier: ConfiguredTargetIdentifier, name: String, dependencies: Set, toolchain: Path?) { + self.identifier = identifier self.name = name self.dependencies = dependencies self.toolchain = toolchain @@ -108,9 +106,9 @@ public struct BuildDescriptionConfiguredTargetSourcesRequest: SessionMessage, Re public let request: BuildRequestMessagePayload /// The configured targets for which to load source file information - public let configuredTargets: [ConfiguredTargetGUID] + public let configuredTargets: [ConfiguredTargetIdentifier] - public init(sessionHandle: String, buildDescriptionID: BuildDescriptionID, request: BuildRequestMessagePayload, configuredTargets: [ConfiguredTargetGUID]) { + public init(sessionHandle: String, buildDescriptionID: BuildDescriptionID, request: BuildRequestMessagePayload, configuredTargets: [ConfiguredTargetIdentifier]) { self.sessionHandle = sessionHandle self.buildDescriptionID = buildDescriptionID self.request = request @@ -148,12 +146,12 @@ public struct BuildDescriptionConfiguredTargetSourcesResponse: Message, Serializ public struct ConfiguredTargetSourceFilesInfo: SerializableCodable, Equatable, Sendable { /// The configured target to which this info belongs - public let configuredTarget: ConfiguredTargetGUID + public let configuredTarget: ConfiguredTargetIdentifier /// Information about the source files in this source file public let sourceFiles: [SourceFileInfo] - public init(configuredTarget: ConfiguredTargetGUID, sourceFiles: [SourceFileInfo]) { + public init(configuredTarget: ConfiguredTargetIdentifier, sourceFiles: [SourceFileInfo]) { self.configuredTarget = configuredTarget self.sourceFiles = sourceFiles } @@ -182,7 +180,7 @@ public struct IndexBuildSettingsRequest: SessionMessage, RequestMessage, Seriali public let request: BuildRequestMessagePayload /// The configured target in whose context the build settings of the source file should be loaded - public let configuredTarget: ConfiguredTargetGUID + public let configuredTarget: ConfiguredTargetIdentifier /// The path of the source file for which the build settings should be loaded public let file: Path @@ -191,7 +189,7 @@ public struct IndexBuildSettingsRequest: SessionMessage, RequestMessage, Seriali sessionHandle: String, buildDescriptionID: BuildDescriptionID, request: BuildRequestMessagePayload, - configuredTarget: ConfiguredTargetGUID, + configuredTarget: ConfiguredTargetIdentifier, file: Path ) { self.sessionHandle = sessionHandle diff --git a/Sources/SwiftBuild/CMakeLists.txt b/Sources/SwiftBuild/CMakeLists.txt index 9a1bbea2..18da3458 100644 --- a/Sources/SwiftBuild/CMakeLists.txt +++ b/Sources/SwiftBuild/CMakeLists.txt @@ -42,7 +42,7 @@ add_library(SwiftBuild SWBBuildServiceSession.swift SWBChannel.swift SWBClientExchangeSupport.swift - SWBConfiguredTargetGUID.swift + SWBConfiguredTargetIdentifier.swift SWBConfiguredTargetInfo.swift SWBConfiguredTargetSourceFilesInfo.swift SWBDocumentationSupport.swift diff --git a/Sources/SwiftBuild/SWBBuildServiceSession.swift b/Sources/SwiftBuild/SWBBuildServiceSession.swift index c96d6c7e..040407ba 100644 --- a/Sources/SwiftBuild/SWBBuildServiceSession.swift +++ b/Sources/SwiftBuild/SWBBuildServiceSession.swift @@ -393,25 +393,25 @@ public final class SWBBuildServiceSession: Sendable { return response.configuredTargets.map { SWBConfiguredTargetInfo($0) } } - public func sources(of configuredTargets: [SWBConfiguredTargetGUID], buildDescription: SWBBuildDescriptionID, buildRequest: SWBBuildRequest) async throws -> [SWBConfiguredTargetSourceFilesInfo] { + public func sources(of configuredTargets: [SWBConfiguredTargetIdentifier], buildDescription: SWBBuildDescriptionID, buildRequest: SWBBuildRequest) async throws -> [SWBConfiguredTargetSourceFilesInfo] { let response = try await service.send( request: BuildDescriptionConfiguredTargetSourcesRequest( sessionHandle: uid, buildDescriptionID: BuildDescriptionID(buildDescription), request: buildRequest.messagePayloadRepresentation, - configuredTargets: configuredTargets.map { ConfiguredTargetGUID($0) } + configuredTargets: configuredTargets.map { ConfiguredTargetIdentifier($0) } ) ) return response.targetSourceFileInfos.map { SWBConfiguredTargetSourceFilesInfo($0) } } - public func indexCompilerArguments(of file: AbsolutePath, in configuredTarget: SWBConfiguredTargetGUID, buildDescription: SWBBuildDescriptionID, buildRequest: SWBBuildRequest) async throws -> [String] { + public func indexCompilerArguments(of file: AbsolutePath, in configuredTarget: SWBConfiguredTargetIdentifier, buildDescription: SWBBuildDescriptionID, buildRequest: SWBBuildRequest) async throws -> [String] { let buildSettings = try await service.send( request: IndexBuildSettingsRequest( sessionHandle: uid, buildDescriptionID: BuildDescriptionID(buildDescription), request: buildRequest.messagePayloadRepresentation, - configuredTarget: ConfiguredTargetGUID(configuredTarget), + configuredTarget: ConfiguredTargetIdentifier(configuredTarget), file: Path(file.pathString) ) ) diff --git a/Sources/SwiftBuild/SWBConfiguredTargetGUID.swift b/Sources/SwiftBuild/SWBConfiguredTargetGUID.swift deleted file mode 100644 index 4b193169..00000000 --- a/Sources/SwiftBuild/SWBConfiguredTargetGUID.swift +++ /dev/null @@ -1,31 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift open source project -// -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -import SWBProtocol - -public struct SWBConfiguredTargetGUID: RawRepresentable, Hashable, Sendable { - public var rawValue: String - - public init(rawValue: String) { - self.rawValue = rawValue - } - - init(_ guid: ConfiguredTargetGUID) { - self.init(rawValue: guid.rawValue) - } -} - -extension ConfiguredTargetGUID { - init(_ guid: SWBConfiguredTargetGUID) { - self.init(guid.rawValue) - } -} diff --git a/Sources/SwiftBuild/SWBConfiguredTargetIdentifier.swift b/Sources/SwiftBuild/SWBConfiguredTargetIdentifier.swift new file mode 100644 index 00000000..2e1d3dad --- /dev/null +++ b/Sources/SwiftBuild/SWBConfiguredTargetIdentifier.swift @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SWBProtocol + +public struct SWBConfiguredTargetIdentifier: Hashable, Sendable { + public var rawGUID: String + public var targetGUID: SWBTargetGUID + + public init(rawGUID: String, targetGUID: SWBTargetGUID) { + self.rawGUID = rawGUID + self.targetGUID = targetGUID + } + + init(configuredTargetIdentifier: ConfiguredTargetIdentifier) { + self.init(rawGUID: configuredTargetIdentifier.rawGUID, targetGUID: SWBTargetGUID(configuredTargetIdentifier.targetGUID)) + } +} + +extension ConfiguredTargetIdentifier { + init(_ identifier: SWBConfiguredTargetIdentifier) { + self.init(rawGUID: identifier.rawGUID, targetGUID: TargetGUID(rawValue: identifier.targetGUID.rawValue)) + } +} diff --git a/Sources/SwiftBuild/SWBConfiguredTargetInfo.swift b/Sources/SwiftBuild/SWBConfiguredTargetInfo.swift index 410924c1..55b41e36 100644 --- a/Sources/SwiftBuild/SWBConfiguredTargetInfo.swift +++ b/Sources/SwiftBuild/SWBConfiguredTargetInfo.swift @@ -14,25 +14,21 @@ import SWBProtocol public struct SWBConfiguredTargetInfo { /// The GUID of this configured target - public let guid: SWBConfiguredTargetGUID - - /// The GUID of the target from which this configured target was created - public let target: SWBTargetGUID + public let identifier: SWBConfiguredTargetIdentifier /// A name of the target that may be displayed to the user public let name: String /// The configured targets that this target depends on - public let dependencies: Set + public let dependencies: Set /// The path of the toolchain that should be used to build this target. /// /// `nil` if the toolchain for this target could not be determined due to an error. public let toolchain: AbsolutePath? - public init(guid: SWBConfiguredTargetGUID, target: SWBTargetGUID, name: String, dependencies: Set, toolchain: AbsolutePath?) { - self.guid = guid - self.target = target + public init(identifier: SWBConfiguredTargetIdentifier, name: String, dependencies: Set, toolchain: AbsolutePath?) { + self.identifier = identifier self.name = name self.dependencies = dependencies self.toolchain = toolchain @@ -40,10 +36,9 @@ public struct SWBConfiguredTargetInfo { init(_ configuredTargetInfo: BuildDescriptionConfiguredTargetsResponse.ConfiguredTargetInfo) { self.init( - guid: SWBConfiguredTargetGUID(configuredTargetInfo.guid), - target: SWBTargetGUID(configuredTargetInfo.target), + identifier: SWBConfiguredTargetIdentifier(configuredTargetIdentifier: configuredTargetInfo.identifier), name: configuredTargetInfo.name, - dependencies: Set(configuredTargetInfo.dependencies.map { SWBConfiguredTargetGUID($0) }), + dependencies: Set(configuredTargetInfo.dependencies.map { SWBConfiguredTargetIdentifier(configuredTargetIdentifier: $0) }), toolchain: AbsolutePath(configuredTargetInfo.toolchain) ) } diff --git a/Sources/SwiftBuild/SWBConfiguredTargetSourceFilesInfo.swift b/Sources/SwiftBuild/SWBConfiguredTargetSourceFilesInfo.swift index d87f5927..6ad3b2ce 100644 --- a/Sources/SwiftBuild/SWBConfiguredTargetSourceFilesInfo.swift +++ b/Sources/SwiftBuild/SWBConfiguredTargetSourceFilesInfo.swift @@ -45,18 +45,18 @@ public struct SWBConfiguredTargetSourceFilesInfo: Equatable, Sendable { } /// The configured target to which this info belongs - public let configuredTarget: SWBConfiguredTargetGUID + public let configuredTarget: SWBConfiguredTargetIdentifier /// Information about the source files in this source file public let sourceFiles: [SourceFileInfo] - public init(configuredTarget: SWBConfiguredTargetGUID, sourceFiles: [SWBConfiguredTargetSourceFilesInfo.SourceFileInfo]) { + public init(configuredTarget: SWBConfiguredTargetIdentifier, sourceFiles: [SWBConfiguredTargetSourceFilesInfo.SourceFileInfo]) { self.configuredTarget = configuredTarget self.sourceFiles = sourceFiles } init(_ sourceFilesInfo: BuildDescriptionConfiguredTargetSourcesResponse.ConfiguredTargetSourceFilesInfo) { - self.configuredTarget = SWBConfiguredTargetGUID(sourceFilesInfo.configuredTarget) + self.configuredTarget = SWBConfiguredTargetIdentifier(configuredTargetIdentifier: sourceFilesInfo.configuredTarget) self.sourceFiles = sourceFilesInfo.sourceFiles.map { SourceFileInfo($0) } } } diff --git a/Tests/SwiftBuildTests/InspectBuildDescriptionTests.swift b/Tests/SwiftBuildTests/InspectBuildDescriptionTests.swift index 7af073cf..de98291d 100644 --- a/Tests/SwiftBuildTests/InspectBuildDescriptionTests.swift +++ b/Tests/SwiftBuildTests/InspectBuildDescriptionTests.swift @@ -68,7 +68,7 @@ fileprivate struct InspectBuildDescriptionTests { #expect(frameworkTargetInfo.dependencies == []) #expect(frameworkTargetInfo.toolchain != nil) let appTargetInfo = try #require(targetInfos.filter { $0.name == "MyApp" }.only) - #expect(appTargetInfo.dependencies == [frameworkTargetInfo.guid]) + #expect(appTargetInfo.dependencies == [frameworkTargetInfo.identifier]) #expect(appTargetInfo.toolchain != nil) } } @@ -122,8 +122,8 @@ fileprivate struct InspectBuildDescriptionTests { let appTargetInfo = try #require(targetInfos.filter { $0.name == "MyApp" }.only) let otherAppTargetInfo = try #require(targetInfos.filter { $0.name == "MyOtherApp" }.only) - let appSources = try #require(await testSession.session.sources(of: [appTargetInfo.guid], buildDescription: buildDescriptionID, buildRequest: request).only) - #expect(appSources.configuredTarget == appTargetInfo.guid) + let appSources = try #require(await testSession.session.sources(of: [appTargetInfo.identifier], buildDescription: buildDescriptionID, buildRequest: request).only) + #expect(appSources.configuredTarget == appTargetInfo.identifier) print(appSources.sourceFiles) let myAppFile = try #require(appSources.sourceFiles.only) #expect(myAppFile.path.pathString.hasSuffix("MyApp.swift")) @@ -131,11 +131,11 @@ fileprivate struct InspectBuildDescriptionTests { #expect(myAppFile.indexOutputPath != nil) let combinedSources = try await testSession.session.sources( - of: [appTargetInfo.guid, otherAppTargetInfo.guid], + of: [appTargetInfo.identifier, otherAppTargetInfo.identifier], buildDescription: buildDescriptionID, buildRequest: request ) - #expect(Set(combinedSources.map(\.configuredTarget)) == [appTargetInfo.guid, otherAppTargetInfo.guid]) + #expect(Set(combinedSources.map(\.configuredTarget)) == [appTargetInfo.identifier, otherAppTargetInfo.identifier]) #expect(Set(combinedSources.flatMap(\.sourceFiles).map { URL(filePath: $0.path.pathString).lastPathComponent }) == ["MyApp.swift", "MyOtherApp.swift"]) let emptyTargetListInfos = try await testSession.session.sources(of: [], buildDescription: buildDescriptionID, buildRequest: request) @@ -143,7 +143,7 @@ fileprivate struct InspectBuildDescriptionTests { await #expect(throws: (any Error).self) { try await testSession.session.sources( - of: [SWBConfiguredTargetGUID(rawValue: "does-not-exist")], + of: [SWBConfiguredTargetIdentifier(rawGUID: "does-not-exist", targetGUID: .init(rawValue: "does-not-exist"))], buildDescription: buildDescriptionID, buildRequest: request ) @@ -201,13 +201,13 @@ fileprivate struct InspectBuildDescriptionTests { let targetInfos = try await testSession.session.configuredTargets(buildDescription: buildDescriptionID, buildRequest: request) let appTargetInfo = try #require(targetInfos.filter { $0.name == "MyApp" }.only) let otherAppTargetInfo = try #require(targetInfos.filter { $0.name == "MyOtherApp" }.only) - let appSources = try #require(await testSession.session.sources(of: [appTargetInfo.guid], buildDescription: buildDescriptionID, buildRequest: request).only) + let appSources = try #require(await testSession.session.sources(of: [appTargetInfo.identifier], buildDescription: buildDescriptionID, buildRequest: request).only) let myAppFile = try #require(Set(appSources.sourceFiles.map(\.path)).filter { $0.pathString.hasSuffix("MyApp.swift") }.only) - let appIndexSettings = try await testSession.session.indexCompilerArguments(of: myAppFile, in: appTargetInfo.guid, buildDescription: buildDescriptionID, buildRequest: request) + let appIndexSettings = try await testSession.session.indexCompilerArguments(of: myAppFile, in: appTargetInfo.identifier, buildDescription: buildDescriptionID, buildRequest: request) #expect(appIndexSettings.contains("-DMY_APP")) #expect(!appIndexSettings.contains("-DMY_OTHER_APP")) - let otherAppIndexSettings = try await testSession.session.indexCompilerArguments(of: myAppFile, in: otherAppTargetInfo.guid, buildDescription: buildDescriptionID, buildRequest: request) + let otherAppIndexSettings = try await testSession.session.indexCompilerArguments(of: myAppFile, in: otherAppTargetInfo.identifier, buildDescription: buildDescriptionID, buildRequest: request) #expect(otherAppIndexSettings.contains("-DMY_OTHER_APP")) } }