Skip to content

Commit 6fa8141

Browse files
committed
Refactor build system support
This is an initial step of unwinding the direct dependency of individual commands to a concrete build system implementation, through two major changes: - Adding a new target `DriverSupport` which contains integration with swift-driver that is independent of a concrete build system being used (today mostly `checkSupportedFrontendFlags(flags:fileSystem)` but there could be more in the future) - Adding a new `BuildSystemProvider` API which handles instantiation of a concrete build system. This will e.g. allow creating a `SwiftCommand` which doesn't depend on the `XCBuildSupport` module (which is going to help with #5807) and also provides a way to generally clean up (almost) all callsites from directly interacting with a concrete build system.
1 parent 1c68725 commit 6fa8141

25 files changed

+315
-181
lines changed

Package.swift

+8
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,14 @@ let package = Package(
308308
"SPMBuildCore",
309309
"SPMLLBuild",
310310
.product(name: "SwiftDriver", package: "swift-driver"),
311+
"DriverSupport",
312+
],
313+
exclude: ["CMakeLists.txt"]
314+
),
315+
.target(
316+
name: "DriverSupport",
317+
dependencies: [
318+
.product(name: "SwiftDriver", package: "swift-driver"),
311319
],
312320
exclude: ["CMakeLists.txt"]
313321
),

Sources/Build/BuildOperation.swift

+16-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import Basics
14+
@_implementationOnly import DriverSupport
1415
import LLBuildManifest
1516
import PackageGraph
1617
import PackageLoading
@@ -57,7 +58,17 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
5758
public let cacheBuildManifest: Bool
5859

5960
/// The build plan that was computed, if any.
60-
public private(set) var buildPlan: BuildPlan?
61+
public private(set) var _buildPlan: BuildPlan?
62+
63+
public var buildPlan: SPMBuildCore.BuildPlan {
64+
get throws {
65+
if let buildPlan = _buildPlan {
66+
return buildPlan
67+
} else {
68+
throw StringError("did not compute a build plan yet")
69+
}
70+
}
71+
}
6172

6273
/// The build description resulting from planing.
6374
private let buildDescription = ThreadSafeBox<BuildDescription>()
@@ -166,7 +177,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
166177
return
167178
}
168179
// Ensure the compiler supports the import-scan operation
169-
guard SwiftTargetBuildDescription.checkSupportedFrontendFlags(flags: ["import-prescan"], fileSystem: localFileSystem) else {
180+
guard DriverSupport.checkSupportedFrontendFlags(flags: ["import-prescan"], fileSystem: localFileSystem) else {
170181
return
171182
}
172183

@@ -457,7 +468,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
457468
fileSystem: self.fileSystem,
458469
observabilityScope: self.observabilityScope
459470
)
460-
self.buildPlan = plan
471+
self._buildPlan = plan
461472

