Skip to content

Commit 151804b

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 6aff18f commit 151804b

28 files changed

+340
-204
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/BuildOperationBuildSystemDelegateHandler.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ public struct BuildDescription: Codable {
354354
self.builtTestProducts = plan.buildProducts.filter{ $0.product.type == .test }.map { desc in
355355
return BuiltTestProduct(
356356
productName: desc.product.name,
357-
binaryPath: desc.binary
357+
binaryPath: desc.binaryPath
358358
)
359359
}
360360
self.pluginDescriptions = pluginDescriptions

Sources/Build/BuildPlan.swift

+10-25
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
///
@@ -1387,12 +1372,12 @@ public final class ProductBuildDescription {
13871372
let librarian = buildParameters.toolchain.librarianPath.pathString
13881373
let triple = buildParameters.triple
13891374
if triple.isWindows(), librarian.hasSuffix("link") || librarian.hasSuffix("link.exe") {
1390-
return [librarian, "/LIB", "/OUT:\(binary.pathString)", "@\(linkFileListPath.pathString)"]
1375+
return [librarian, "/LIB", "/OUT:\(binaryPath.pathString)", "@\(linkFileListPath.pathString)"]
13911376
}
13921377
if triple.isDarwin(), librarian.hasSuffix("libtool") {
1393-
return [librarian, "-o", binary.pathString, "@\(linkFileListPath.pathString)"]
1378+
return [librarian, "-o", binaryPath.pathString, "@\(linkFileListPath.pathString)"]
13941379
}
1395-
return [librarian, "crs", binary.pathString, "@\(linkFileListPath.pathString)"]
1380+
return [librarian, "crs", binaryPath.pathString, "@\(linkFileListPath.pathString)"]
13961381
}
13971382

13981383
/// The arguments to link and create this product.
@@ -1416,7 +1401,7 @@ public final class ProductBuildDescription {
14161401
}
14171402

14181403
args += ["-L", buildParameters.buildPath.pathString]
1419-
args += ["-o", binary.pathString]
1404+
args += ["-o", binaryPath.pathString]
14201405
args += ["-module-name", product.name.spm_mangledToC99ExtendedIdentifier()]
14211406
args += dylibs.map({ "-l" + $0.product.name })
14221407

@@ -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.
@@ -2055,7 +2040,7 @@ public class BuildPlan {
20552040

20562041
// Plan products.
20572042
for buildProduct in buildProducts {
2058-
try plan(buildProduct)
2043+
try plan(buildProduct as! ProductBuildDescription)
20592044
}
20602045
// FIXME: We need to find out if any product has a target on which it depends
20612046
// 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

+10-9
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

@@ -559,7 +560,7 @@ extension LLBuildManifestBuilder {
559560
guard let planProduct = plan.productMap[product] else {
560561
throw InternalError("unknown product \(product)")
561562
}
562-
inputs.append(file: planProduct.binary)
563+
inputs.append(file: planProduct.binaryPath)
563564
}
564565
return
565566
}
@@ -588,7 +589,7 @@ extension LLBuildManifestBuilder {
588589
throw InternalError("unknown product \(product)")
589590
}
590591
// Establish a dependency on binary of the product.
591-
inputs.append(file: planProduct.binary)
592+
inputs.append(file: planProduct.binaryPath)
592593

593594
// For automatic and static libraries, and plugins, add their targets as static input.
594595
case .library(.automatic), .library(.static), .plugin:
@@ -742,7 +743,7 @@ extension LLBuildManifestBuilder {
742743
throw InternalError("unknown product \(product)")
743744
}
744745
// Establish a dependency on binary of the product.
745-
let binary = planProduct.binary
746+
let binary = planProduct.binaryPath
746747
inputs.append(file: binary)
747748

748749
case .library(.automatic), .library(.static), .plugin:
@@ -894,20 +895,20 @@ extension LLBuildManifestBuilder {
894895
case .library(.static):
895896
manifest.addShellCmd(
896897
name: cmdName,
897-
description: "Archiving \(buildProduct.binary.prettyPath())",
898+
description: "Archiving \(buildProduct.binaryPath.prettyPath())",
898899
inputs: buildProduct.objects.map(Node.file),
899-
outputs: [.file(buildProduct.binary)],
900+
outputs: [.file(buildProduct.binaryPath)],
900901
arguments: try buildProduct.archiveArguments()
901902
)
902903

903904
default:
904-
let inputs = buildProduct.objects + buildProduct.dylibs.map({ $0.binary })
905+
let inputs = buildProduct.objects + buildProduct.dylibs.map({ $0.binaryPath })
905906

906907
manifest.addShellCmd(
907908
name: cmdName,
908-
description: "Linking \(buildProduct.binary.prettyPath())",
909+
description: "Linking \(buildProduct.binaryPath.prettyPath())",
909910
inputs: inputs.map(Node.file),
910-
outputs: [.file(buildProduct.binary)],
911+
outputs: [.file(buildProduct.binaryPath)],
911912
arguments: try buildProduct.linkArguments()
912913
)
913914
}
@@ -919,7 +920,7 @@ extension LLBuildManifestBuilder {
919920
manifest.addNode(output, toTarget: targetName)
920921
manifest.addPhonyCmd(
921922
name: output.name,
922-
inputs: [.file(buildProduct.binary)],
923+
inputs: [.file(buildProduct.binaryPath)],
923924
outputs: [output]
924925
)
925926

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,10 @@ 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+
guard let buildOperation = try swiftTool.createBuildSystem(explicitBuildSystem: .native) as? BuildOperation else {
110+
throw StringError("asked for native build system but did not get it")
111+
}
109112
let buildManifest = try buildOperation.getBuildManifest()
110113
var serializer = DOTManifestSerializer(manifest: buildManifest)
111114
// 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)