Skip to content

Commit a442e86

Browse files
committed
build: introduce SWIFTPM_BUILD_ONLY_TESTS support
This adds support for an environment variable to exclude all dependencies from being built. We can externally pass in the appropriate include and library search paths allowing us to control the build and share the artifacts from the previous build reducing overall cost in CI.
1 parent ff7ea75 commit a442e86

File tree

1 file changed

+114
-129
lines changed

1 file changed

+114
-129
lines changed

Package.swift

Lines changed: 114 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,91 @@
1515
import class Foundation.ProcessInfo
1616
import PackageDescription
1717

18-
// When building the toolchain on the CI for ELF platforms, remove the CI's
18+
func defined(_ variable: String) -> Bool {
19+
ProcessInfo.processInfo.environment[variable] != nil
20+
}
21+
22+
var buildOnlyTests: Bool {
23+
defined("SWIFTPM_BUILD_ONLY_TESTS")
24+
}
25+
26+
var useLocalDependencies: Bool {
27+
defined("SWIFTCI_USE_LOCAL_DEPS")
28+
}
29+
30+
var useLLBuildFramework: Bool {
31+
defined("SWIFTPM_LLBUILD_FWK")
32+
}
33+
34+
var useSwiftBuildFramework: Bool {
35+
defined("SWIFTPM_SWBUILD_FRAMEWORK")
36+
}
37+
38+
@MainActor
39+
func LLBuildFrameworkDependency<T>(enabled: [T] = [], disabled: [T] = []) -> [T] {
40+
if useLLBuildFramework { return enabled }
41+
return disabled
42+
}
43+
44+
@MainActor
45+
func SwiftBuildFrameworkDependency<T>(enabled: [T] = [], disabled: [T] = []) -> [T] {
46+
if useSwiftBuildFramework { return enabled }
47+
return disabled
48+
}
49+
50+
var dependencies: [Package.Dependency] {
51+
if buildOnlyTests { return [] }
52+
53+
if useLocalDependencies {
54+
return [
55+
.package(path: "../swift-argument-parser"),
56+
.package(path: "../swift-crypto"),
57+
.package(path: "../swift-syntax"),
58+
.package(path: "../swift-system"),
59+
.package(path: "../swift-collections"),
60+
.package(path: "../swift-certificates"),
61+
.package(path: "../swift-toolchain-sqlite"),
62+
] + LLBuildFrameworkDependency(disabled: [
63+
.package(name: "swift-llbuild", path: "../llbuild"),
64+
]) + SwiftBuildFrameworkDependency(enabled: [
65+
.package(path: "../swift-build"),
66+
], disabled: [
67+
.package(path: "../swift-tools-support-core"),
68+
.package(path: "../swift-driver"),
69+
])
70+
}
71+
72+
/// When not using local dependencies, the branch to use for llbuild and TSC
73+
/// repositories.
74+
let relatedDependenciesBranch = "main"
75+
76+
return [
77+
// The 'swift-argument-parser' version declared here must match that
78+
// used by 'swift-driver' and 'sourcekit-lsp'. Please coordinate
79+
// dependency version changes here with those projects.
80+
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.5.1")),
81+
.package(url: "https://github.com/apple/swift-crypto.git", .upToNextMinor(from: "3.0.0")),
82+
.package(url: "https://github.com/swiftlang/swift-syntax.git", branch: relatedDependenciesBranch),
83+
.package(url: "https://github.com/apple/swift-system.git", from: "1.1.1"),
84+
.package(url: "https://github.com/apple/swift-collections.git", "1.0.1" ..< "1.2.0"),
85+
.package(url: "https://github.com/apple/swift-certificates.git", "1.0.1" ..< "1.6.0"),
86+
.package(url: "https://github.com/swiftlang/swift-toolchain-sqlite.git", from: "1.0.0"),
87+
88+
// For use in previewing documentation
89+
.package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.1.0"),
90+
] + LLBuildFrameworkDependency(disabled: [
91+
.package(url: "https://github.com/swiftlang/swift-llbuild.git", branch: relatedDependenciesBranch),
92+
]) + SwiftBuildFrameworkDependency(enabled: [
93+
.package(url: "https://github.com/swiftlang/swift-build.git", branch: relatedDependenciesBranch),
94+
], disabled: [
95+
.package(url: "https://github.com/swiftlang/swift-tools-support-core.git", branch: relatedDependenciesBranch),
96+
.package(url: "https://github.com/swiftlang/swift-driver.git", branch: relatedDependenciesBranch),
97+
])
98+
}
99+
100+
101+
// When building the toolchain on the CI for ELF platforms, remove the CI's !=
102+
// nil
19103
// stdlib absolute runpath and add ELF's $ORIGIN relative paths before installing.
20104
let swiftpmLinkSettings: [LinkerSetting]
21105
let packageLibraryLinkSettings: [LinkerSetting]
@@ -101,39 +185,14 @@ if ProcessInfo.processInfo.environment["SWIFTCI_INSTALL_RPATH_OS"] == "android"
101185
*/
102186
let autoProducts = [swiftPMProduct, swiftPMDataModelProduct]
103187

