Skip to content

Commit 08ace3d

Browse files
authored
[6.0][Build/PackageGraph] Switch BuildSubset.{product, target} and `Modu… (#7668)
…lesGraph.{product, target}(...)` to use optional destination - Explanation: Follow-up to #7646 This is mostly NFC change. It makes more sense to default `destination` to "undefined" when applicable because it's not always possible to know intended destination based on user input. This kind of design makes more sense for internal APIs, instead of having users to pass `.destination` even though it might not be always correct. - Main Branch PRs: #7650 - Risk: Very Low - Reviewed By: @MaxDesiatov - Testing: Existing test-cases were modified and new tests were added.
1 parent 616edfd commit 08ace3d

File tree

9 files changed

+168
-35
lines changed

9 files changed

+168
-35
lines changed

Sources/Build/BuildOperation.swift

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
516516
}
517517

518518
/// Compute the llbuild target name using the given subset.
519-
private func computeLLBuildTargetName(for subset: BuildSubset) throws -> String {
519+
func computeLLBuildTargetName(for subset: BuildSubset) throws -> String {
520520
switch subset {
521521
case .allExcludingTests:
522522
return LLBuildManifestBuilder.TargetKind.main.targetName
@@ -526,9 +526,15 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
526526
// FIXME: This is super unfortunate that we might need to load the package graph.
527527
let graph = try getPackageGraph()
528528

529+
let buildTriple: BuildTriple? = if let destination {
530+
destination == .host ? .tools : .destination
531+
} else {
532+
nil
533+
}
534+
529535
let product = graph.product(
530536
for: productName,
531-
destination: destination == .host ? .tools : .destination
537+
destination: buildTriple
532538
)
533539

534540
guard let product else {
@@ -556,9 +562,15 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
556562
// FIXME: This is super unfortunate that we might need to load the package graph.
557563
let graph = try getPackageGraph()
558564

565+
let buildTriple: BuildTriple? = if let destination {
566+
destination == .host ? .tools : .destination
567+
} else {
568+
nil
569+
}
570+
559571
let target = graph.target(
560572
for: targetName,
561-
destination: destination == .host ? .tools : .destination
573+
destination: buildTriple
562574
)
563575

564576
guard let target else {
@@ -669,7 +681,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
669681
// Emit warnings about any unhandled files in authored packages. We do this after applying build tool plugins, once we know what files they handled.
670682
// rdar://113256834 This fix works for the plugins that do not have PreBuildCommands.
671683
let targetsToConsider: [ResolvedModule]
672-
if let subset = subset, let recursiveDependencies = try
684+
if let subset = subset, let recursiveDependencies = try
673685
subset.recursiveDependencies(for: graph, observabilityScope: observabilityScope) {
674686
targetsToConsider = recursiveDependencies
675687
} else {
@@ -939,18 +951,30 @@ extension BuildSubset {
939951
case .allExcludingTests:
940952
return graph.reachableTargets.filter { $0.type != .test }
941953
case .product(let productName, let destination):
954+
let buildTriple: BuildTriple? = if let destination {
955+
destination == .host ? .tools : .destination
956+
} else {
957+
nil
958+
}
959+
942960
guard let product = graph.product(
943961
for: productName,
944-
destination: destination == .host ? .tools : .destination
962+
destination: buildTriple
945963
) else {
946964
observabilityScope.emit(error: "no product named '\(productName)'")
947965
return nil
948966
}
949967
return try product.recursiveTargetDependencies()
950968
case .target(let targetName, let destination):
969+
let buildTriple: BuildTriple? = if let destination {
970+
destination == .host ? .tools : .destination
971+
} else {
972+
nil
973+
}
974+
951975
guard let target = graph.target(
952976
for: targetName,
953-
destination: destination == .host ? .tools : .destination
977+
destination: buildTriple
954978
) else {
955979
observabilityScope.emit(error: "no target named '\(targetName)'")
956980
return nil

Sources/Commands/Utilities/PluginDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ final class PluginDelegate: PluginInvocationDelegate {
385385

386386
// Find the target in the build operation's package graph; it's an error if we don't find it.
387387
let packageGraph = try buildSystem.getPackageGraph()
388-
guard let target = packageGraph.target(for: targetName, destination: .destination) else {
388+
guard let target = packageGraph.target(for: targetName) else {
389389
throw StringError("could not find a target named “\(targetName)")
390390
}
391391

Sources/PackageGraph/ModulesGraph.swift

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -138,55 +138,59 @@ public struct ModulesGraph {
138138
package.dependencies.compactMap { self.package(for: $0) }
139139
}
140140

141-
public func product(for name: String, destination: BuildTriple) -> ResolvedProduct? {
141+
/// Find a product given a name and an optional destination. If a destination is not specified
142+
/// this method uses `.destination` and falls back to `.tools` for macros, plugins, and tests.
143+
public func product(for name: String, destination: BuildTriple? = .none) -> ResolvedProduct? {
142144
func findProduct(name: String, destination: BuildTriple) -> ResolvedProduct? {
143145
self.allProducts.first { $0.name == name && $0.buildTriple == destination }
144146
}
145147

146-
if let product = findProduct(name: name, destination: destination) {
147-
return product
148+
if let destination {
149+
return findProduct(name: name, destination: destination)
148150
}
149151

150-
// FIXME: This is a temporary workaround and needs to be handled by the callers.
152+
if let product = findProduct(name: name, destination: .destination) {
153+
return product
154+
}
151155

152156
// It's possible to request a build of a macro, a plugin, or a test via `swift build`
153157
// which won't have the right destination set because it's impossible to indicate it.
154158
//
155159
// Same happens with `--test-product` - if one of the test targets directly references
156160
// a macro then all if its targets and the product itself become `host`.
157-
if destination == .destination {
158-
if let toolsProduct = findProduct(name: name, destination: .tools),
159-
toolsProduct.type == .macro || toolsProduct.type == .plugin || toolsProduct.type == .test
160-
{
161-
return toolsProduct
162-
}
161+
if let toolsProduct = findProduct(name: name, destination: .tools),
162+
toolsProduct.type == .macro || toolsProduct.type == .plugin || toolsProduct.type == .test
163+
{
164+
return toolsProduct
163165
}
164166

165167
return nil
166168
}
167169

168-
public func target(for name: String, destination: BuildTriple) -> ResolvedModule? {
170+
/// Find a target given a name and an optional destination. If a destination is not specified
171+
/// this method uses `.destination` and falls back to `.tools` for macros, plugins, and tests.
172+
public func target(for name: String, destination: BuildTriple? = .none) -> ResolvedModule? {
169173
func findModule(name: String, destination: BuildTriple) -> ResolvedModule? {
170174
self.allTargets.first { $0.name == name && $0.buildTriple == destination }
171175
}
172176

173-
if let module = findModule(name: name, destination: destination) {
174-
return module
177+
if let destination {
178+
return findModule(name: name, destination: destination)
175179
}
176180

177-
// FIXME: This is a temporary workaround and needs to be handled by the callers.
181+
if let module = findModule(name: name, destination: .destination) {
182+
return module
183+
}
178184

179185
// It's possible to request a build of a macro, a plugin or a test via `swift build`
180186
// which won't have the right destination set because it's impossible to indicate it.
181187
//
182188
// Same happens with `--test-product` - if one of the test targets directly references
183189
// a macro then all if its targets and the product itself become `host`.
184-
if destination == .destination {
185-
if let toolsModule = findModule(name: name, destination: .tools),
186-
toolsModule.type == .macro || toolsModule.type == .plugin || toolsModule.type == .test
187-
{
188-
return toolsModule
189-
}
190+
if let toolsModule = findModule(name: name, destination: .tools),
191+
toolsModule.type == .macro || toolsModule.type == .plugin || toolsModule.type == .test
192+
{
193+
return toolsModule
190194
}
191195

192196
return nil

Sources/SPMBuildCore/BuildSystem/BuildSystem.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ public enum BuildSubset {
2424
/// Represents the subset of all products and targets.
2525
case allIncludingTests
2626

27-
/// Represents a specific product.
28-
case product(String, for: BuildParameters.Destination = .target)
27+
/// Represents a specific product. Allows to set a specific
28+
/// destination if it's known.
29+
case product(String, for: BuildParameters.Destination? = .none)
2930

30-
/// Represents a specific target.
31-
case target(String, for: BuildParameters.Destination = .target)
31+
/// Represents a specific target. Allows to set a specific
32+
/// destination if it's known.
33+
case target(String, for: BuildParameters.Destination? = .none)
3234
}
3335

3436
/// A protocol that represents a build system used by SwiftPM for all build operations. This allows factoring out the

Sources/SPMTestSupport/MockPackageGraphs.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,11 @@ package func macrosPackageGraph() throws -> MockPackageGraph {
127127

128128
package func macrosTestsPackageGraph() throws -> MockPackageGraph {
129129
let fs = InMemoryFileSystem(emptyFiles:
130+
"/swift-mmio/Plugins/MMIOPlugin/source.swift",
130131
"/swift-mmio/Sources/MMIO/source.swift",
131132
"/swift-mmio/Sources/MMIOMacros/source.swift",
132133
"/swift-mmio/Sources/MMIOMacrosTests/source.swift",
134+
"/swift-mmio/Sources/MMIOMacro+PluginTests/source.swift",
133135
"/swift-syntax/Sources/SwiftSyntax/source.swift",
134136
"/swift-syntax/Sources/SwiftSyntaxMacrosTestSupport/source.swift",
135137
"/swift-syntax/Sources/SwiftSyntaxMacros/source.swift",
@@ -156,6 +158,11 @@ package func macrosTestsPackageGraph() throws -> MockPackageGraph {
156158
name: "MMIO",
157159
type: .library(.automatic),
158160
targets: ["MMIO"]
161+
),
162+
ProductDescription(
163+
name: "MMIOPlugin",
164+
type: .plugin,
165+
targets: ["MMIOPlugin"]
159166
)
160167
],
161168
targets: [
@@ -171,13 +178,26 @@ package func macrosTestsPackageGraph() throws -> MockPackageGraph {
171178
],
172179
type: .macro
173180
),
181+
TargetDescription(
182+
name: "MMIOPlugin",
183+
type: .plugin,
184+
pluginCapability: .buildTool
185+
),
174186
TargetDescription(
175187
name: "MMIOMacrosTests",
176188
dependencies: [
177189
.target(name: "MMIOMacros"),
178190
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax")
179191
],
180192
type: .test
193+
),
194+
TargetDescription(
195+
name: "MMIOMacro+PluginTests",
196+
dependencies: [
197+
.target(name: "MMIOPlugin"),
198+
.target(name: "MMIOMacros")
199+
],
200+
type: .test
181201
)
182202
]
183203
),

Sources/SPMTestSupport/PackageGraphTester.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public final class PackageGraphResult {
8888

8989
package func checkTarget(
9090
_ name: String,
91-
destination: BuildTriple = .destination,
91+
destination: BuildTriple? = .none,
9292
file: StaticString = #file,
9393
line: UInt = #line,
9494
body: (ResolvedTargetResult) -> Void
@@ -113,7 +113,7 @@ public final class PackageGraphResult {
113113

114114
public func checkProduct(
115115
_ name: String,
116-
destination: BuildTriple = .destination,
116+
destination: BuildTriple? = .none,
117117
file: StaticString = #file,
118118
line: UInt = #line,
119119
body: (ResolvedProductResult) -> Void

Tests/BuildTests/BuildOperationTests.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import LLBuildManifest
1818
@_spi(DontAdoptOutsideOfSwiftPMExposedForBenchmarksAndTestsOnly)
1919
import PackageGraph
2020
import SPMBuildCore
21+
@_spi(SwiftPMInternal)
2122
import SPMTestSupport
2223
import XCTest
2324

@@ -176,4 +177,41 @@ final class BuildOperationTests: XCTestCase {
176177
}
177178
}
178179
}
180+
181+
func testHostProductsAndTargetsWithoutExplicitDestination() throws {
182+
let mock = try macrosTestsPackageGraph()
183+
184+
let op = mockBuildOperation(
185+
productsBuildParameters: mockBuildParameters(destination: .target),
186+
toolsBuildParameters: mockBuildParameters(destination: .host),
187+
packageGraphLoader: { mock.graph },
188+
scratchDirectory: AbsolutePath("/.build/\(hostTriple)"),
189+
fs: mock.fileSystem,
190+
observabilityScope: mock.observabilityScope
191+
)
192+
193+
XCTAssertEqual(
194+
"MMIOMacros-\(hostTriple)-debug-tool.exe",
195+
try op.computeLLBuildTargetName(for: .product("MMIOMacros"))
196+
)
197+
198+
for target in ["MMIOMacros", "MMIOPlugin", "MMIOMacrosTests", "MMIOMacro+PluginTests"] {
199+
XCTAssertEqual(
200+
"\(target)-\(hostTriple)-debug-tool.module",
201+
try op.computeLLBuildTargetName(for: .target(target))
202+
)
203+
}
204+
205+
let dependencies = try BuildSubset.target("MMIOMacro+PluginTests").recursiveDependencies(
206+
for: mock.graph,
207+
observabilityScope: mock.observabilityScope
208+
)
209+
210+
XCTAssertNotNil(dependencies)
211+
XCTAssertTrue(dependencies!.count > 0)
212+
213+
for dependency in dependencies! {
214+
XCTAssertEqual(dependency.buildTriple, .tools)
215+
}
216+
}
179217
}

Tests/BuildTests/CrossCompilationBuildPlanTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ final class CrossCompilationBuildPlanTests: XCTestCase {
300300
)
301301
let result = try BuildPlanResult(plan: plan)
302302
result.checkProductsCount(2)
303-
result.checkTargetsCount(15)
303+
result.checkTargetsCount(16)
304304

305305
XCTAssertTrue(try result.allTargets(named: "SwiftSyntax")
306306
.map { try $0.swiftTarget() }

0 commit comments

Comments
 (0)