Skip to content

Commit af93a3c

Browse files
authored
Create an alternate SwiftPM build system called Swift Build (#8271)
Add basic test coverage for the new build system for the supported platforms: Linux, macOS, and Windows. Provide basic progress reporting, and an option for "very verbose" mode so that that individual build tasks and the arguments can be inspected for correctness. Build a package with the new build system like this: swift build --build-system=swiftbuild Enable very verbose task outputs with their flags, options, and arguments: swift build --build-system=swiftbuild --vv
1 parent 6bdb3d3 commit af93a3c

26 files changed

+4232
-48
lines changed

IntegrationTests/Tests/IntegrationTests/SwiftPMTests.swift

+16
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,22 @@ final class SwiftPMTests: XCTestCase {
4949
}
5050
}
5151

52+
func testSwiftBuild() throws {
53+
#if os(Linux)
54+
if FileManager.default.contents(atPath: "/etc/system-release").map { String(decoding: $0, as: UTF8.self) == "Amazon Linux release 2 (Karoo)\n" } ?? false {
55+
throw XCTSkip("Skipping SwiftBuild testing on Amazon Linux because of platform issues.")
56+
}
57+
#endif
58+
59+
// Test SwiftBuildSystem
60+
try withTemporaryDirectory { tmpDir in
61+
let packagePath = tmpDir.appending(component: "foo")
62+
try localFileSystem.createDirectory(packagePath)
63+
try sh(swiftPackage, "--package-path", packagePath, "init", "--type", "executable")
64+
try sh(swiftBuild, "--package-path", packagePath, "--build-system", "swiftbuild")
65+
}
66+
}
67+
5268
func testArchCustomization() throws {
5369
#if !os(macOS)
5470
try XCTSkip("Test requires macOS")

Package.swift

+35
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,13 @@ let package = Package(
452452
.unsafeFlags(["-static"]),
453453
]
454454
),
455+
.target(
456+
name: "SwiftBuildSupport",
457+
dependencies: [
458+
"SPMBuildCore",
459+
"PackageGraph",
460+
]
461+
),
455462
.target(
456463
/** High level functionality */
457464
name: "Workspace",
@@ -500,6 +507,7 @@ let package = Package(
500507
"PackageGraph",
501508
"Workspace",
502509
"XCBuildSupport",
510+
"SwiftBuildSupport",
503511
],
504512
exclude: ["CMakeLists.txt"],
505513
swiftSettings: [
@@ -521,6 +529,7 @@ let package = Package(
521529
"SourceControl",
522530
"Workspace",
523531
"XCBuildSupport",
532+
"SwiftBuildSupport",
524533
] + swiftSyntaxDependencies(["SwiftIDEUtils"]),
525534
exclude: ["CMakeLists.txt", "README.md"],
526535
swiftSettings: [
@@ -619,6 +628,7 @@ let package = Package(
619628
"PackageLoading",
620629
"PackageModel",
621630
"XCBuildSupport",
631+
"SwiftBuildSupport",
622632
],
623633
exclude: ["CMakeLists.txt"]
624634
),
@@ -698,6 +708,7 @@ let package = Package(
698708
dependencies: [
699709
"Build",
700710
"XCBuildSupport",
711+
"SwiftBuildSupport",
701712
"_InternalTestSupport"
702713
],
703714
swiftSettings: [
@@ -1010,3 +1021,27 @@ if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
10101021
.package(path: "../swift-toolchain-sqlite"),
10111022
]
10121023
}
1024+
1025+
if ProcessInfo.processInfo.environment["SWIFTPM_SWBUILD_FRAMEWORK"] == nil &&
1026+
ProcessInfo.processInfo.environment["SWIFTPM_NO_SWBUILD_DEPENDENCY"] == nil {
1027+
1028+
let swiftbuildsupport: Target = package.targets.first(where: { $0.name == "SwiftBuildSupport" } )!
1029+
swiftbuildsupport.dependencies += [
1030+
.product(name: "SwiftBuild", package: "swift-build"),
1031+
]
1032+
1033+
swiftbuildsupport.dependencies += [
1034+
// This is here to statically link the build service in the same executable as SwiftPM
1035+
.product(name: "SWBBuildService", package: "swift-build"),
1036+
]
1037+
1038+
if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
1039+
package.dependencies += [
1040+
.package(url: "https://github.com/swiftlang/swift-build.git", branch: relatedDependenciesBranch),
1041+
]
1042+
} else {
1043+
package.dependencies += [
1044+
.package(path: "../swift-build"),
1045+
]
1046+
}
1047+
}

Sources/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ add_subdirectory(swift-test)
4040
add_subdirectory(SwiftSDKCommand)
4141
add_subdirectory(Workspace)
4242
add_subdirectory(XCBuildSupport)
43+
add_subdirectory(SwiftBuildSupport)

Sources/CoreCommands/BuildSystemSupport.swift

+31
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import Basics
1414
import Build
1515
import SPMBuildCore
1616
import XCBuildSupport
17+
import SwiftBuildSupport
1718
import PackageGraph
1819

1920
import class Basics.ObservabilityScope
@@ -93,10 +94,40 @@ private struct XcodeBuildSystemFactory: BuildSystemFactory {
9394
}
9495
}
9596

