11import Foundation
22import Subprocess
33import XUtils
4+ import Superutils
45
56public struct BuildSettings : Sendable {
67 private static let customBinDir =
78 // this is the same option used by SwiftPM itself for dev builds
89 ProcessInfo . processInfo. environment [ " SWIFTPM_CUSTOM_BIN_DIR " ] . map { FilePath ( $0) }
910
10- private static let envURL = URL ( fileURLWithPath: " /usr/bin/env " )
11-
12- public let packagePath : String
11+ public var packagePath : String
1312 public let configuration : BuildConfiguration
1413 public let triple : String
15- public let sdkOptions : [ String ]
16- public let options : [ String ]
14+ public let buildSystem : BuildSystem
15+ public let customOptions : [ String ]
16+
17+ public var sdkOptions : [ String ]
18+ public var sdkEnvironment : [ Environment . Key : String ? ]
19+
20+ private var configOptions : [ String ] {
21+ return [
22+ " --configuration " , configuration. rawValue,
23+ " --build-system " , buildSystem. pmName,
24+ " --package-path " , packagePath,
25+ ]
26+ }
27+
28+ private var resolvedBaseOptions : [ String ] {
29+ configOptions + sdkOptions + customOptions
30+ }
1731
1832 public init (
1933 configuration: BuildConfiguration ,
2034 triple: String ,
35+ buildSystem: BuildSystem = . default,
2136 packagePath: String = " . " ,
2237 options: [ String ] = [ ]
2338 ) async throws {
2439 self . packagePath = packagePath
2540 self . configuration = configuration
26- self . options = options
41+ self . customOptions = options
2742 self . triple = triple
43+ self . buildSystem = buildSystem
44+
45+ self . sdkEnvironment = [
46+ // xcrun passes an SDKROOT that messes with our sdk configuration
47+ " SDKROOT " : nil ,
48+ ]
2849
29- // on macOS we don't explicitly install a Swift SDK but
30- // SwiftPM vends "implicit" Darwin SDKs as of Swift 6.1,
31- // i.e. we can pass `--swift-sdk arm64-apple-ios` and it
32- // just works. See:
33- // https://github.com/swiftlang/swift-package-manager/pull/6828
34- self . sdkOptions = [ " --swift-sdk " , triple]
50+ switch buildSystem {
51+ case . swiftPM:
52+ // on macOS we don't explicitly install a Swift SDK but
53+ // SwiftPM vends "implicit" Darwin SDKs as of Swift 6.1,
54+ // i.e. we can pass `--swift-sdk arm64-apple-ios` and it
55+ // just works. See:
56+ // https://github.com/swiftlang/swift-package-manager/pull/6828
57+ self . sdkOptions = [ " --swift-sdk " , triple]
58+ case . swiftBuild:
59+ self . sdkOptions = [ " --triple " , triple]
60+ #if !os(macOS)
61+ let darwinSDK = try await DarwinSDK . current ( )
62+ . orThrow ( StringError ( " No Darwin SDK configured. Please run `xtool setup`. " ) )
63+ self . sdkOptions += [
64+ " --toolset " , " \( darwinSDK. bundle. path) /toolset-swb.json " ,
65+ ]
66+ self . sdkEnvironment. merge ( [
67+ " XCODE_EXTRA_PLATFORM_FOLDERS " : " \( darwinSDK. bundle. path) /Developer/Platforms " ,
68+ ] ) { $1 }
69+ #endif
70+ }
3571 }
3672
3773 #if os(macOS)
@@ -44,15 +80,40 @@ public struct BuildSettings: Sendable {
4480 return result. standardOutput? . trimmingCharacters ( in: . whitespacesAndNewlines) ?? " "
4581 }
4682
47- private static let swiftURL = Task {
83+ private static let _swiftURL = Task {
4884 try await FilePath ( xcrun ( [ " -f " , " swift " ] ) )
4985 }
86+
87+ public static func swiftURL( ) async throws -> FilePath {
88+ try await _swiftURL. value
89+ }
90+
91+ private static let _swiftcURL = Task {
92+ try await FilePath ( xcrun ( [ " -f " , " swiftc " ] ) )
93+ }
94+
95+ public static func swiftcURL( ) async throws -> FilePath {
96+ try await _swiftcURL. value
97+ }
98+ #else
99+ public static func swiftURL( ) async throws -> FilePath {
100+ try await FilePath ( ToolRegistry . locate ( " swift " ) ) . orThrow ( StringError ( " Got bad path for swift executable " ) )
101+ }
102+
103+ public static func swiftcURL( ) async throws -> FilePath {
104+ try await FilePath ( ToolRegistry . locate ( " swiftc " ) ) . orThrow ( StringError ( " Got bad path for swiftc executable " ) )
105+ }
50106 #endif
51107
108+ public func withPackagePath( _ path: String ) -> Self {
109+ var copy = self
110+ copy. packagePath = path
111+ return copy
112+ }
113+
52114 public func swiftPMInvocation(
53115 forTool tool: String ,
54116 arguments: [ String ] ,
55- packagePathOverride: String ? = nil
56117 ) async throws -> Subprocess . Configuration {
57118 let executable : Executable
58119 let baseArguments : [ String ]
@@ -65,35 +126,60 @@ public struct BuildSettings: Sendable {
65126 // to add SDKROOT=.../MacOSX.sdk to our invocations. We avoid this by
66127 // 1) invoking the real swift executable (located with `xcrun -f`) and
67128 // 2) explicitly removing SDKROOT from the env, as it may be inherited
68- // through the `swift run pack` invocation .
69- executable = . path( try await Self . swiftURL. value )
129+ // through a parent process (e.g. `swift run xtool`) .
130+ executable = . path( try await Self . swiftURL ( ) )
70131 #else
71132 executable = . name( " swift " )
72133 #endif
73134 baseArguments = [ tool]
74135 }
75136
76- let extraArguments : [ String ] = [
77- " --package-path " , packagePathOverride ?? packagePath,
78- " --configuration " , configuration. rawValue,
79- ]
80-
81- var rawEnv = ProcessInfo . processInfo. environment
82- rawEnv. removeValue ( forKey: " SDKROOT " )
83- let env = Dictionary ( uniqueKeysWithValues: rawEnv. map {
84- ( Environment . Key ( rawValue: $0) !, $1)
85- } )
86-
87137 return Configuration (
88138 executable,
89- arguments: . init( baseArguments + extraArguments + sdkOptions + options + arguments) ,
90- environment: . custom ( env ) ,
139+ arguments: . init( baseArguments + resolvedBaseOptions + arguments) ,
140+ environment: . inherit . updating ( sdkEnvironment ) ,
91141 platformOptions: . withGracefulShutDown,
92142 )
93143 }
144+
145+ public var buildServerArguments : [ String ] {
146+ return [
147+ " package " , " experimental-build-server " ,
148+ " --disable-automatic-resolution " ,
149+ // TODO: once https://github.com/swiftlang/swift-package-manager/pull/9819 makes it into a release
150+ // (Swift 6.4), pass --experimental-skip-acquiring-lock
151+ ] + resolvedBaseOptions
152+ }
94153}
95154
96155public enum BuildConfiguration : String , CaseIterable , Sendable {
97156 case debug
98157 case release
158+
159+ var swiftBuildValue : String {
160+ switch self {
161+ case . debug: " Debug "
162+ case . release: " Release "
163+ }
164+ }
165+ }
166+
167+ public enum BuildSystem : Sendable {
168+ case swiftPM
169+ case swiftBuild
170+
171+ public static var `default` : Self {
172+ #if os(macOS)
173+ return . swiftBuild
174+ #else
175+ return . swiftBuild
176+ #endif
177+ }
178+
179+ var pmName : String {
180+ switch self {
181+ case . swiftPM: " native "
182+ case . swiftBuild: " swiftbuild "
183+ }
184+ }
99185}
0 commit comments