Skip to content

Commit a956af4

Browse files
committed
[PackageModel] Toolchain: Add a way to retrieve features supported by the Swift compiler
1 parent e8aff4b commit a956af4

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

Sources/PackageModel/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ add_library(PackageModel
5858
SwiftSDKs/SwiftSDKBundleStore.swift
5959
Toolchain.swift
6060
ToolchainConfiguration.swift
61+
Toolchain+SupportedFeatures.swift
6162
Toolset.swift
6263
ToolsVersion.swift
6364
ToolsVersionSpecificationGeneration.swift
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Basics
14+
15+
import enum TSCBasic.JSON
16+
import TSCUtility
17+
18+
public enum SwiftCompilerFeature {
19+
case upcoming(name: String, migratable: Bool, enabledIn: SwiftLanguageVersion)
20+
case experimental(name: String, migratable: Bool)
21+
22+
public var upcoming: Bool {
23+
switch self {
24+
case .upcoming: true
25+
case .experimental: false
26+
}
27+
}
28+
29+
public var experimental: Bool {
30+
switch self {
31+
case .upcoming: false
32+
case .experimental: true
33+
}
34+
}
35+
36+
public var name: String {
37+
switch self {
38+
case .upcoming(name: let name, migratable: _, enabledIn: _):
39+
name
40+
case .experimental(name: let name, migratable: _):
41+
name
42+
}
43+
}
44+
45+
public var migratable: Bool {
46+
switch self {
47+
case .upcoming(name: _, migratable: let migratable, enabledIn: _):
48+
migratable
49+
case .experimental(name: _, migratable: let migratable):
50+
migratable
51+
}
52+
}
53+
}
54+
55+
extension Toolchain {
56+
public var swiftCompilerSupportedFeatures: [SwiftCompilerFeature] {
57+
get throws {
58+
let compilerOutput: String
59+
do {
60+
let result = try AsyncProcess.popen(args: swiftCompilerPath.pathString, "-print-supported-features")
61+
compilerOutput = try result.utf8Output().spm_chomp()
62+
} catch {
63+
throw InternalError("Failed to get supported features info (\(error.interpolationDescription))")
64+
}
65+
66+
if compilerOutput.isEmpty {
67+
return []
68+
}
69+
70+
let parsedSupportedFeatures: JSON
71+
do {
72+
parsedSupportedFeatures = try JSON(string: compilerOutput)
73+
} catch {
74+
throw InternalError(
75+
"Failed to parse supported features info (\(error.interpolationDescription)).\nRaw compiler output: \(compilerOutput)"
76+
)
77+
}
78+
79+
let features: JSON = try parsedSupportedFeatures.get("features")
80+
81+
let upcoming: [SwiftCompilerFeature] = try features.getArray("upcoming").map {
82+
let name: String = try $0.get("name")
83+
let migratable: Bool? = $0.get("migratable")
84+
let enabledIn: String = try $0.get("enabled_in")
85+
86+
guard let mode = SwiftLanguageVersion(string: enabledIn) else {
87+
throw InternalError("Unknown swift language mode: \(enabledIn)")
88+
}
89+
90+
return .upcoming(
91+
name: name,
92+
migratable: migratable ?? false,
93+
enabledIn: mode
94+
)
95+
}
96+
97+
let experimental: [SwiftCompilerFeature] = try features.getArray("experimental").map {
98+
let name: String = try $0.get("name")
99+
let migratable: Bool? = $0.get("migratable")
100+
101+
return .experimental(
102+
name: name,
103+
migratable: migratable ?? false
104+
)
105+
}
106+
107+
return upcoming + experimental
108+
}
109+
}
110+
}

0 commit comments

Comments
 (0)