97+
private struct SwiftBuildSystemFactory: BuildSystemFactory {
98+
let swiftCommandState: SwiftCommandState
99+
100+
func makeBuildSystem(
101+
explicitProduct: String?,
102+
traitConfiguration: TraitConfiguration,
103+
cacheBuildManifest: Bool,
104+
productsBuildParameters: BuildParameters?,
105+
toolsBuildParameters: BuildParameters?,
106+
packageGraphLoader: (() async throws -> ModulesGraph)?,
107+
outputStream: OutputByteStream?,
108+
logLevel: Diagnostic.Severity?,
109+
observabilityScope: ObservabilityScope?
110+
) throws -> any BuildSystem {
111+
return try SwiftBuildSystem(
112+
buildParameters: productsBuildParameters ?? self.swiftCommandState.productsBuildParameters,
113+
packageGraphLoader: packageGraphLoader ?? {
114+
try await self.swiftCommandState.loadPackageGraph(
115+
explicitProduct: explicitProduct
116+
)
117+
},
118+
outputStream: outputStream ?? self.swiftCommandState.outputStream,
119+
logLevel: logLevel ?? self.swiftCommandState.logLevel,
120+
fileSystem: self.swiftCommandState.fileSystem,
121+
observabilityScope: observabilityScope ?? self.swiftCommandState.observabilityScope
122+
)
123+
}
124+
}
125+
96126
extension SwiftCommandState {
97127
public var defaultBuildSystemProvider: BuildSystemProvider {
98128
.init(providers: [
99129
.native: NativeBuildSystemFactory(swiftCommandState: self),
130+
.swiftbuild: SwiftBuildSystemFactory(swiftCommandState: self),
100131
.xcode: XcodeBuildSystemFactory(swiftCommandState: self)
101132
])
102133
}

Sources/CoreCommands/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ target_link_libraries(CoreCommands PUBLIC
1919
TSCBasic
2020
TSCUtility
2121
Workspace
22-
XCBuildSupport)
22+
XCBuildSupport
23+
SwiftBuildSupport)
2324
target_link_libraries(CoreCommands PRIVATE
2425
DriverSupport
2526
$<$<NOT:$<PLATFORM_ID:Darwin>>:FoundationXML>)