104-
let shoudUseSwiftBuildFramework = (ProcessInfo.processInfo.environment["SWIFTPM_SWBUILD_FRAMEWORK"] != nil)
105-
106-
let swiftDriverDeps: [Target.Dependency]
107-
let swiftTSCBasicsDeps: [Target.Dependency]
108-
let swiftToolsCoreSupportAutoDeps: [Target.Dependency]
109-
let swiftTSCTestSupportDeps: [Target.Dependency]
110-
111-
if shoudUseSwiftBuildFramework {
112-
swiftDriverDeps = []
113-
swiftTSCBasicsDeps = []
114-
swiftToolsCoreSupportAutoDeps = []
115-
swiftTSCTestSupportDeps = []
116-
} else {
117-
swiftDriverDeps = [
118-
.product(name: "SwiftDriver", package: "swift-driver")
119-
]
120-
swiftTSCBasicsDeps = [
121-
.product(name: "TSCBasic", package: "swift-tools-support-core"),
122-
]
123-
swiftToolsCoreSupportAutoDeps = [
124-
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core")
125-
]
126-
swiftTSCTestSupportDeps = [
127-
.product(name: "TSCTestSupport", package: "swift-tools-support-core"),
128-
]
129-
}
130188
let package = Package(
131189
name: "SwiftPM",
132190
platforms: [
133191
.macOS(.v13),
134192
.iOS(.v17),
135193
.macCatalyst(.v17),
136194
],
195+
dependencies: dependencies,
137196
products:
138197
autoProducts.flatMap {
139198
(includeDynamicLibrary ? [
@@ -272,7 +331,9 @@ let package = Package(
272331
.product(name: "DequeModule", package: "swift-collections"),
273332
.product(name: "OrderedCollections", package: "swift-collections"),
274333
.product(name: "SystemPackage", package: "swift-system"),
275-
] + swiftToolsCoreSupportAutoDeps,
334+
] + SwiftBuildFrameworkDependency(disabled: [
335+
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core")
336+
]),
276337
exclude: ["CMakeLists.txt", "Vendor/README.md"],
277338
swiftSettings: swift6CompatibleExperimentalFeatures + [
278339
.enableExperimentalFeature("StrictConcurrency"),
@@ -323,7 +384,9 @@ let package = Package(
323384
.target(
324385
/** Shim for llbuild library */
325386
name: "SPMLLBuild",
326-
dependencies: ["Basics"],
387+
dependencies: ["Basics"] + LLBuildFrameworkDependency(disabled: [
388+
.product(name: "llbuildSwift", package: "swift-llbuild"),
389+
]),
327390
exclude: ["CMakeLists.txt"],
328391
swiftSettings: commonExperimentalFeatures + [
329392
.unsafeFlags(["-static"]),
@@ -335,7 +398,9 @@ let package = Package(
335398
name: "SwiftFixIt",
336399
dependencies: [
337400
"Basics",
338-
] + swiftTSCBasicsDeps + swiftSyntaxDependencies(
401+
] + SwiftBuildFrameworkDependency(disabled: [
402+
.product(name: "TSCBasic", package: "swift-tools-support-core"),
403+
]) + swiftSyntaxDependencies(
339404
["SwiftDiagnostics", "SwiftIDEUtils", "SwiftParser", "SwiftSyntax"]
340405
),
341406
exclude: ["CMakeLists.txt"],
@@ -349,7 +414,9 @@ let package = Package(
349414
name: "BinarySymbols",
350415
dependencies: [
351416
"Basics",
352-
] + swiftTSCBasicsDeps,
417+
] + SwiftBuildFrameworkDependency(disabled: [
418+
.product(name: "TSCBasic", package: "swift-tools-support-core"),
419+
]),
353420
exclude: ["CMakeLists.txt"],
354421
swiftSettings: commonExperimentalFeatures + [
355422
.unsafeFlags(["-static"]),
@@ -514,7 +581,9 @@ let package = Package(
514581
"SPMLLBuild",
515582
.product(name: "OrderedCollections", package: "swift-collections"),
516583
"DriverSupport",
517-
] + swiftDriverDeps,
584+
] + SwiftBuildFrameworkDependency(disabled: [
585+
.product(name: "SwiftDriver", package: "swift-driver")
586+
]),
518587
exclude: ["CMakeLists.txt"],
519588
swiftSettings: commonExperimentalFeatures + [
520589
.unsafeFlags(["-static"]),
@@ -525,7 +594,9 @@ let package = Package(
525594
dependencies: [
526595
"Basics",
527596
"PackageModel",
528-
] + swiftDriverDeps,
597+
] + SwiftBuildFrameworkDependency(disabled: [
598+
.product(name: "SwiftDriver", package: "swift-driver")
599+
]),
529600
exclude: ["CMakeLists.txt"],
530601
swiftSettings: commonExperimentalFeatures + [
531602
.unsafeFlags(["-static"]),
@@ -549,7 +620,11 @@ let package = Package(
549620
dependencies: [
550621
"SPMBuildCore",
551622
"PackageGraph",
552-
],
623+
] + SwiftBuildFrameworkDependency(enabled: [
624+
.product(name: "SwiftBuild", package: "swift-build"),
625+
// This is here to statically link the build service in the same executable as SwiftPM
626+
.product(name: "SWBBuildService", package: "swift-build"),
627+
]),
553628
exclude: ["CMakeLists.txt", "README.md"],
554629
swiftSettings: commonExperimentalFeatures
555630
),
@@ -825,7 +900,9 @@ let package = Package(
825900
"SourceControl",
826901
.product(name: "OrderedCollections", package: "swift-collections"),
827902
"Workspace",
828-
] + swiftTSCTestSupportDeps,
903+
] + SwiftBuildFrameworkDependency(disabled: [
904+
.product(name: "TSCTestSupport", package: "swift-tools-support-core"),
905+
]),
829906
swiftSettings: [
830907
.unsafeFlags(["-static"]),
831908
]
@@ -1012,7 +1089,7 @@ package.targets.append(contentsOf: [
10121089

10131090
// rdar://101868275 "error: cannot find 'XCTAssertEqual' in scope" can affect almost any functional test, so we flat out
10141091
// disable them all until we know what is going on
1015-
if ProcessInfo.processInfo.environment["SWIFTCI_DISABLE_SDK_DEPENDENT_TESTS"] == nil {
1092+
if !defined("SWIFTCI_DISABLE_SDK_DEPENDENT_TESTS") {
10161093
package.targets.append(contentsOf: [
10171094
.testTarget(
10181095
name: "FunctionalTests",
@@ -1060,109 +1137,17 @@ func swiftSyntaxDependencies(_ names: [String]) -> [Target.Dependency] {
10601137
/// This means that the swift-syntax symbols don't need to be statically linked, which allows us to stay below the
10611138
/// maximum number of exported symbols on Windows, in turn allowing us to build sourcekit-lsp using SwiftPM on Windows
10621139
/// and run its tests.
1063-
let buildDynamicSwiftSyntaxLibrary = ProcessInfo.processInfo.environment["SWIFTSYNTAX_BUILD_DYNAMIC_LIBRARY"] != nil
1140+
let buildDynamicSwiftSyntaxLibrary = defined("SWIFTSYNTAX_BUILD_DYNAMIC_LIBRARY")
10641141
if buildDynamicSwiftSyntaxLibrary {
10651142
return [.product(name: "_SwiftSyntaxDynamic", package: "swift-syntax")]
10661143
} else {
10671144
return names.map { .product(name: $0, package: "swift-syntax") }
10681145
}
10691146
}
10701147

1071-
// Add package dependency on llbuild when not bootstrapping.
1072-
//
1073-
// When bootstrapping SwiftPM, we can't use llbuild as a package dependency it
1074-
// will provided by whatever build system (SwiftCI, bootstrap script) is driving
1075-
// the build process. So, we only add these dependencies if SwiftPM is being
1076-
// built directly using SwiftPM. It is a bit unfortunate that we've add the
1077-
// package dependency like this but there is no other good way of expressing
1078-
// this right now.
1079-
1080-
/// When not using local dependencies, the branch to use for llbuild and TSC repositories.
1081-
let relatedDependenciesBranch = "main"
1082-
1083-
if ProcessInfo.processInfo.environment["SWIFTPM_LLBUILD_FWK"] == nil {
1084-
if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
1085-
package.dependencies += [
1086-
.package(url: "https://github.com/swiftlang/swift-llbuild.git", branch: relatedDependenciesBranch),
1087-
]
1088-
} else {
1089-
// In Swift CI, use a local path to llbuild to interoperate with tools
1090-
// like `update-checkout`, which control the sources externally.
1091-
package.dependencies += [
1092-
.package(name: "swift-llbuild", path: "../llbuild"),
1093-
]
1094-
}
1095-
package.targets.first(where: { $0.name == "SPMLLBuild" })!.dependencies += [
1096-
.product(name: "llbuildSwift", package: "swift-llbuild"),
1097-
]
1098-
}
1099-
1100-
if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
1101-
package.dependencies += [
1102-
// The 'swift-argument-parser' version declared here must match that
1103-
// used by 'swift-driver' and 'sourcekit-lsp'. Please coordinate
1104-
// dependency version changes here with those projects.
1105-
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.5.1")),
1106-
.package(url: "https://github.com/apple/swift-crypto.git", .upToNextMinor(from: "3.0.0")),
1107-
.package(url: "https://github.com/swiftlang/swift-syntax.git", branch: relatedDependenciesBranch),
1108-
.package(url: "https://github.com/apple/swift-system.git", from: "1.1.1"),
1109-
.package(url: "https://github.com/apple/swift-collections.git", "1.0.1" ..< "1.2.0"),
1110-
.package(url: "https://github.com/apple/swift-certificates.git", "1.0.1" ..< "1.6.0"),
1111-
.package(url: "https://github.com/swiftlang/swift-toolchain-sqlite.git", from: "1.0.0"),
1112-
// For use in previewing documentation
1113-
.package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.1.0"),
1114-
]
1115-
if !swiftDriverDeps.isEmpty {
1116-
package.dependencies += [
1117-
.package(url: "https://github.com/swiftlang/swift-tools-support-core.git", branch: relatedDependenciesBranch),
1118-
.package(url: "https://github.com/swiftlang/swift-driver.git", branch: relatedDependenciesBranch),
1119-
]
1120-
}
1121-
} else {
1122-
package.dependencies += [
1123-
.package(path: "../swift-argument-parser"),
1124-
.package(path: "../swift-crypto"),
1125-
.package(path: "../swift-syntax"),
1126-
.package(path: "../swift-system"),
1127-
.package(path: "../swift-collections"),
1128-
.package(path: "../swift-certificates"),
1129-
.package(path: "../swift-toolchain-sqlite"),
1130-
]
1131-
if !swiftDriverDeps.isEmpty {
1132-
package.dependencies += [
1133-
.package(path: "../swift-tools-support-core"),
1134-
.package(path: "../swift-driver"),
1135-
]
1136-
}
1137-
1138-
}
1139-
11401148
/// If ENABLE_APPLE_PRODUCT_TYPES is set in the environment, then also define ENABLE_APPLE_PRODUCT_TYPES in each of the regular targets and test targets.
11411149
if ProcessInfo.processInfo.environment["ENABLE_APPLE_PRODUCT_TYPES"] == "1" {
11421150
for target in package.targets.filter({ $0.type == .regular || $0.type == .test }) {
11431151
target.swiftSettings = (target.swiftSettings ?? []) + [ .define("ENABLE_APPLE_PRODUCT_TYPES") ]
11441152
}
11451153
}
1146-
1147-
if !shoudUseSwiftBuildFramework {
1148-
1149-
let swiftbuildsupport: Target = package.targets.first(where: { $0.name == "SwiftBuildSupport" } )!
1150-
swiftbuildsupport.dependencies += [
1151-
.product(name: "SwiftBuild", package: "swift-build"),
1152-
]
1153-
1154-
swiftbuildsupport.dependencies += [
1155-
// This is here to statically link the build service in the same executable as SwiftPM
1156-
.product(name: "SWBBuildService", package: "swift-build"),
1157-
]
1158-
1159-
if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
1160-
package.dependencies += [
1161-
.package(url: "https://github.com/swiftlang/swift-build.git", branch: relatedDependenciesBranch),
1162-
]
1163-
} else {
1164-
package.dependencies += [
1165-
.package(path: "../swift-build"),
1166-
]
1167-
}
1168-
}

0 commit comments

Comments
 (0)