-
Notifications
You must be signed in to change notification settings - Fork 187
Expand file tree
/
Copy pathCommandLineToolSpecDiscoveredInfoTests.swift
More file actions
326 lines (289 loc) · 17.6 KB
/
Copy pathCommandLineToolSpecDiscoveredInfoTests.swift
File metadata and controls
326 lines (289 loc) · 17.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import Foundation
@_spi(Testing) import SWBCore
import SWBProtocol
import SWBTestSupport
import SWBUtil
import Testing
import SWBMacro
@Suite fileprivate struct CommandLineToolSpecDiscoveredInfoTests: CoreBasedTests {
@Test(.skipHostOS(.windows, "Failed to obtain command line tool spec info but no errors were emitted"))
func discoveredClangSpecInfo() async throws {
try await withSpec("com.apple.compilers.llvm.clang.1_0", .deferred) { (info: DiscoveredClangToolSpecInfo) in
#expect(!info.toolPath.isEmpty)
#if canImport(Darwin)
#expect(info.clangVersion != nil)
#endif
if let clangVersion = info.clangVersion {
#expect(clangVersion > Version(0, 0, 0, 0))
}
#if canImport(Darwin)
#expect(info.llvmVersion != nil)
#endif
if let llvmVersion = info.llvmVersion {
#expect(llvmVersion > Version(0, 0, 0))
}
}
// undefined_arch + sysroot=nil
try await withSpec("com.apple.compilers.llvm.clang.1_0", .result(status: .exit(0), stdout: Data("#define __clang_version__ \"8.1.0 (clang-802.1.38)\"".utf8), stderr: Data())) { (info: DiscoveredClangToolSpecInfo) in
#expect(info.toolPath.basename == "clang")
#expect(info.clangVersion == Version(802, 1, 38))
#expect(info.llvmVersion == Version(8, 1))
}
try await withSpec("com.apple.compilers.llvm.clang.1_0", .result(status: .exit(0), stdout: Data("#define __clang_version__ \"12.0.0 (clang-1200.0.31.1)\"".utf8), stderr: Data())) { (info: DiscoveredClangToolSpecInfo) in
#expect(info.toolPath.basename == "clang")
#expect(info.clangVersion == Version(1200, 0, 31, 1))
#expect(info.llvmVersion == Version(12))
}
try await withSpec("com.apple.compilers.llvm.clang.1_0", .result(status: .exit(0), stdout: Data("#define __clang_version__ \"12.0.0 (clang-1200.0.22.5) [ptrauth objc isa mode: sign-and-strip]\"".utf8), stderr: Data())) { (info: DiscoveredClangToolSpecInfo) in
#expect(info.toolPath.basename == "clang")
#expect(info.clangVersion == Version(1200, 0, 22, 5))
#expect(info.llvmVersion == Version(12))
}
try await withSpec("com.apple.compilers.llvm.clang.1_0", .result(status: .exit(0), stdout: Data("#define __clang_version__ \"11.0.3 (clang-1103.0.29.20) (-macos10.15-objc-selector-opts)\"".utf8), stderr: Data())) { (info: DiscoveredClangToolSpecInfo) in
#expect(info.toolPath.basename == "clang")
#expect(info.clangVersion == Version(1103, 0, 29, 20))
#expect(info.llvmVersion == Version(11, 0, 3))
}
try await withSpec("com.apple.compilers.llvm.clang.1_0", .result(status: .exit(0), stdout: Data("#define __clang_version__ \"17.0.0 (https://github.com/swiftlang/llvm-project.git 5bbcb7bc1701d40b9189d124d910b64009665cc0)\"".utf8), stderr: Data())) { (info: DiscoveredClangToolSpecInfo) in
#expect(info.toolPath.basename == "clang")
#expect(info.clangVersion == nil)
#expect(info.llvmVersion == Version(17))
}
try await withSpec("com.apple.compilers.llvm.clang.1_0", .result(status: .exit(0), stdout: Data("#define __clang_version__ \"19.0.0 (https://android.googlesource.com/toolchain/llvm-project 97a699bf4812a18fb657c2779f5296a4ab2694d2)\"".utf8), stderr: Data())) { (info: DiscoveredClangToolSpecInfo) in
#expect(info.toolPath.basename == "clang")
#expect(info.clangVersion == nil)
#expect(info.llvmVersion == Version(19))
}
}
@Test
func discoveredClangSpecInfoAcrossToolchains() async throws {
let core = try await getCore()
let toolchains = core.toolchainRegistry.toolchains
#expect(toolchains.count > 0) // must be at least one toolchain (default)
for toolchain in toolchains.sorted(by: \.identifier) {
if toolchain.identifier == "qnx" {
// QNX toolchains do not have clang
continue
}
let clangPath = try #require(toolchain.executableSearchPaths.findExecutable(operatingSystem: core.hostOperatingSystem, basename: "clang"), "Unable to find clang in search paths for toolchain '\(toolchain.identifier)': \(toolchain.executableSearchPaths.environmentRepresentation)")
let info = try await discoveredClangToolInfo(toolPath: clangPath, arch: "undefined_arch", sysroot: nil)
#expect(info.toolPath == clangPath)
#if canImport(Darwin)
if toolchain.identifier.hasPrefix("org.swift.") || toolchain.identifier.hasPrefix("org.swiftwasm.") {
#expect(info.clangVersion == nil, "Open Source toolchains are expected to NOT have a clang version")
} else if toolchain.identifier == "android" {
#expect(info.clangVersion == nil, "Android toolchains are expected to NOT have a clang version")
} else {
#expect(info.clangVersion != nil, "Unable to find clang version for toolchain \(toolchain.identifier). Used clang at path \(clangPath.str).")
}
#expect(info.llvmVersion != nil, "Unable to find llvm version for toolchain \(toolchain.identifier). Used clang at path \(clangPath.str).")
#endif
}
}
@Test
func discoveredSwiftSpecInfo() async throws {
let core = try await getCore()
try await withSpec(SwiftCompilerSpec.self, .deferred) { (info: DiscoveredSwiftCompilerToolSpecInfo) in
#expect(info.toolPath.basename == core.hostOperatingSystem.imageFormat.executableName(basename: "swiftc"))
#expect(info.swiftVersion > Version(0, 0, 0))
#expect(!info.swiftTag.isEmpty)
#expect(info.swiftABIVersion == nil)
}
try await withSpec(SwiftCompilerSpec.self, .result(status: .exit(0), stdout: Data("Swift version 5.9-dev (LLVM fd31e7eab45779f, Swift 86e6bda88e47178)\n".utf8), stderr: Data())) { (info: DiscoveredSwiftCompilerToolSpecInfo) in
#expect(info.toolPath.basename == core.hostOperatingSystem.imageFormat.executableName(basename: "swiftc"))
#expect(info.swiftVersion == Version(5, 9))
#expect(info.swiftTag == "LLVM fd31e7eab45779f, Swift 86e6bda88e47178")
}
try await withSpec(SwiftCompilerSpec.self, .result(status: .exit(0), stdout: Data("Swift version 5.9 (Swift 86e6bda88e47178 LLVM fd31e7eab45779f)\n".utf8), stderr: Data())) { (info: DiscoveredSwiftCompilerToolSpecInfo) in
#expect(info.toolPath.basename == core.hostOperatingSystem.imageFormat.executableName(basename: "swiftc"))
#expect(info.swiftVersion == Version(5, 9))
#expect(info.swiftTag == "Swift 86e6bda88e47178 LLVM fd31e7eab45779f")
}
try await withSpec(SwiftCompilerSpec.self, .result(status: .exit(0), stdout: Data("Swift version 6.2 (swift-6.2-DEVELOPMENT-SNAPSHOT-2025-05-15-a)\n".utf8), stderr: Data())) { (info: DiscoveredSwiftCompilerToolSpecInfo) in
#expect(info.toolPath.basename == core.hostOperatingSystem.imageFormat.executableName(basename: "swiftc"))
#expect(info.swiftVersion == Version(6, 2))
#expect(info.swiftTag == "swift-6.2-DEVELOPMENT-SNAPSHOT-2025-05-15-a")
}
try await withSpec(SwiftCompilerSpec.self, .result(status: .exit(0), stdout: Data("Apple Swift version 5.9 (swiftlang-5.9.0.106.53 clang-1500.0.13.6)\n".utf8), stderr: Data("swift-driver version: 1.80 ".utf8))) { (info: DiscoveredSwiftCompilerToolSpecInfo) in
#expect(info.toolPath.basename == core.hostOperatingSystem.imageFormat.executableName(basename: "swiftc"))
#expect(info.swiftVersion == Version(5, 9))
#expect(info.swiftTag == "swiftlang-5.9.0.106.53 clang-1500.0.13.6")
}
try await withSpec(SwiftCompilerSpec.self, .result(status: .exit(0), stdout: Data("Swift version 5.10.1 (swift-5.10.1-RELEASE)\nTarget: aarch64-unknown-linux-gnu\n".utf8), stderr: Data())) { (info: DiscoveredSwiftCompilerToolSpecInfo) in
#expect(info.toolPath.basename == core.hostOperatingSystem.imageFormat.executableName(basename: "swiftc"))
#expect(info.swiftVersion == Version(5, 10, 1))
#expect(info.swiftTag == "swift-5.10.1-RELEASE")
}
}
@Test
func discoveredSwiftABIToolsSpecInfo() async throws {
try await withSpec("com.apple.build-tools.swift-abi-checker", .deferred) { (info: DiscoveredSwiftCompilerToolSpecInfo) in
#expect(info.toolPath.basenameWithoutSuffix == "swiftc")
}
try await withSpec("com.apple.build-tools.swift-abi-generation", .deferred) { (info: DiscoveredSwiftCompilerToolSpecInfo) in
#expect(info.toolPath.basenameWithoutSuffix == "swiftc")
}
}
// Linker tool discovery is a bit more complex as it afffected by the ALTERNATE_LINKER build setting.
func ldMacroTable() async throws -> MacroValueAssignmentTable {
let core = try await getCore()
return MacroValueAssignmentTable(namespace: core.specRegistry.internalMacroNamespace)
}
@Test
func discoveredLdLinkerSpecInfo() async throws {
var table = try await ldMacroTable()
table.push(BuiltinMacros._LD_MULTIARCH, literal: true)
// Default Linker, just check we have one.
try await withSpec(LdLinkerSpec.self, .deferred, additionalTable: table) { (info: DiscoveredLdLinkerToolSpecInfo) in
#expect(!info.toolPath.isEmpty)
#expect(info.toolVersion != nil)
if let toolVersion = info.toolVersion {
#expect(toolVersion > Version(0, 0, 0))
}
}
}
@Test(.requireSDKs(.macOS))
func discoveredLdLinkerSpecInfo_macOS() async throws {
var table = try await ldMacroTable()
table.push(BuiltinMacros._LD_MULTIARCH, literal: true)
// Default Linker
try await withSpec(LdLinkerSpec.self, .deferred, additionalTable: table) { (info: DiscoveredLdLinkerToolSpecInfo) in
#expect(!info.toolPath.isEmpty)
#expect(info.toolVersion != nil)
if let toolVersion = info.toolVersion {
#expect(toolVersion > Version(0, 0, 0))
}
#expect(info.linker == .ld64)
// rdar://112109825 (ld_prime only reports arm64 and arm64e architectures in ld -version_details)
// let expectedArchs = Set(["armv7", "armv7k", "armv7s", "arm64", "arm64e", "i386", "x86_64"])
// XCTAssertEqual(info.architectures.intersection(expectedArchs), expectedArchs)
// XCTAssertFalse(info.architectures.contains("(tvOS)"))
}
}
@Test(.requireSDKs(.linux))
func discoveredLdLinkerSpecInfo_Linux() async throws {
var table = try await ldMacroTable()
table.push(BuiltinMacros._LD_MULTIARCH, literal: true)
// Default Linker
try await withSpec(LdLinkerSpec.self, .deferred, additionalTable: table) { (info: DiscoveredLdLinkerToolSpecInfo) in
#expect(!info.toolPath.isEmpty)
#expect(info.toolVersion != nil)
if let toolVersion = info.toolVersion {
#expect(toolVersion > Version(0, 0, 0))
}
#expect(info.linker == .gnuld)
}
try await withSpec(LdLinkerSpec.self, .result(status: .exit(0), stdout: Data("GNU ld (GNU Binutils for Debian) 2.40\n".utf8), stderr: Data()), additionalTable: table) { (info: DiscoveredLdLinkerToolSpecInfo) in
#expect(!info.toolPath.isEmpty)
#expect(info.toolVersion == Version(2, 40))
#expect(info.architectures == Set())
}
try await withSpec(LdLinkerSpec.self, .result(status: .exit(0), stdout: Data("GNU ld version 2.29.1-31.amzn2.0.1\n".utf8), stderr: Data()), additionalTable: table) { (info: DiscoveredLdLinkerToolSpecInfo) in
#expect(!info.toolPath.isEmpty)
#expect(info.toolVersion == Version(2, 29, 1))
#expect(info.architectures == Set())
}
// llvm-ld
table.push(BuiltinMacros.ALTERNATE_LINKER, literal: "lld")
try await withSpec(LdLinkerSpec.self, .deferred, additionalTable: table) { (info: DiscoveredLdLinkerToolSpecInfo) in
#expect(!info.toolPath.isEmpty)
#expect(info.toolVersion != nil)
if let toolVersion = info.toolVersion {
#expect(toolVersion > Version(0, 0, 0))
}
#expect(info.linker == .lld)
}
// gold
table.push(BuiltinMacros.ALTERNATE_LINKER, literal: "gold")
try await withSpec(LdLinkerSpec.self, .deferred, additionalTable: table) { (info: DiscoveredLdLinkerToolSpecInfo) in
#expect(!info.toolPath.isEmpty)
#expect(info.toolVersion != nil)
if let toolVersion = info.toolVersion {
#expect(toolVersion > Version(0, 0, 0))
}
#expect(info.linker == .gold)
}
}
@Test(.skipHostOS(.windows), .requireSystemPackages(apt: "libtool", dnf: "libtool", freebsd: "libtool", openbsd: "libtool"))
func discoveredLibtoolSpecInfo() async throws {
try await withSpec(LibtoolLinkerSpec.self, .deferred) { (info: DiscoveredLibtoolLinkerToolSpecInfo) in
#expect(info.toolPath.basename == "libtool")
#expect(info.toolVersion != nil)
if let toolVersion = info.toolVersion {
#expect(toolVersion > Version(0, 0, 0))
}
}
}
@Test(.requireSDKs(.macOS))
func discoveredLibtoolSpecInfoApple() async throws {
try await withSpec(LibtoolLinkerSpec.self, .result(status: .exit(0), stdout: Data("Apple Inc. version cctools-1008.2".utf8), stderr: Data()), platform: "macosx") { (info: DiscoveredLibtoolLinkerToolSpecInfo) in
#expect(info.toolPath.basename == "libtool")
let toolVersion = try #require(info.toolVersion)
#expect(toolVersion == Version(1008, 2))
}
try await withSpec(LibtoolLinkerSpec.self, .result(status: .exit(0), stdout: Data("Apple Inc. version cctools_sdk-1008.2".utf8), stderr: Data()), platform: "macosx") { (info: DiscoveredLibtoolLinkerToolSpecInfo) in
#expect(info.toolPath.basename == "libtool")
let toolVersion = try #require(info.toolVersion)
#expect(toolVersion == Version(1008, 2))
}
}
@Test(.requireSDKs(.linux))
func discoveredLibtoolSpecInfoLinux() async throws {
try await withSpec(LibtoolLinkerSpec.self, .result(status: .exit(0), stdout: Data("libtool (GNU libtool) 2.4.7\nWritten by AUTHOR, 1996\n\nCopyright (c) 2014 Free Software Foundation, Inc.\n\n".utf8), stderr: Data()), platform: "linux") { (info: DiscoveredLibtoolLinkerToolSpecInfo) in
#expect(info.toolPath.basename == "libtool")
let toolVersion = try #require(info.toolVersion)
#expect(toolVersion == Version(2, 4, 7))
}
}
@Test(.requireHostOS(.macOS))
func discoveredTAPISpecInfo() async throws {
try await withSpec("com.apple.build-tools.tapi.installapi", .deferred) { (info: DiscoveredTAPIToolSpecInfo) in
#expect(!info.toolPath.isEmpty)
#expect(info.toolVersion != nil)
if let toolVersion = info.toolVersion {
#expect(toolVersion > Version(0, 0, 0))
}
}
// ...and with fake data
try await withSpec("com.apple.build-tools.tapi.installapi", .result(status: .exit(0), stdout: Data("Apple TAPI version 15.0.0 (tapi-1500.0.9.1)".utf8), stderr: Data())) { (info: DiscoveredTAPIToolSpecInfo) in
#expect(info.toolPath.basename == "tapi")
let toolVersion = try #require(info.toolVersion)
#expect(toolVersion == Version(1500, 0, 9, 1))
}
try await withSpec("com.apple.build-tools.tapi.installapi", .result(status: .exit(0), stdout: Data("Apple TAPI version 15.0.0 (tapi-1500.0.8.4.3) (+internal-os)".utf8), stderr: Data())) { (info: DiscoveredTAPIToolSpecInfo) in
#expect(info.toolPath.basename == "tapi")
let toolVersion = try #require(info.toolVersion)
#expect(toolVersion == Version(1500, 0, 8, 4, 3))
}
}
@Test(.requireHostOS(.macOS))
func discoveredTAPIExtraToolsSpecInfo() async throws {
try await withSpec("com.apple.compilers.documentation.objc-symbol-extract", .deferred) { (info: DiscoveredTAPIToolSpecInfo) in
#expect(info.toolPath.basename == "tapi")
}
try await withSpec("com.apple.build-tools.tapi.merge", .deferred) { (info: DiscoveredTAPIToolSpecInfo) in
#expect(info.toolPath.basename == "tapi")
}
}
@Test(.skipHostOS(.windows)) // docc.exe is missing from the Swift toolchain distribution
func discoveredDoccSpecInfo() async throws {
let core = try await getCore()
// Once with the real tool
try await withSpec("com.apple.compilers.documentation", .deferred, { (info: DocumentationCompilerToolSpecInfo) in
#expect(info.toolPath.basename == core.hostOperatingSystem.imageFormat.executableName(basename: "docc"))
#expect(info.toolVersion == nil)
#expect(info.toolFeatures.has(.diagnosticsFile))
})
}
}