462473
let (buildDescription, buildManifest) = try BuildDescription.create(
463474
with: plan,
@@ -568,14 +579,14 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
568579

569580
public func provideBuildErrorAdvice(for target: String, command: String, message: String) -> String? {
570581
// Find the target for which the error was emitted. If we don't find it, we can't give any advice.
571-
guard let _ = self.buildPlan?.targets.first(where: { $0.target.name == target }) else { return nil }
582+
guard let _ = self._buildPlan?.targets.first(where: { $0.target.name == target }) else { return nil }
572583

573584
// Check for cases involving modules that cannot be found.
574585
if let importedModule = try? RegEx(pattern: "no such module '(.+)'").matchGroups(in: message).first?.first {
575586
// A target is importing a module that can't be found. We take a look at the build plan and see if can offer any advice.
576587

577588
// Look for a target with the same module name as the one that's being imported.
578-
if let importedTarget = self.buildPlan?.targets.first(where: { $0.target.c99name == importedModule }) {
589+
if let importedTarget = self._buildPlan?.targets.first(where: { $0.target.c99name == importedModule }) {
579590
// For the moment we just check for executables that other targets try to import.
580591
if importedTarget.target.type == .executable {
581592
return "module '\(importedModule)' is the main module of an executable, and cannot be imported by tests and other targets"

Sources/Build/BuildPlan.swift

+6-21
Original file line numberDiff line numberDiff line change
@@ -851,16 +851,6 @@ public final class SwiftTargetBuildDescription {
851851
try self.fileSystem.writeIfChanged(path: path, bytes: stream.bytes)
852852
}
853853

854-
public static func checkSupportedFrontendFlags(flags: Set<String>, fileSystem: FileSystem) -> Bool {
855-
do {
856-
let executor = try SPMSwiftDriverExecutor(resolver: ArgsResolver(fileSystem: fileSystem), fileSystem: fileSystem, env: [:])
857-
let driver = try Driver(args: ["swiftc"], executor: executor)
858-
return driver.supportedFrontendFlags.intersection(flags) == flags
859-
} catch {
860-
return false
861-
}
862-
}
863-
864854
/// The arguments needed to compile this target.
865855
public func compileArguments() throws -> [String] {
866856
var args = [String]()
@@ -1262,7 +1252,7 @@ public final class SwiftTargetBuildDescription {
12621252
}
12631253

12641254
/// The build description for a product.
1265-
public final class ProductBuildDescription {
1255+
public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription {
12661256

12671257
/// The reference to the product.
12681258
public let package: ResolvedPackage
@@ -1276,12 +1266,7 @@ public final class ProductBuildDescription {
12761266
public let toolsVersion: ToolsVersion
12771267

12781268
/// The build parameters.
1279-
let buildParameters: BuildParameters
1280-
1281-
/// The path to the product binary produced.
1282-
public var binary: AbsolutePath {
1283-
return buildParameters.binaryPath(for: product)
1284-
}
1269+
public let buildParameters: BuildParameters
12851270

12861271
/// All object files to link into this product.
12871272
///
@@ -1639,7 +1624,7 @@ public final class PluginDescription: Codable {
16391624
}
16401625

16411626
/// A build plan for a package graph.
1642-
public class BuildPlan {
1627+
public class BuildPlan: SPMBuildCore.BuildPlan {
16431628

16441629
public enum Error: Swift.Error, CustomStringConvertible, Equatable {
16451630
/// There is no buildable target in the graph.
@@ -1680,8 +1665,8 @@ public class BuildPlan {
16801665
}
16811666

16821667
/// The products in this plan.
1683-
public var buildProducts: AnySequence<ProductBuildDescription> {
1684-
return AnySequence(productMap.values)
1668+
public var buildProducts: AnySequence<SPMBuildCore.ProductBuildDescription> {
1669+
return AnySequence(productMap.values.map { $0 as SPMBuildCore.ProductBuildDescription })
16851670
}
16861671

16871672
/// The results of invoking any build tool plugins used by targets in this build.
@@ -2056,7 +2041,7 @@ public class BuildPlan {
20562041

20572042
// Plan products.
20582043
for buildProduct in buildProducts {
2059-
try plan(buildProduct)
2044+
try plan(buildProduct as! ProductBuildDescription)
20602045
}
20612046
// FIXME: We need to find out if any product has a target on which it depends
20622047
// both static and dynamically and then issue a suitable diagnostic or auto

Sources/Build/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ add_library(Build
1111
BuildOperation.swift
1212
BuildPlan.swift
1313
LLBuildManifestBuilder.swift
14-
SPMSwiftDriverExecutor.swift
1514
SwiftCompilerOutputParser.swift)
1615
target_link_libraries(Build PUBLIC
1716
TSCBasic
@@ -21,6 +20,7 @@ target_link_libraries(Build PUBLIC
2120
SPMBuildCore
2221
SPMLLBuild)
2322
target_link_libraries(Build PRIVATE
23+
DriverSupport
2424
SwiftDriver)
2525

2626
# NOTE(compnerd) workaround for CMake not setting up include flags yet

Sources/Build/LLBuildManifestBuilder.swift

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import PackageGraph
1515
import PackageModel
1616
import LLBuildManifest
1717
import SPMBuildCore
18+
@_implementationOnly import DriverSupport
1819
@_implementationOnly import SwiftDriver
1920
import TSCBasic
2021

Sources/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_subdirectory(SPMSQLite3)
1010
add_subdirectory(Basics)
1111
add_subdirectory(Build)
1212
add_subdirectory(Commands)
13+
add_subdirectory(DriverSupport)
1314
add_subdirectory(LLBuildManifest)
1415
add_subdirectory(PackageCollections)
1516
add_subdirectory(PackageCollectionsModel)

Sources/Commands/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
88

99
add_library(Commands
10-
1110
Options.swift
1211
Snippets/CardEvent.swift
1312
Snippets/Cards/SnippetCard.swift
@@ -44,6 +43,7 @@ target_link_libraries(Commands PUBLIC
4443
Workspace
4544
XCBuildSupport)
4645
target_link_libraries(Commands PRIVATE
46+
DriverSupport
4747
$<$<NOT:$<PLATFORM_ID:Darwin>>:FoundationXML>)
4848
# NOTE(compnerd) workaround for CMake not setting up include flags yet
4949
set_target_properties(Commands PROPERTIES

Sources/Commands/Options.swift

+5-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import TSCBasic
1515
import PackageFingerprint
1616
import PackageModel
1717
import SPMBuildCore
18-
import Build
1918

2019
import struct TSCUtility.Triple
2120

@@ -346,9 +345,9 @@ struct BuildOptions: ParsableArguments {
346345

347346
/// The build system to use.
348347
@Option(name: .customLong("build-system"))
349-
var _buildSystem: BuildSystemKind = .native
348+
var _buildSystem: BuildSystemProvider.Kind = .native
350349

351-
var buildSystem: BuildSystemKind {
350+
var buildSystem: BuildSystemProvider.Kind {
352351
#if os(macOS)
353352
// Force the Xcode build system if we want to build more than one arch.
354353
return archs.count > 1 ? .xcode : self._buildSystem
@@ -377,11 +376,6 @@ struct BuildOptions: ParsableArguments {
377376
case disableIndexStore
378377
}
379378

380-
enum BuildSystemKind: String, ExpressibleByArgument, CaseIterable {
381-
case native
382-
case xcode
383-
}
384-
385379
enum TargetDependencyImportCheckingMode : String, Codable, ExpressibleByArgument {
386380
case none
387381
case warn
@@ -462,3 +456,6 @@ extension Sanitizer {
462456
return Sanitizer.allCases.map(\.rawValue).joined(separator: ", ")
463457
}
464458
}
459+
460+
extension BuildSystemProvider.Kind: ExpressibleByArgument {
461+
}

Sources/Commands/SwiftBuildTool.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ public struct SwiftBuildTool: SwiftCommand {
105105
}
106106

107107
if options.printManifestGraphviz {
108-
let buildOperation = try swiftTool.createBuildOperation()
108+
// FIXME: Doesn't seem ideal that we need an explicit build operation, but this concretely uses the `LLBuildManifest`.
109+
let buildOperation = try swiftTool.createBuildSystem(useSpecificBuildSystem: .native) as! BuildOperation
109110
let buildManifest = try buildOperation.getBuildManifest()
110111
var serializer = DOTManifestSerializer(manifest: buildManifest)
111112
// print to stdout

Sources/Commands/SwiftPackageRegistryTool.swift

-2
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@ import ArgumentParser
1414
import Basics
1515
import TSCBasic
1616
import SPMBuildCore
17-
import Build
1817
import PackageModel
1918
import PackageLoading
2019
import PackageGraph
2120
import SourceControl
22-
import XCBuildSupport
2321
import Workspace
2422
import Foundation
2523
import PackageRegistry

0 commit comments

Comments
 (0)