Skip to content

Commit 349caaf

Browse files
Add missing libcurl4-openssl-dev dependency in Ubuntu/Debian packages, add more EndToEnd testcases (#236)
As outlined in #197, the generator was not downloading the needed `libcurl4-openssl-dev` dependency that is required to statically link `FoundationNetworking` with `--static-swift-stdlib`. This PR adds the needed dependency for all supported Ubuntu and Debian versions with a little bit of refactoring in `LinuxDistribution.swift` to reduce duplication of common dependencies across versions. I also added an additional testcase in the `EndToEndTests` to verify this curl dependency is available and works. With this change is some improvements to the logging of the EndToEndTests, so we end up with the following output: ``` 2025-08-15T13:42:09+0000 info EndToEndTests: temporaryDirectory=/tmp/6E93604C-CC84-4E25-A67E-F947CE19D282 [SwiftSDKGeneratorTests] Created temporary directory 2025-08-15T13:42:09+0000 info EndToEndTests: scratchPath=/tmp/6E93604C-CC84-4E25-A67E-F947CE19D282 [SwiftSDKGeneratorTests] Building SDK generator 2025-08-15T13:44:22+0000 info EndToEndTests: runArguments=--sdk-name ubuntu_24.04_x86_64_6.1-RELEASE --host-toolchain --swift-version 6.1-RELEASE --target x86_64-unknown-linux-gnu --distribution-name ubuntu --distribution-version 24.04 scratchPath=/tmp/6E93604C-CC84-4E25-A67E-F947CE19D282 [SwiftSDKGeneratorTests] Building Swift SDK 2025-08-15T13:45:35+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE scratchPath=/tmp/6E93604C-CC84-4E25-A67E-F947CE19D282 [SwiftSDKGeneratorTests] Installing new Swift SDK 2025-08-15T13:45:50+0000 info EndToEndTests: temporaryDirectory=/tmp/6E93604C-CC84-4E25-A67E-F947CE19D282 [SwiftSDKGeneratorTests] Removed temporary directory 2025-08-15T13:45:50+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE [SwiftSDKGeneratorTests] Running test cases... 2025-08-15T13:45:50+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE temporaryDirectory=/tmp/8688FF7E-C08E-4ED6-A218-304D4AB9D88E testcase=helloWorld [SwiftSDKGeneratorTests] Created temporary directory 2025-08-15T13:45:50+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=helloWorld [SwiftSDKGeneratorTests] Creating test project /tmp/8688FF7E-C08E-4ED6-A218-304D4AB9D88E/swift-sdk-generator-test 2025-08-15T13:45:50+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=helloWorld [SwiftSDKGeneratorTests] Building test project 2025-08-15T13:46:08+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=helloWorld [SwiftSDKGeneratorTests] Test project built successfully 2025-08-15T13:46:08+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=helloWorld [SwiftSDKGeneratorTests] Building test project with static-swift-stdlib 2025-08-15T13:46:11+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=helloWorld [SwiftSDKGeneratorTests] Test project built successfully 2025-08-15T13:46:11+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE temporaryDirectory=/tmp/8688FF7E-C08E-4ED6-A218-304D4AB9D88E testcase=helloWorld [SwiftSDKGeneratorTests] Removed temporary directory 2025-08-15T13:46:11+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE temporaryDirectory=/tmp/312A6E7E-95DF-4BCE-8D18-9E7EF1D163F6 testcase=curlDependency [SwiftSDKGeneratorTests] Created temporary directory 2025-08-15T13:46:11+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=curlDependency [SwiftSDKGeneratorTests] Creating test project /tmp/312A6E7E-95DF-4BCE-8D18-9E7EF1D163F6/swift-sdk-generator-test 2025-08-15T13:46:11+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=curlDependency [SwiftSDKGeneratorTests] Building test project 2025-08-15T13:46:19+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=curlDependency [SwiftSDKGeneratorTests] Test project built successfully 2025-08-15T13:46:19+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=curlDependency [SwiftSDKGeneratorTests] Building test project with static-swift-stdlib 2025-08-15T13:46:24+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=curlDependency [SwiftSDKGeneratorTests] Test project built successfully 2025-08-15T13:46:24+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE temporaryDirectory=/tmp/312A6E7E-95DF-4BCE-8D18-9E7EF1D163F6 testcase=curlDependency [SwiftSDKGeneratorTests] Removed temporary directory 2025-08-15T13:46:24+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE temporaryDirectory=/tmp/4B1AB5C9-3C87-4258-8BA0-97B305B59970 testcase=libcNonshared [SwiftSDKGeneratorTests] Created temporary directory 2025-08-15T13:46:24+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=libcNonshared [SwiftSDKGeneratorTests] Creating test project /tmp/4B1AB5C9-3C87-4258-8BA0-97B305B59970/swift-sdk-generator-test 2025-08-15T13:46:24+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=libcNonshared [SwiftSDKGeneratorTests] Building test project 2025-08-15T13:46:30+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=libcNonshared [SwiftSDKGeneratorTests] Test project built successfully 2025-08-15T13:46:30+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=libcNonshared [SwiftSDKGeneratorTests] Building test project with static-swift-stdlib 2025-08-15T13:46:36+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE testcase=libcNonshared [SwiftSDKGeneratorTests] Test project built successfully 2025-08-15T13:46:36+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE temporaryDirectory=/tmp/4B1AB5C9-3C87-4258-8BA0-97B305B59970 testcase=libcNonshared [SwiftSDKGeneratorTests] Removed temporary directory 2025-08-15T13:46:36+0000 info EndToEndTests: bundleName=ubuntu_24.04_x86_64_6.1-RELEASE [SwiftSDKGeneratorTests] Removing Swift SDK to clean up... warning: `swift experimental-sdk` command is deprecated and will be removed in a future version of SwiftPM. Use `swift sdk` instead. ``` If you notice in the above, we now have: - Separate logging of building the SDK generator and actually building the Swift SDK. - Cleaner logging of removing and installing Swift SDKs. - Each testcase now has a key that gives the name of the testcase, that is logged in the "testcase" metadata key to identify which may work or fail. - Testcases are run concurrently with a throwing task group. As we add more testcases in the future this helps to reduce the time it takes to run each case.
1 parent 77b1dd9 commit 349caaf

File tree

2 files changed

+77
-70
lines changed

2 files changed

+77
-70
lines changed

Sources/SwiftSDKGenerator/PlatformModels/LinuxDistribution.swift

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -50,49 +50,41 @@ public enum LinuxDistribution: Hashable, Sendable {
5050
}
5151
}
5252

