Skip to content

Commit 3572819

Browse files
leogdionclaude
andcommitted
fix(broadcast): build on non-Apple platforms; require Swift 6.0
Boutique (Bodega/SQLite/swift-collections) imports CryptoKit, which is unavailable off Apple platforms. Gate its target dependency to Apple via `.when(platforms:)` so SwiftPM never compiles it on Linux, and wrap `MultiSessionLogger` + its test in `#if canImport(Boutique)`. `Log.default` drops the OSLog-only `ConsoleLogger` where OSLog is absent. Bump swift-tools to 6.0 (with swiftLanguageModes [.v5]): the library uses `Synchronization.Mutex` and `Foundation.FormatStyle`, both of which only exist in the Swift 6.0 toolchain on Linux. The iOS 18 / macOS 15 floor already requires Swift 6 on Apple, so 5.10 toolchains now get a clean tools-version error instead of failing deep in the FormatStyle layer. Verified: `swift build` is green on Linux (swift:6.3) and macOS (6.3.2); 5.10 fails fast with a clear "requires Swift tools 6.0" message. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 5804909 commit 3572819

4 files changed

Lines changed: 43 additions & 9 deletions

File tree

Package.swift

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
1-
// swift-tools-version:5.10
1+
// swift-tools-version:6.0
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
55

6+
// Broadcast requires Swift 6.0+: it uses `Synchronization.Mutex` and, on non-Apple platforms,
7+
// `Foundation.FormatStyle` — both of which only exist in the Swift 6.0 toolchain on Linux.
8+
//
9+
// Boutique (and its Bodega/SQLite/swift-collections chain) imports `CryptoKit`, which is
10+
// unavailable on non-Apple platforms, so its *target* dependency is gated to Apple platforms
11+
// with `.when(platforms:)`. On Linux SwiftPM still resolves Boutique but never compiles it,
12+
// and `MultiSessionLogger` (guarded by `#if canImport(Boutique)`) compiles to nothing.
13+
// `ConsoleLogger` is likewise gated on `#if canImport(OSLog)`.
14+
//
15+
// `swiftLanguageModes: [.v5]` keeps Swift 5 language mode so existing `static var` globals do
16+
// not become hard concurrency errors under Swift 6 mode.
617
let package = Package(
718
name: "Broadcast",
819
platforms: [
@@ -23,15 +34,24 @@ let package = Package(
2334
.target(
2435
name: "Broadcast",
2536
dependencies: [
26-
.product(name: "Boutique", package: "Boutique")
37+
.product(
38+
name: "Boutique",
39+
package: "Boutique",
40+
condition: .when(platforms: [.iOS, .macOS, .tvOS, .watchOS, .visionOS])
41+
)
2742
]
2843
),
2944
.testTarget(
3045
name: "BroadcastTests",
3146
dependencies: [
32-
.product(name: "Boutique", package: "Boutique"),
33-
"Broadcast"
47+
"Broadcast",
48+
.product(
49+
name: "Boutique",
50+
package: "Boutique",
51+
condition: .when(platforms: [.iOS, .macOS, .tvOS, .watchOS, .visionOS])
52+
)
3453
]
3554
)
36-
]
55+
],
56+
swiftLanguageModes: [.v5]
3757
)

Sources/Broadcast/Log/Log.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,22 +88,30 @@ public extension Log {
8888
/// lifetime control, deterministic tests, or multiple independently exported buffers.
8989
static let sessionLogger = SessionLogger()
9090

91+
#if canImport(OSLog)
9192
/// Broadcast's shared console destination.
9293
///
9394
/// Prefer creating your own ``ConsoleLogger`` with your app's subsystem and category
9495
/// for production integrations.
9596
static let consoleLogger = ConsoleLogger(subsystem: "com.mergesort.broadcast", category: "logs")
97+
#endif
9698

9799
/// A convenience log that writes to Broadcast's default console and session destinations.
98100
///
99101
/// This is useful for quick integration or examples. Apps that need support-log
100102
/// export, privacy-specific routing, or dependency injection should construct
101103
/// their own ``Log``.
104+
///
105+
/// ``ConsoleLogger`` is only included on Apple platforms where OSLog is available;
106+
/// elsewhere the default log writes to the ``SessionLogger`` alone.
102107
static let `default` = Log(
103-
destinations: [
104-
Log.consoleLogger,
105-
Log.sessionLogger
106-
]
108+
destinations: {
109+
#if canImport(OSLog)
110+
return [Log.consoleLogger, Log.sessionLogger]
111+
#else
112+
return [Log.sessionLogger]
113+
#endif
114+
}()
107115
)
108116
}
109117

Sources/Broadcast/Loggers/MultiSessionLogger.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#if canImport(Boutique)
12
import Boutique
23
import Foundation
34
import Synchronization
@@ -137,3 +138,5 @@ private final class MultiSessionLogStorage {
137138
try? await self.$records.removeAll()
138139
}
139140
}
141+
142+
#endif

Tests/BroadcastTests/MultiSessionLogger.Tests.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#if canImport(Boutique)
12
import Boutique
23
@testable import Broadcast
34
import Foundation
@@ -183,3 +184,5 @@ private final class SequentialDateProvider: Sendable {
183184
}
184185
}
185186
}
187+
188+
#endif

0 commit comments

Comments
 (0)