Skip to content

Add FreeBSD support #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ let package = Package(
"SWBBuildSystem",
"SWBServiceCore",
"SWBTaskExecution",
.product(name: "SystemPackage", package: "swift-system", condition: .when(platforms: [.linux, .android, .windows])),
.product(name: "SystemPackage", package: "swift-system", condition: .when(platforms: [.linux, .openbsd, .android, .windows, .custom("freebsd")])),
],
exclude: ["CMakeLists.txt"],
swiftSettings: swiftSettings(languageMode: .v5)),
Expand Down Expand Up @@ -195,8 +195,8 @@ let package = Package(
"SWBCSupport",
"SWBLibc",
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "Crypto", package: "swift-crypto", condition: .when(platforms: [.linux, .openbsd, .android])),
.product(name: "SystemPackage", package: "swift-system", condition: .when(platforms: [.linux, .android, .windows])),
.product(name: "Crypto", package: "swift-crypto", condition: .when(platforms: [.linux, .openbsd, .android, .custom("freebsd")])),
.product(name: "SystemPackage", package: "swift-system", condition: .when(platforms: [.linux, .openbsd, .android, .windows, .custom("freebsd")])),
],
exclude: ["CMakeLists.txt"],
swiftSettings: swiftSettings(languageMode: .v5)),
Expand Down Expand Up @@ -439,7 +439,7 @@ if useLocalDependencies {
package.dependencies += [
.package(url: "https://github.com/apple/swift-crypto.git", "2.0.0"..<"4.0.0"),
.package(url: "https://github.com/swiftlang/swift-driver.git", branch: "main"),
.package(url: "https://github.com/apple/swift-system.git", .upToNextMajor(from: "1.4.1")),
.package(url: "https://github.com/apple/swift-system.git", .upToNextMajor(from: "1.4.2")),
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.0.3"),
]
if !useLLBuildFramework {
Expand Down
4 changes: 4 additions & 0 deletions Sources/SWBCore/Settings/Settings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5323,6 +5323,10 @@ extension OperatingSystem {
return "windows"
case .linux:
return "linux"
case .freebsd:
return "freebsd"
case .openbsd:
return "openbsd"
case .android:
return "android"
case .unknown:
Expand Down
12 changes: 8 additions & 4 deletions Sources/SWBGenericUnixPlatform/Plugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ struct GenericUnixPlatformSpecsExtension: SpecificationsExtension {
}

func specificationDomains() -> [String: [String]] {
["linux": ["generic-unix"]]
[
"linux": ["generic-unix"],
"freebsd": ["generic-unix"],
"openbsd": ["generic-unix"],
]
}
}

Expand Down Expand Up @@ -73,9 +77,9 @@ struct GenericUnixSDKRegistryExtension: SDKRegistryExtension {

let defaultProperties: [String: PropertyListItem]
switch operatingSystem {
case .linux:
case .linux, .freebsd:
defaultProperties = [
// Workaround to avoid `-dependency_info` on Linux.
// Workaround to avoid `-dependency_info`.
"LD_DEPENDENCY_INFO_FILE": .plString(""),

"GENERATE_TEXT_BASED_STUBS": "NO",
Expand Down Expand Up @@ -167,6 +171,6 @@ struct GenericUnixToolchainRegistryExtension: ToolchainRegistryExtension {
extension OperatingSystem {
/// 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.
var createFallbackSystemToolchain: Bool {
return self == .linux
return self == .linux || self == .freebsd || self == .openbsd
}
}
27 changes: 27 additions & 0 deletions Sources/SWBGenericUnixPlatform/Specs/FreeBSDLibtool.xcspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

(
{
Domain = freebsd;
Identifier = com.apple.pbx.linkers.libtool;
BasedOn = generic-unix:com.apple.pbx.linkers.libtool;
Type = Linker;
Options = (
{
Name = "LIBTOOL_USE_RESPONSE_FILE";
Type = Boolean;
DefaultValue = NO;
},
);
},
)
20 changes: 20 additions & 0 deletions Sources/SWBTestSupport/RunDestinationTestSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ extension _RunDestinationInfo {
windows
case .linux:
linux
case .freebsd:
freebsd
case .openbsd:
openbsd
case .android:
android
case .unknown:
Expand Down Expand Up @@ -259,6 +263,22 @@ extension _RunDestinationInfo {
return .init(platform: "linux", sdk: "linux", sdkVariant: "linux", targetArchitecture: arch, supportedArchitectures: ["x86_64", "aarch64"], disableOnlyActiveArch: false)
}

/// A run destination targeting FreeBSD generic device, using the public SDK.
package static var freebsd: Self {
guard let arch = Architecture.hostStringValue else {
preconditionFailure("Unknown architecture \(Architecture.host.stringValue ?? "<nil>")")
}
return .init(platform: "freebsd", sdk: "freebsd", sdkVariant: "freebsd", targetArchitecture: arch, supportedArchitectures: ["x86_64", "aarch64"], disableOnlyActiveArch: false)
}

/// A run destination targeting OpenBSD generic device, using the public SDK.
package static var openbsd: Self {
guard let arch = Architecture.hostStringValue else {
preconditionFailure("Unknown architecture \(Architecture.host.stringValue ?? "<nil>")")
}
return .init(platform: "openbsd", sdk: "openbsd", sdkVariant: "openbsd", targetArchitecture: arch, supportedArchitectures: ["x86_64", "aarch64"], disableOnlyActiveArch: false)
}

/// A run destination targeting Android generic device, using the public SDK.
package static var android: Self {
return .init(platform: "android", sdk: "android", sdkVariant: "android", targetArchitecture: "undefined_arch", supportedArchitectures: ["armv7", "aarch64", "riscv64", "i686", "x86_64"], disableOnlyActiveArch: true)
Expand Down
9 changes: 9 additions & 0 deletions Sources/SWBTestSupport/SkippedTestSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ extension KnownSDK {
return windows
case .success(.linux):
return linux
case .success(.freebsd):
return freebsd
case .success(.openbsd):
return openbsd
case .success(.android):
return android
case .success(.unknown), .failure:
Expand All @@ -68,6 +72,8 @@ extension KnownSDK {
extension KnownSDK {
package static let windows: Self = "windows"
package static let linux: Self = "linux"
package static let freebsd: Self = "freebsd"
package static let openbsd: Self = "openbsd"
package static let android: Self = "android"
package static let qnx: Self = "qnx"
package static let wasi: Self = "wasi"
Expand Down Expand Up @@ -143,6 +149,9 @@ extension Trait where Self == Testing.ConditionTrait {
case .linux:
// Amazon Linux 2 has glibc 2.26, and glibc 2.29 is needed for posix_spawn_file_actions_addchdir_np support
FileManager.default.contents(atPath: "/etc/system-release").map { String(decoding: $0, as: UTF8.self) == "Amazon Linux release 2 (Karoo)\n" } ?? false
case .openbsd:
// OpenBSD does not yet have posix_spawn_file_actions_addchdir support at all
true
default:
false
}
Expand Down
8 changes: 7 additions & 1 deletion Sources/SWBUtil/Architecture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,13 @@ public struct Architecture: Sendable {
if uname(&buf) == 0 {
return withUnsafeBytes(of: &buf.machine) { buf in
let data = Data(buf)
return String(decoding: data[0...(data.lastIndex(where: { $0 != 0 }) ?? 0)], as: UTF8.self)
let value = String(decoding: data[0...(data.lastIndex(where: { $0 != 0 }) ?? 0)], as: UTF8.self)
switch value {
case "amd64":
return "x86_64"
default:
return value
}
}
}
return nil
Expand Down
8 changes: 8 additions & 0 deletions Sources/SWBUtil/FSProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,9 @@ class LocalFS: FSProxy, @unchecked Sendable {
#if os(Windows)
// Implement ADS on Windows? See also https://github.com/swiftlang/swift-foundation/issues/1166
return []
#elseif os(FreeBSD)
// FreeBSD blocked on https://github.com/swiftlang/swift/pull/77836
return []
#elseif os(OpenBSD)
// OpenBSD no longer supports extended attributes
return []
Expand Down Expand Up @@ -805,6 +808,8 @@ class LocalFS: FSProxy, @unchecked Sendable {
func setExtendedAttribute(_ path: Path, key: String, value: ByteString) throws {
#if os(Windows)
// Implement ADS on Windows? See also https://github.com/swiftlang/swift-foundation/issues/1166
#elseif os(FreeBSD)
// FreeBSD blocked on https://github.com/swiftlang/swift/pull/77836
#elseif os(OpenBSD)
// OpenBSD no longer supports extended attributes
#else
Expand All @@ -825,6 +830,9 @@ class LocalFS: FSProxy, @unchecked Sendable {
#if os(Windows)
// Implement ADS on Windows? See also https://github.com/swiftlang/swift-foundation/issues/1166
return nil
#elseif os(FreeBSD)
// FreeBSD blocked on https://github.com/swiftlang/swift/pull/77836
return nil
#elseif os(OpenBSD)
// OpenBSD no longer supports extended attributes
return nil
Expand Down
2 changes: 1 addition & 1 deletion Sources/SWBUtil/Lock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public final class Lock: @unchecked Sendable {
#if os(Windows)
@usableFromInline
let mutex: UnsafeMutablePointer<SRWLOCK> = UnsafeMutablePointer.allocate(capacity: 1)
#elseif os(OpenBSD)
#elseif os(FreeBSD) || os(OpenBSD)
@usableFromInline
let mutex: UnsafeMutablePointer<pthread_mutex_t?> = UnsafeMutablePointer.allocate(capacity: 1)
#else
Expand Down
8 changes: 7 additions & 1 deletion Sources/SWBUtil/ProcessInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ extension ProcessInfo {
return .windows
#elseif os(Linux)
return .linux
#elseif os(FreeBSD)
return .freebsd
#elseif os(OpenBSD)
return .openbsd
#else
if try FileManager.default.isReadableFile(atPath: systemVersionPlistURL.filePath.str) {
switch try systemVersion().productName {
Expand Down Expand Up @@ -127,6 +131,8 @@ public enum OperatingSystem: Hashable, Sendable {
case visionOS(simulator: Bool)
case windows
case linux
case freebsd
case openbsd
case android
case unknown

Expand Down Expand Up @@ -155,7 +161,7 @@ public enum OperatingSystem: Hashable, Sendable {
return .macho
case .windows:
return .pe
case .linux, .android, .unknown:
case .linux, .freebsd, .openbsd, .android, .unknown:
return .elf
}
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/SWBUtilTests/FSProxyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ import SWBTestSupport
case .android, .linux:
// This will _usually_ be correct on Linux-derived OSes (see above), but not always.
#expect(current_gid == ownership.group)
case .macOS, .iOS, .tvOS, .watchOS, .visionOS:
case .macOS, .iOS, .tvOS, .watchOS, .visionOS, .freebsd, .openbsd:
#expect(parentDirOwnership.group == ownership.group)
case .windows:
// POSIX permissions don't exist, so everything is hardcoded to zero.
Expand Down Expand Up @@ -566,7 +566,7 @@ import SWBTestSupport
}
}

@Test(.skipHostOS(.windows))
@Test(.skipHostOS(.windows), .skipHostOS(.freebsd, "Blocked on https://github.com/swiftlang/swift/pull/77836"))
func extendedAttributesSupport() throws {
try withTemporaryDirectory { (tmpDir: Path) in
// Many filesystems on other platforms (e.g. various non-ext4 temporary filesystems on Linux) don't support xattrs and will return ENOTSUP.
Expand Down
2 changes: 1 addition & 1 deletion Tests/SWBUtilTests/MiscTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import SWBUtil
#expect(SWBUtil.userCacheDir().str.hasPrefix("/var/folders"))
case .android:
#expect(SWBUtil.userCacheDir().str.hasPrefix("/data/local/tmp"))
case .linux, .unknown:
case .linux, .freebsd, .openbsd, .unknown:
#expect(SWBUtil.userCacheDir().str.hasPrefix("/tmp"))
}
}
Expand Down