Skip to content

Commit 1059504

Browse files
committed
Add FreeBSD support
This allows building Swift Build for FreeBSD hosts, as well as building for a FreeBSD target from a FreeBSD host. Also adds some speculative support for targeting OpenBSD on OpenBSD hosts, since SwiftPM has minimal support.
1 parent 253fbdf commit 1059504

File tree

12 files changed

+98
-14
lines changed

12 files changed

+98
-14
lines changed

Package.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ let package = Package(
105105
"SWBBuildSystem",
106106
"SWBServiceCore",
107107
"SWBTaskExecution",
108-
.product(name: "SystemPackage", package: "swift-system", condition: .when(platforms: [.linux, .android, .windows])),
108+
.product(name: "SystemPackage", package: "swift-system", condition: .when(platforms: [.linux, .openbsd, .android, .windows, .custom("freebsd")])),
109109
],
110110
exclude: ["CMakeLists.txt"],
111111
swiftSettings: swiftSettings(languageMode: .v5)),
@@ -195,8 +195,8 @@ let package = Package(
195195
"SWBCSupport",
196196
"SWBLibc",
197197
.product(name: "ArgumentParser", package: "swift-argument-parser"),
198-
.product(name: "Crypto", package: "swift-crypto", condition: .when(platforms: [.linux, .openbsd, .android])),
199-
.product(name: "SystemPackage", package: "swift-system", condition: .when(platforms: [.linux, .android, .windows])),
198+
.product(name: "Crypto", package: "swift-crypto", condition: .when(platforms: [.linux, .openbsd, .android, .custom("freebsd")])),
199+
.product(name: "SystemPackage", package: "swift-system", condition: .when(platforms: [.linux, .openbsd, .android, .windows, .custom("freebsd")])),
200200
],
201201
exclude: ["CMakeLists.txt"],
202202
swiftSettings: swiftSettings(languageMode: .v5)),
@@ -439,7 +439,7 @@ if useLocalDependencies {
439439
package.dependencies += [
440440
.package(url: "https://github.com/apple/swift-crypto.git", "2.0.0"..<"4.0.0"),
441441
.package(url: "https://github.com/swiftlang/swift-driver.git", branch: "main"),
442-
.package(url: "https://github.com/apple/swift-system.git", .upToNextMajor(from: "1.4.1")),
442+
.package(url: "https://github.com/apple/swift-system.git", .upToNextMajor(from: "1.4.2")),
443443
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.0.3"),
444444
]
445445
if !useLLBuildFramework {

Sources/SWBCore/Settings/Settings.swift

+4
Original file line numberDiff line numberDiff line change
@@ -5323,6 +5323,10 @@ extension OperatingSystem {
53235323
return "windows"
53245324
case .linux:
53255325
return "linux"
5326+
case .freebsd:
5327+
return "freebsd"
5328+
case .openbsd:
5329+
return "openbsd"
53265330
case .android:
53275331
return "android"
53285332
case .unknown:

Sources/SWBGenericUnixPlatform/Plugin.swift

+8-4
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ struct GenericUnixPlatformSpecsExtension: SpecificationsExtension {
3939
}
4040

4141
func specificationDomains() -> [String: [String]] {
42-
["linux": ["generic-unix"]]
42+
[
43+
"linux": ["generic-unix"],
44+
"freebsd": ["generic-unix"],
45+
"openbsd": ["generic-unix"],
46+
]
4347
}
4448
}
4549

@@ -73,9 +77,9 @@ struct GenericUnixSDKRegistryExtension: SDKRegistryExtension {
7377

7478
let defaultProperties: [String: PropertyListItem]
7579
switch operatingSystem {
76-
case .linux:
80+
case .linux, .freebsd:
7781
defaultProperties = [
78-
// Workaround to avoid `-dependency_info` on Linux.
82+
// Workaround to avoid `-dependency_info`.
7983
"LD_DEPENDENCY_INFO_FILE": .plString(""),
8084

8185
"GENERATE_TEXT_BASED_STUBS": "NO",
@@ -167,6 +171,6 @@ struct GenericUnixToolchainRegistryExtension: ToolchainRegistryExtension {
167171
extension OperatingSystem {
168172
/// Whether the Core is allowed to create a fallback toolchain, SDK, and platform for this operating system in cases where no others have been provided.
169173
var createFallbackSystemToolchain: Bool {
170-
return self == .linux
174+
return self == .linux || self == .freebsd || self == .openbsd
171175
}
172176
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
(
14+
{
15+
Domain = freebsd;
16+
Identifier = com.apple.pbx.linkers.libtool;
17+
BasedOn = generic-unix:com.apple.pbx.linkers.libtool;
18+
Type = Linker;
19+
Options = (
20+
{
21+
Name = "LIBTOOL_USE_RESPONSE_FILE";
22+
Type = Boolean;
23+
DefaultValue = NO;
24+
},
25+
);
26+
},
27+
)

Sources/SWBTestSupport/RunDestinationTestSupport.swift

+20
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ extension _RunDestinationInfo {
9898
windows
9999
case .linux:
100100
linux
101+
case .freebsd:
102+
freebsd
103+
case .openbsd:
104+
openbsd
101105
case .android:
102106
android
103107
case .unknown:
@@ -259,6 +263,22 @@ extension _RunDestinationInfo {
259263
return .init(platform: "linux", sdk: "linux", sdkVariant: "linux", targetArchitecture: arch, supportedArchitectures: ["x86_64", "aarch64"], disableOnlyActiveArch: false)
260264
}
261265

266+
/// A run destination targeting FreeBSD generic device, using the public SDK.
267+
package static var freebsd: Self {
268+
guard let arch = Architecture.hostStringValue else {
269+
preconditionFailure("Unknown architecture \(Architecture.host.stringValue ?? "<nil>")")
270+
}
271+
return .init(platform: "freebsd", sdk: "freebsd", sdkVariant: "freebsd", targetArchitecture: arch, supportedArchitectures: ["x86_64", "aarch64"], disableOnlyActiveArch: false)
272+
}
273+
274+
/// A run destination targeting OpenBSD generic device, using the public SDK.
275+
package static var openbsd: Self {
276+
guard let arch = Architecture.hostStringValue else {
277+
preconditionFailure("Unknown architecture \(Architecture.host.stringValue ?? "<nil>")")
278+
}
279+
return .init(platform: "openbsd", sdk: "openbsd", sdkVariant: "openbsd", targetArchitecture: arch, supportedArchitectures: ["x86_64", "aarch64"], disableOnlyActiveArch: false)
280+
}
281+
262282
/// A run destination targeting Android generic device, using the public SDK.
263283
package static var android: Self {
264284
return .init(platform: "android", sdk: "android", sdkVariant: "android", targetArchitecture: "undefined_arch", supportedArchitectures: ["armv7", "aarch64", "riscv64", "i686", "x86_64"], disableOnlyActiveArch: true)

Sources/SWBTestSupport/SkippedTestSupport.swift

+9
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ extension KnownSDK {
4848
return windows
4949
case .success(.linux):
5050
return linux
51+
case .success(.freebsd):
52+
return freebsd
53+
case .success(.openbsd):
54+
return openbsd
5155
case .success(.android):
5256
return android
5357
case .success(.unknown), .failure:
@@ -68,6 +72,8 @@ extension KnownSDK {
6872
extension KnownSDK {
6973
package static let windows: Self = "windows"
7074
package static let linux: Self = "linux"
75+
package static let freebsd: Self = "freebsd"
76+
package static let openbsd: Self = "openbsd"
7177
package static let android: Self = "android"
7278
package static let qnx: Self = "qnx"
7379
package static let wasi: Self = "wasi"
@@ -143,6 +149,9 @@ extension Trait where Self == Testing.ConditionTrait {
143149
case .linux:
144150
// Amazon Linux 2 has glibc 2.26, and glibc 2.29 is needed for posix_spawn_file_actions_addchdir_np support
145151
FileManager.default.contents(atPath: "/etc/system-release").map { String(decoding: $0, as: UTF8.self) == "Amazon Linux release 2 (Karoo)\n" } ?? false
152+
case .openbsd:
153+
// OpenBSD does not yet have posix_spawn_file_actions_addchdir support at all
154+
true
146155
default:
147156
false
148157
}

Sources/SWBUtil/Architecture.swift

+7-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,13 @@ public struct Architecture: Sendable {
9898
if uname(&buf) == 0 {
9999
return withUnsafeBytes(of: &buf.machine) { buf in
100100
let data = Data(buf)
101-
return String(decoding: data[0...(data.lastIndex(where: { $0 != 0 }) ?? 0)], as: UTF8.self)
101+
let value = String(decoding: data[0...(data.lastIndex(where: { $0 != 0 }) ?? 0)], as: UTF8.self)
102+
switch value {
103+
case "amd64":
104+
return "x86_64"
105+
default:
106+
return value
107+
}
102108
}
103109
}
104110
return nil

Sources/SWBUtil/FSProxy.swift

+8
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,9 @@ class LocalFS: FSProxy, @unchecked Sendable {
765765
#if os(Windows)
766766
// Implement ADS on Windows? See also https://github.com/swiftlang/swift-foundation/issues/1166
767767
return []
768+
#elseif os(FreeBSD)
769+
// FreeBSD blocked on https://github.com/swiftlang/swift/pull/77836
770+
return []
768771
#elseif os(OpenBSD)
769772
// OpenBSD no longer supports extended attributes
770773
return []
@@ -805,6 +808,8 @@ class LocalFS: FSProxy, @unchecked Sendable {
805808
func setExtendedAttribute(_ path: Path, key: String, value: ByteString) throws {
806809
#if os(Windows)
807810
// Implement ADS on Windows? See also https://github.com/swiftlang/swift-foundation/issues/1166
811+
#elseif os(FreeBSD)
812+
// FreeBSD blocked on https://github.com/swiftlang/swift/pull/77836
808813
#elseif os(OpenBSD)
809814
// OpenBSD no longer supports extended attributes
810815
#else
@@ -825,6 +830,9 @@ class LocalFS: FSProxy, @unchecked Sendable {
825830
#if os(Windows)
826831
// Implement ADS on Windows? See also https://github.com/swiftlang/swift-foundation/issues/1166
827832
return nil
833+
#elseif os(FreeBSD)
834+
// FreeBSD blocked on https://github.com/swiftlang/swift/pull/77836
835+
return nil
828836
#elseif os(OpenBSD)
829837
// OpenBSD no longer supports extended attributes
830838
return nil

Sources/SWBUtil/Lock.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public final class Lock: @unchecked Sendable {
2626
#if os(Windows)
2727
@usableFromInline
2828
let mutex: UnsafeMutablePointer<SRWLOCK> = UnsafeMutablePointer.allocate(capacity: 1)
29-
#elseif os(OpenBSD)
29+
#elseif os(FreeBSD) || os(OpenBSD)
3030
@usableFromInline
3131
let mutex: UnsafeMutablePointer<pthread_mutex_t?> = UnsafeMutablePointer.allocate(capacity: 1)
3232
#else

Sources/SWBUtil/ProcessInfo.swift

+7-1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ extension ProcessInfo {
9797
return .windows
9898
#elseif os(Linux)
9999
return .linux
100+
#elseif os(FreeBSD)
101+
return .freebsd
102+
#elseif os(OpenBSD)
103+
return .openbsd
100104
#else
101105
if try FileManager.default.isReadableFile(atPath: systemVersionPlistURL.filePath.str) {
102106
switch try systemVersion().productName {
@@ -127,6 +131,8 @@ public enum OperatingSystem: Hashable, Sendable {
127131
case visionOS(simulator: Bool)
128132
case windows
129133
case linux
134+
case freebsd
135+
case openbsd
130136
case android
131137
case unknown
132138

@@ -155,7 +161,7 @@ public enum OperatingSystem: Hashable, Sendable {
155161
return .macho
156162
case .windows:
157163
return .pe
158-
case .linux, .android, .unknown:
164+
case .linux, .freebsd, .openbsd, .android, .unknown:
159165
return .elf
160166
}
161167
}

Tests/SWBUtilTests/FSProxyTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ import SWBTestSupport
488488
case .android, .linux:
489489
// This will _usually_ be correct on Linux-derived OSes (see above), but not always.
490490
#expect(current_gid == ownership.group)
491-
case .macOS, .iOS, .tvOS, .watchOS, .visionOS:
491+
case .macOS, .iOS, .tvOS, .watchOS, .visionOS, .freebsd, .openbsd:
492492
#expect(parentDirOwnership.group == ownership.group)
493493
case .windows:
494494
// POSIX permissions don't exist, so everything is hardcoded to zero.
@@ -566,7 +566,7 @@ import SWBTestSupport
566566
}
567567
}
568568

569-
@Test(.skipHostOS(.windows))
569+
@Test(.skipHostOS(.windows), .skipHostOS(.freebsd, "Blocked on https://github.com/swiftlang/swift/pull/77836"))
570570
func extendedAttributesSupport() throws {
571571
try withTemporaryDirectory { (tmpDir: Path) in
572572
// Many filesystems on other platforms (e.g. various non-ext4 temporary filesystems on Linux) don't support xattrs and will return ENOTSUP.

Tests/SWBUtilTests/MiscTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import SWBUtil
2525
#expect(SWBUtil.userCacheDir().str.hasPrefix("/var/folders"))
2626
case .android:
2727
#expect(SWBUtil.userCacheDir().str.hasPrefix("/data/local/tmp"))
28-
case .linux, .unknown:
28+
case .linux, .freebsd, .openbsd, .unknown:
2929
#expect(SWBUtil.userCacheDir().str.hasPrefix("/tmp"))
3030
}
3131
}

0 commit comments

Comments
 (0)