|
13 | 13 | import Basics |
14 | 14 | import Foundation |
15 | 15 | import TSCUtility |
| 16 | +import enum TSCBasic.JSON |
16 | 17 |
|
17 | 18 | import class Basics.AsyncProcess |
18 | 19 |
|
@@ -74,6 +75,9 @@ public final class UserToolchain: Toolchain { |
74 | 75 |
|
75 | 76 | public let targetTriple: Basics.Triple |
76 | 77 |
|
| 78 | + // A version string that can be used to identify the swift compiler version |
| 79 | + public let swiftCompilerVersion: String? |
| 80 | + |
77 | 81 | /// The list of CPU architectures to build for. |
78 | 82 | public let architectures: [String]? |
79 | 83 |
|
@@ -160,6 +164,75 @@ public final class UserToolchain: Toolchain { |
160 | 164 | return try getTool(name, binDirectories: envSearchPaths, fileSystem: fileSystem) |
161 | 165 | } |
162 | 166 |
|
| 167 | + private static func getTargetInfo(swiftCompiler: AbsolutePath) throws -> JSON { |
| 168 | + // Call the compiler to get the target info JSON. |
| 169 | + let compilerOutput: String |
| 170 | + do { |
| 171 | + let result = try AsyncProcess.popen(args: swiftCompiler.pathString, "-print-target-info") |
| 172 | + compilerOutput = try result.utf8Output().spm_chomp() |
| 173 | + } catch { |
| 174 | + throw InternalError( |
| 175 | + "Failed to load target info (\(error.interpolationDescription))" |
| 176 | + ) |
| 177 | + } |
| 178 | + // Parse the compiler's JSON output. |
| 179 | + do { |
| 180 | + return try JSON(string: compilerOutput) |
| 181 | + } catch { |
| 182 | + throw InternalError( |
| 183 | + "Failed to parse target info (\(error.interpolationDescription)).\nRaw compiler output: \(compilerOutput)" |
| 184 | + ) |
| 185 | + } |
| 186 | + } |
| 187 | + |
| 188 | + private static func getHostTriple(targetInfo: JSON) throws -> Basics.Triple { |
| 189 | + // Get the triple string from the target info. |
| 190 | + let tripleString: String |
| 191 | + do { |
| 192 | + tripleString = try targetInfo.get("target").get("triple") |
| 193 | + } catch { |
| 194 | + throw InternalError( |
| 195 | + "Target info does not contain a triple string (\(error.interpolationDescription)).\nTarget info: \(targetInfo)" |
| 196 | + ) |
| 197 | + } |
| 198 | + |
| 199 | + // Parse the triple string. |
| 200 | + do { |
| 201 | + return try Triple(tripleString) |
| 202 | + } catch { |
| 203 | + throw InternalError( |
| 204 | + "Failed to parse triple string (\(error.interpolationDescription)).\nTriple string: \(tripleString)" |
| 205 | + ) |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + private static func computeSwiftCompilerVersion(targetInfo: JSON) -> String? { |
| 210 | + // Get the compiler version from the target info |
| 211 | + let compilerVersion: String |
| 212 | + do { |
| 213 | + compilerVersion = try targetInfo.get("compilerVersion") |
| 214 | + } catch { |
| 215 | + return nil |
| 216 | + } |
| 217 | + |
| 218 | + // Extract the swift version using regex from the description if available |
| 219 | + do { |
| 220 | + let regex = try Regex(#"\((swift(lang)?-[^ )]*)"#) |
| 221 | + if let match = try regex.firstMatch(in: compilerVersion), match.count > 1, let substring = match[1].substring { |
| 222 | + return String(substring) |
| 223 | + } |
| 224 | + |
| 225 | + let regex2 = try Regex(#"\(.*Swift (.*)[ )]"#) |
| 226 | + if let match2 = try regex2.firstMatch(in: compilerVersion), match2.count > 1, let substring = match2[1].substring { |
| 227 | + return "swift-\(substring)" |
| 228 | + } else { |
| 229 | + return nil |
| 230 | + } |
| 231 | + } catch { |
| 232 | + return nil |
| 233 | + } |
| 234 | + } |
| 235 | + |
163 | 236 | // MARK: - public API |
164 | 237 |
|
165 | 238 | public static func determineLibrarian( |
@@ -570,6 +643,7 @@ public final class UserToolchain: Toolchain { |
570 | 643 | swiftSDK: SwiftSDK, |
571 | 644 | environment: Environment = .current, |
572 | 645 | searchStrategy: SearchStrategy = .default, |
| 646 | + customTargetInfo: JSON? = nil, |
573 | 647 | customLibrariesLocation: ToolchainConfiguration.SwiftPMLibrariesLocation? = nil, |
574 | 648 | customInstalledSwiftPMConfiguration: InstalledSwiftPMConfiguration? = nil, |
575 | 649 | fileSystem: any FileSystem = localFileSystem |
@@ -612,8 +686,14 @@ public final class UserToolchain: Toolchain { |
612 | 686 | default: InstalledSwiftPMConfiguration.default) |
613 | 687 | } |
614 | 688 |
|
615 | | - // Use the triple from Swift SDK or compute the host triple using swiftc. |
616 | | - var triple = try swiftSDK.targetTriple ?? Triple.getHostTriple(usingSwiftCompiler: swiftCompilers.compile) |
| 689 | + // targetInfo from the compiler |
| 690 | + let targetInfo = try customTargetInfo ?? Self.getTargetInfo(swiftCompiler: swiftCompilers.compile) |
| 691 | + |
| 692 | + // Get compiler version information from target info |
| 693 | + self.swiftCompilerVersion = Self.computeSwiftCompilerVersion(targetInfo: targetInfo) |
| 694 | + |
| 695 | + // Use the triple from Swift SDK or compute the host triple from the target info |
| 696 | + var triple = try swiftSDK.targetTriple ?? Self.getHostTriple(targetInfo: targetInfo) |
617 | 697 |
|
618 | 698 | // Change the triple to the specified arch if there's exactly one of them. |
619 | 699 | // The Triple property is only looked at by the native build system currently. |
|
0 commit comments