Sources/CoreCommands/SwiftCommandState.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ public final class SwiftCommandState {
728728
toolsBuildParameters: BuildParameters? = .none,
729729
packageGraphLoader: (() async throws -> ModulesGraph)? = .none,
730730
outputStream: OutputByteStream? = .none,
731-
logLevel: Basics.Diagnostic.Severity? = .none,
731+
logLevel: Basics.Diagnostic.Severity? = nil,
732732
observabilityScope: ObservabilityScope? = .none
733733
) async throws -> BuildSystem {
734734
guard let buildSystemProvider else {
@@ -747,7 +747,7 @@ public final class SwiftCommandState {
747747
toolsBuildParameters: toolsBuildParameters,
748748
packageGraphLoader: packageGraphLoader,
749749
outputStream: outputStream,
750-
logLevel: logLevel,
750+
logLevel: logLevel ?? self.logLevel,
751751
observabilityScope: observabilityScope
752752
)
753753

Sources/PackageModel/SwiftLanguageVersion.swift

+5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ public struct SwiftLanguageVersion: Hashable, Sendable {
3939
v3, v4, v4_2, v5, v6
4040
]
4141

42+
/// The list of supported Swift language versions for this toolchain.
43+
public static let supportedSwiftLanguageVersions = [
44+
v4, v4_2, v5, v6
45+
]
46+
4247
/// The raw value of the language version.
4348
//
4449
// This should be passed as a value to Swift compiler's -swift-version flag.

Sources/SPMBuildCore/BuildSystem/BuildSystem.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public enum BuildSubset {
3333
}
3434

3535
/// A protocol that represents a build system used by SwiftPM for all build operations. This allows factoring out the
36-
/// implementation details between SwiftPM's `BuildOperation` and the XCBuild backed `XCBuildSystem`.
36+
/// implementation details between SwiftPM's `BuildOperation` and the Swift Build backed `SwiftBuildSystem`.
3737
public protocol BuildSystem: Cancellable {
3838

3939
/// The delegate used by the build system.
@@ -130,6 +130,7 @@ public struct BuildSystemProvider {
130130
// TODO: In the future, we may want this to be about specific capabilities of a build system rather than choosing a concrete one.
131131
public enum Kind: String, CaseIterable {
132132
case native
133+
case swiftbuild
133134
case xcode
134135
}
135136

@@ -172,6 +173,7 @@ extension BuildSystemProvider.Kind {
172173
public var usesXcodeBuildEngine: Bool {
173174
switch self {
174175
case .native: return false
176+
case .swiftbuild: return false
175177
case .xcode: return true
176178
}
177179
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import SPMBuildCore
2+
import PackageModel
3+
4+
extension BuildConfiguration {
5+
public var swiftbuildName: String {
6+
switch self {
7+
case .debug: "Debug"
8+
case .release: "Release"
9+
}
10+
}
11+
}
12+
13+
extension BuildSubset {
14+
var pifTargetName: String {
15+
switch self {
16+
case .product(let name, _):
17+
PackagePIFProjectBuilder.targetName(for: name)
18+
case .target(let name, _):
19+
name
20+
case .allExcludingTests:
21+
PIFBuilder.allExcludingTestsTargetName
22+
case .allIncludingTests:
23+
PIFBuilder.allIncludingTestsTargetName
24+
}
25+
}
26+
}
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# This source file is part of the Swift open source project
2+
#
3+
# Copyright (c) 2025 Apple Inc. and the Swift project authors
4+
# Licensed under Apache License v2.0 with Runtime Library Exception
5+
#
6+
# See http://swift.org/LICENSE.txt for license information
7+
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
8+
9+
add_library(SwiftBuildSupport STATIC
10+
PIF.swift
11+
PIFBuilder.swift
12+
BuildSystem.swift
13+
SwiftBuildSystem.swift)
14+
target_link_libraries(SwiftBuildSupport PUBLIC
15+
Build
16+
DriverSupport
17+
TSCBasic
18+
TSCUtility
19+
PackageGraph
20+
)
21+
22+
set_target_properties(SwiftBuildSupport PROPERTIES
23+
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})

0 commit comments

Comments
 (0)