53+
private var commonPackages: [String] {
54+
[
55+
"libc6",
56+
"libc6-dev",
57+
"libgcc-s1",
58+
"libstdc++6",
59+
"linux-libc-dev",
60+
"zlib1g",
61+
"zlib1g-dev",
62+
"libcurl4-openssl-dev",
63+
]
64+
}
65+
5366
public var requiredPackages: [String] {
5467
switch self {
5568
case .focal:
56-
return [
57-
"libc6",
58-
"libc6-dev",
59-
"libgcc-s1",
69+
return commonPackages + [
6070
"libgcc-10-dev",
6171
"libicu66",
6272
"libicu-dev",
6373
"libstdc++-10-dev",
64-
"libstdc++6",
65-
"linux-libc-dev",
66-
"zlib1g",
67-
"zlib1g-dev",
6874
]
6975
case .jammy:
70-
return [
71-
"libc6",
72-
"libc6-dev",
73-
"libgcc-s1",
76+
return commonPackages + [
7477
"libgcc-12-dev",
7578
"libicu70",
7679
"libicu-dev",
7780
"libstdc++-12-dev",
78-
"libstdc++6",
79-
"linux-libc-dev",
80-
"zlib1g",
81-
"zlib1g-dev",
8281
]
8382
case .noble:
84-
return [
85-
"libc6",
86-
"libc6-dev",
87-
"libgcc-s1",
83+
return commonPackages + [
8884
"libgcc-13-dev",
8985
"libicu74",
9086
"libicu-dev",
9187
"libstdc++-13-dev",
92-
"libstdc++6",
93-
"linux-libc-dev",
94-
"zlib1g",
95-
"zlib1g-dev",
9688
]
9789
}
9890
}
@@ -121,35 +113,34 @@ public enum LinuxDistribution: Hashable, Sendable {
121113
}
122114
}
123115

116+
private var commonPackages: [String] {
117+
[
118+
"libc6",
119+
"libc6-dev",
120+
"libgcc-s1",
121+
"libstdc++6",
122+
"linux-libc-dev",
123+
"zlib1g",
124+
"zlib1g-dev",
125+
"libcurl4-openssl-dev",
126+
]
127+
}
128+
124129
public var requiredPackages: [String] {
125130
switch self {
126131
case .bullseye:
127-
return [
128-
"libc6",
129-
"libc6-dev",
130-
"libgcc-s1",
132+
return commonPackages + [
131133
"libgcc-10-dev",
132134
"libicu67",
133135
"libicu-dev",
134136
"libstdc++-10-dev",
135-
"libstdc++6",
136-
"linux-libc-dev",
137-
"zlib1g",
138-
"zlib1g-dev",
139137
]
140138
case .bookworm:
141-
return [
142-
"libc6",
143-
"libc6-dev",
144-
"libgcc-s1",
139+
return commonPackages + [
145140
"libgcc-12-dev",
146141
"libicu72",
147142
"libicu-dev",
148143
"libstdc++-12-dev",
149-
"libstdc++6",
150-
"linux-libc-dev",
151-
"zlib1g",
152-
"zlib1g-dev",
153144
]
154145
}
155146
}

Tests/SwiftSDKGeneratorTests/EndToEndTests.swift

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,21 @@ func buildSDK(_ logger: Logger, scratchPath: String, withArguments runArguments:
5959
async throws -> String
6060
{
6161
var logger = logger
62-
logger[metadataKey: "runArguments"] = "\"\(runArguments)\""
63-
logger[metadataKey: "scratchPath"] = "\(scratchPath)"
62+
logger[metadataKey: "scratchPath"] = .string(scratchPath)
6463

65-
logger.info("Building Swift SDK")
64+
let packageDirectory = FilePath(#filePath)
65+
.removingLastComponent()
66+
.removingLastComponent()
6667

67-
var packageDirectory = FilePath(#filePath)
68-
packageDirectory.removeLastComponent()
69-
packageDirectory.removeLastComponent()
68+
logger.info("Building SDK generator")
69+
_ = try await Shell.readStdout(
70+
"cd \(packageDirectory) && swift build --scratch-path \"\(scratchPath)\" --product swift-sdk-generator"
71+
)
7072

73+
logger.info("Building Swift SDK", metadata: ["runArguments": .string(runArguments)])
7174
let generatorOutput = try await Shell.readStdout(
7275
"cd \(packageDirectory) && swift run --scratch-path \"\(scratchPath)\" swift-sdk-generator make-linux-sdk \(runArguments)"
7376
)
74-
logger.info("Finished building Swift SDK")
7577

7678
let installCommand = try XCTUnwrap(
7779
generatorOutput.split(separator: "\n").first {
@@ -84,30 +86,28 @@ func buildSDK(_ logger: Logger, scratchPath: String, withArguments runArguments:
8486
).stem
8587
logger[metadataKey: "bundleName"] = "\(bundleName)"
8688

87-
logger.info("Checking installed Swift SDKs")
89+
// Make sure this bundle hasn't been installed already.
8890
let installedSDKs = try await Shell.readStdout("swift experimental-sdk list").components(
8991
separatedBy: "\n"
9092
)
91-
92-
// Make sure this bundle hasn't been installed already.
9393
if installedSDKs.contains(bundleName) {
94-
logger.info("Removing existing Swift SDK")
94+
logger.info("Removing existing Swift SDK", metadata: ["bundleName": .string(bundleName)])
9595
try await Shell.run("swift experimental-sdk remove \(bundleName)")
9696
}
9797

98-
logger.info("Installing new Swift SDK")
98+
logger.info("Installing new Swift SDK", metadata: ["bundleName": .string(bundleName)])
9999
let installOutput = try await Shell.readStdout(String(installCommand))
100100
XCTAssertTrue(installOutput.contains("successfully installed"))
101101

102102
return bundleName
103103
}
104104

105105
private let testcases = [
106-
#"""
106+
"helloWorld": #"""
107107
// Default program generated by swift package init
108108
print("Hello, world!")
109109
"""#,
110-
#"""
110+
"libcNonshared": #"""
111111
// Check that libc_nonshared.a is linked properly
112112
import Foundation
113113
@@ -117,6 +117,10 @@ private let testcases = [
117117
118118
atexit(fin)
119119
"""#,
120+
"curlDependency": #"""
121+
// Check that FoundationNetworking can be linked with libcurl4.a
122+
import FoundationNetworking
123+
"""#,
120124
]
121125

122126
final class RepeatedBuildTests: XCTestCase {
@@ -258,7 +262,6 @@ func buildTestcase(_ logger: Logger, testcase: String, bundleName: String, tempD
258262

259263
// This is a workaround for if Swift 6.0 is used as the host toolchain to run the generator.
260264
// We manually set the swift-tools-version to 5.9 to support building our test cases.
261-
logger.info("Updating minimum swift-tools-version in test project...")
262265
let package_swift = testPackageURL.appendingPathComponent("Package.swift")
263266
let text = try String(contentsOf: package_swift, encoding: .utf8)
264267
var lines = text.components(separatedBy: .newlines)
@@ -325,7 +328,6 @@ func buildTestcase(_ logger: Logger, testcase: String, bundleName: String, tempD
325328

326329
func buildTestcases(config: SDKConfiguration) async throws {
327330
var logger = Logger(label: "EndToEndTests")
328-
logger[metadataKey: "testcase"] = "testPackageInitExecutable"
329331

330332
if ProcessInfo.processInfo.environment.keys.contains("JENKINS_URL")
331333
|| ProcessInfo.processInfo.environment.keys.contains("GITHUB_ACTIONS")
@@ -350,28 +352,42 @@ func buildTestcases(config: SDKConfiguration) async throws {
350352
withArguments: config.sdkGeneratorArguments
351353
)
352354
}
353-
354-
logger.info("Built Swift SDK")
355+
logger[metadataKey: "bundleName"] = .string(bundleName)
355356

356357
// Cleanup
357358
func cleanupSDK() async {
358359
logger.info("Removing Swift SDK to clean up...")
359360
try? await Shell.run("swift experimental-sdk remove \(bundleName)")
360361
}
361362

362-
for testcase in testcases {
363-
do {
364-
try await FileManager.default.withTemporaryDirectory(logger: logger) { tempDir in
365-
try await buildTestcase(
366-
logger,
367-
testcase: testcase,
368-
bundleName: bundleName,
369-
tempDir: tempDir
370-
)
363+
func testcaseLogger(_ name: String) -> Logger {
364+
var testcaseLogger = logger
365+
testcaseLogger[metadataKey: "testcase"] = .string(name)
366+
return testcaseLogger
367+
}
368+
369+
// Let's run the test cases in parallel to speed things up!
370+
logger.info("Running test cases...")
371+
try await withThrowingTaskGroup(of: Void.self) { group in
372+
for (name, testcase) in testcases {
373+
let testcaseLogger = testcaseLogger(name)
374+
group.addTask {
375+
try await FileManager.default.withTemporaryDirectory(logger: testcaseLogger) { tempDir in
376+
try await buildTestcase(
377+
testcaseLogger,
378+
testcase: testcase,
379+
bundleName: bundleName,
380+
tempDir: tempDir
381+
)
382+
}
383+
}
384+
385+
do {
386+
try await group.next()
387+
} catch {
388+
await cleanupSDK()
389+
throw error
371390
}
372-
} catch {
373-
await cleanupSDK()
374-
throw error
375391
}
376392
}
377393

0 commit comments

Comments
 (0)