Skip to content
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

Fix building and testing on FreeBSD; Add FreeBSD platform support #8193

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ find_package(Foundation QUIET)
find_package(SQLite3 REQUIRED)

# Enable `package` modifier for the whole package.
add_compile_options("$<$<COMPILE_LANGUAGE:Swift>:-package-name;SwiftPM>")
if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
add_compile_options("$<$<COMPILE_LANGUAGE:Swift>:-package-name;SwiftPM>" -L/usr/local/lib)
else()
add_compile_options("$<$<COMPILE_LANGUAGE:Swift>:-package-name;SwiftPM>")
endif()

add_subdirectory(BuildSupport/SwiftSyntax)
add_subdirectory(Sources)
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ let package = Package(
name: "Basics",
dependencies: [
"_AsyncFileSystem",
.target(name: "SPMSQLite3", condition: .when(platforms: [.macOS, .iOS, .tvOS, .watchOS, .visionOS, .macCatalyst, .linux])),
.target(name: "SPMSQLite3", condition: .when(platforms: [.macOS, .iOS, .tvOS, .watchOS, .visionOS, .macCatalyst, .linux, .custom("freebsd")])),
.product(name: "SwiftToolchainCSQLite", package: "swift-toolchain-sqlite", condition: .when(platforms: [.windows, .android])),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to see this port moving forward. 🥲

Have you tried using this SQLite package instead? The only reason most OSs above don't is that this is new: I switched my upcoming native 6.1 toolchain for Android over to using it and was able to remove the external libsqlite package dependency of this Swift toolchain as a result. I suggest you try the same, will require patching llbuild also.

.product(name: "DequeModule", package: "swift-collections"),
.product(name: "OrderedCollections", package: "swift-collections"),
Expand Down
7 changes: 7 additions & 0 deletions Sources/Basics/Archiver/ZipArchiver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ public struct ZipArchiver: Archiver, Cancellable {
arguments: ["tar.exe", "-a", "-c", "-f", destinationPath.pathString, directory.basename],
workingDirectory: directory.parentDirectory
)
#elseif os(FreeBSD)
// On FreeBSD, the unzip command is available in base but not the zip command.
// Therefore; we use libarchive(bsdtar) to produce the ZIP archive instead.
let process = AsyncProcess(
michael-yuji marked this conversation as resolved.
Show resolved Hide resolved
arguments: ["tar", "-c", "--format", "zip", "-f", destinationPath.pathString, directory.basename],
workingDirectory: directory.parentDirectory
)
#else
// This is to work around `swift package-registry publish` tool failing on
// Amazon Linux 2 due to it having an earlier Glibc version (rdar://116370323)
Expand Down
2 changes: 1 addition & 1 deletion Sources/Basics/Cancellator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public final class Cancellator: Cancellable, Sendable {

// Install the default signal handler.
var action = sigaction()
#if canImport(Darwin) || os(OpenBSD)
#if canImport(Darwin) || os(OpenBSD) || os(FreeBSD)
action.__sigaction_u.__sa_handler = SIG_DFL
#elseif canImport(Musl)
action.__sa_handler.sa_handler = SIG_DFL
Expand Down
6 changes: 4 additions & 2 deletions Sources/Basics/Concurrency/AsyncProcess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ package final class AsyncProcess {
return stdinPipe.fileHandleForWriting
#elseif(!canImport(Darwin) || os(macOS))
// Initialize the spawn attributes.
#if canImport(Darwin) || os(Android) || os(OpenBSD)
#if canImport(Darwin) || os(Android) || os(OpenBSD) || os(FreeBSD)
var attributes: posix_spawnattr_t? = nil
#else
var attributes = posix_spawnattr_t()
Expand Down Expand Up @@ -598,7 +598,7 @@ package final class AsyncProcess {
posix_spawnattr_setflags(&attributes, Int16(flags))

// Setup the file actions.
#if canImport(Darwin) || os(Android) || os(OpenBSD)
#if canImport(Darwin) || os(Android) || os(OpenBSD) || os(FreeBSD)
var fileActions: posix_spawn_file_actions_t? = nil
#else
var fileActions = posix_spawn_file_actions_t()
Expand All @@ -614,6 +614,8 @@ package final class AsyncProcess {
if #available(macOS 10.15, *) {
posix_spawn_file_actions_addchdir_np(&fileActions, workingDirectory)
}
#elseif os(FreeBSD)
posix_spawn_file_actions_addchdir_np(&fileActions, workingDirectory)
#elseif os(Linux)
guard SPM_posix_spawn_file_actions_addchdir_np_supported() else {
throw AsyncProcess.Error.workingDirectoryNotSupported
Expand Down
2 changes: 1 addition & 1 deletion Sources/Basics/DispatchTimeInterval+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ extension DispatchTimeInterval {
}

// remove when available to all platforms
#if os(Linux) || os(Windows) || os(Android) || os(OpenBSD)
#if os(Linux) || os(Windows) || os(Android) || os(OpenBSD) || os(FreeBSD)
extension DispatchTime {
public func distance(to: DispatchTime) -> DispatchTimeInterval {
let final = to.uptimeNanoseconds
Expand Down
8 changes: 6 additions & 2 deletions Sources/Basics/Triple+Basics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ extension Triple {
os == .openbsd
}

public func isFreeBSD() -> Bool {
os == .freebsd
}

/// Returns the triple string for the given platform version.
///
/// This is currently meant for Apple platforms only.
Expand Down Expand Up @@ -139,7 +143,7 @@ extension Triple {
switch os {
case _ where isDarwin():
return ".dylib"
case .linux, .openbsd:
case .linux, .openbsd, .freebsd:
return ".so"
case .win32:
return ".dll"
Expand Down Expand Up @@ -179,7 +183,7 @@ extension Triple {
switch os {
case _ where isDarwin():
return ""
case .linux, .openbsd:
case .linux, .openbsd, .freebsd:
return ""
case .win32:
return ".exe"
Expand Down
2 changes: 1 addition & 1 deletion Sources/Basics/Vendor/Triple+Platforms.swift
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ extension Triple {

case .linux:
return environment == .android ? "android" : "linux"
case .freeBSD:
case .freebsd:
return "freebsd"
case .openbsd:
return "openbsd"
Expand Down
4 changes: 2 additions & 2 deletions Sources/Basics/Vendor/Triple.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1089,7 +1089,7 @@ extension Triple {
case cloudABI = "cloudabi"
case darwin
case dragonFly = "dragonfly"
case freeBSD = "freebsd"
case freebsd = "freebsd"
case fuchsia
case ios
case kfreebsd
Expand Down Expand Up @@ -1137,7 +1137,7 @@ extension Triple {
case _ where os.hasPrefix("dragonfly"):
return .dragonFly
case _ where os.hasPrefix("freebsd"):
return .freeBSD
return .freebsd
case _ where os.hasPrefix("fuchsia"):
return .fuchsia
case _ where os.hasPrefix("ios"):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
// Set rpath such that dynamic libraries are looked up
// adjacent to the product, unless overridden.
if !self.buildParameters.linkingParameters.shouldDisableLocalRpath {
if triple.isLinux() {
if triple.isLinux() || triple.isFreeBSD() {
args += ["-Xlinker", "-rpath=$ORIGIN"]
} else if triple.isDarwin() {
let rpath = self.product.type == .test ? "@loader_path/../../../" : "@loader_path"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public final class SwiftModuleBuildDescription {
public var moduleOutputPath: AbsolutePath { // note: needs to be public because of sourcekit-lsp
// If we're an executable and we're not allowing test targets to link against us, we hide the module.
let triple = buildParameters.triple
let allowLinkingAgainstExecutables = (triple.isDarwin() || triple.isLinux() || triple.isWindows()) && self.toolsVersion >= .v5_5
let allowLinkingAgainstExecutables = (triple.isDarwin() || triple.isLinux() || triple.isFreeBSD() || triple.isWindows()) && self.toolsVersion >= .v5_5
let dirPath = (target.type == .executable && !allowLinkingAgainstExecutables) ? self.tempsPath : self.modulesPath
return dirPath.appending(component: "\(self.target.c99name).swiftmodule")
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Build/BuildPlan/BuildPlan+Product.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ extension BuildPlan {
for description in dependencies.staticTargets {
if case let target as ClangModule = description.module.underlying, target.isCXX {
let triple = buildProduct.buildParameters.triple
if triple.isDarwin() {
if triple.isDarwin() || triple.isFreeBSD() {
buildProduct.additionalFlags += ["-lc++"]
} else if triple.isWindows() {
// Don't link any C++ library.
Expand Down
2 changes: 1 addition & 1 deletion Sources/Build/BuildPlan/BuildPlan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ extension BuildParameters {
let args: [String]
if self.triple.isApple() {
args = ["-alias", "_\(target.c99name)_main", "_main"]
} else if self.triple.isLinux() {
} else if self.triple.isLinux() || self.triple.isFreeBSD() {
args = ["--defsym", "main=\(target.c99name)_main"]
} else {
return nil
Expand Down
2 changes: 1 addition & 1 deletion Sources/Commands/SwiftTestCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1491,7 +1491,7 @@ private extension Basics.Diagnostic {
/// it duplicates the definition of this constant in its own source. Any changes
/// to this constant in either package must be mirrored in the other.
private var EXIT_NO_TESTS_FOUND: CInt {
#if os(macOS) || os(Linux) || canImport(Android)
#if os(macOS) || os(Linux) || canImport(Android) || os(FreeBSD)
EX_UNAVAILABLE
#elseif os(Windows)
ERROR_NOT_FOUND
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ private typealias JSONModel = PackageCollectionModel.V1
struct JSONPackageCollectionProvider: PackageCollectionProvider {
// TODO: This can be removed when the `Security` framework APIs that the `PackageCollectionsSigning`
// module depends on are available on all Apple platforms.
#if os(macOS) || os(Linux) || os(Windows) || os(Android)
#if os(macOS) || os(Linux) || os(Windows) || os(Android) || os(FreeBSD)
static let isSignatureCheckSupported = true
#else
static let isSignatureCheckSupported = false
Expand Down Expand Up @@ -551,6 +551,8 @@ extension PackageModel.Platform {
self = PackageModel.Platform.wasi
case let name where name.contains("openbsd"):
self = PackageModel.Platform.openbsd
case let name where name.contains("freebsd"):
self = PackageModel.Platform.freebsd
default:
return nil
}
Expand Down
4 changes: 4 additions & 0 deletions Sources/PackageDescription/SupportedPlatforms.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ public struct Platform: Equatable, Sendable {
/// The OpenBSD platform.
@available(_PackageDescription, introduced: 5.8)
public static let openbsd: Platform = Platform(name: "openbsd")

/// The FreeBSD platform.
@available(_PackageDescription, introduced: 999.0)
public static let freebsd: Platform = Platform(name: "freebsd")
}

/// A platform that the Swift package supports.
Expand Down
7 changes: 5 additions & 2 deletions Sources/PackageLoading/Platform.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public enum Platform: Equatable, Sendable {
case darwin
case linux(LinuxFlavor)
case windows
case freebsd

/// Recognized flavors of linux.
public enum LinuxFlavor: Equatable, Sendable {
Expand All @@ -44,6 +45,8 @@ extension Platform {
{
case "darwin"?:
return .darwin
case "freebsd"?:
return .freebsd
case "linux"?:
return Platform.findCurrentPlatformLinux(localFileSystem)
default:
Expand Down Expand Up @@ -89,15 +92,15 @@ extension Platform {
public var dynamicLibraryExtension: String {
switch self {
case .darwin: return ".dylib"
case .linux, .android: return ".so"
case .linux, .android, .freebsd: return ".so"
case .windows: return ".dll"
}
}

public var executableExtension: String {
switch self {
case .windows: return ".exe"
case .linux, .android, .darwin: return ""
case .linux, .android, .darwin, .freebsd: return ""
}
}
}
10 changes: 9 additions & 1 deletion Sources/PackageLoading/Target+PkgConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ extension SystemPackageProviderDescription {
return " yum install \(packages.joined(separator: " "))\n"
case .nuget(let packages):
return " nuget install \(packages.joined(separator: " "))\n"
case .pkg(let packages):
return " pkg install \(packages.joined(separator: " "))\n"
}
}

Expand All @@ -180,9 +182,13 @@ extension SystemPackageProviderDescription {
switch platform {
case .darwin, .windows, .linux:
return true
case .android:
case .android, .freebsd:
return false
}
case .pkg:
if case .freebsd = platform {
return true
}
}
return false
}
Expand Down Expand Up @@ -215,6 +221,8 @@ extension SystemPackageProviderDescription {
return []
case .nuget:
return []
case .pkg:
return []
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ public enum SystemPackageProviderDescription: Hashable, Codable, Sendable {
case apt([String])
case yum([String])
case nuget([String])
case pkg([String])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is FreeBSD's pkg sufficiently "branded" to call it this? OpenBSD's package manager is named quite similarly, and while it doesn't seem to have a formal name, all of its commands begin with pkg_. pkg also isn't a particularly searchable term.

pkg might still be the right choice, but I just want to make sure we're doing the thought exercise of considering the best name in the context of all the largest 4 BSDs (FreeBSD, OpenBSD, NetBSD, and DragonflyBSD) and what would be least confusing, even if we're not adding those others right now.

Here's some of my thoughts:

  • NetBSD's pkgsrc is not exclusive to NetBSD, and has its own website / identity / branding. So I think an enum named pkgsrc would make sense there.
  • OpenBSD's package system doesn't have a name. Call the enum openbsd_pkg?
  • FreeBSD's package system doesn't have a name, and DragonflyBSD's package management software (as far as I can tell) is a fork of FreeBSD's (as is the OS generally). Two enums freebsd_pkg and dragonflybsd_pkg? Or a single enum pkg that applies to both FreeBSD and DragonflyBSD? That might be a bad idea though, as they are different OSes which may have diverged.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also in my mind, originally I name this pkgng, but pkgng renamed to pkg quite a while ago. https://wiki.freebsd.org/pkg. DragonflyBSD is using the same pkg from FreeBSD https://github.com/DragonFlyBSD/DPorts/blob/master/ports-mgmt/pkg/Makefile.

I'm not sure about OpenBSD tho, and currently the SystemPackageProviderDescription enum does not include one for it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, might be worth starting a Swift evolution thread on the naming. In the meantime you could land this behind an API availability of 999.0

}

extension SystemPackageProviderDescription {
private enum CodingKeys: String, CodingKey {
case brew, apt, yum, nuget
case brew, apt, yum, nuget, pkg
}

public func encode(to encoder: Encoder) throws {
Expand All @@ -38,6 +39,9 @@ extension SystemPackageProviderDescription {
case let .nuget(a1):
var unkeyedContainer = container.nestedUnkeyedContainer(forKey: .nuget)
try unkeyedContainer.encode(a1)
case let .pkg(a1):
var unkeyedContainer = container.nestedUnkeyedContainer(forKey: .pkg)
try unkeyedContainer.encode(a1)
}
}

Expand All @@ -63,6 +67,10 @@ extension SystemPackageProviderDescription {
var unkeyedValues = try values.nestedUnkeyedContainer(forKey: key)
let a1 = try unkeyedValues.decode([String].self)
self = .nuget(a1)
case .pkg:
var unkeyedValues = try values.nestedUnkeyedContainer(forKey: key)
let a1 = try unkeyedValues.decode([String].self)
self = .pkg(a1)
}
}
}
3 changes: 3 additions & 0 deletions Sources/PackageModel/ManifestSourceGeneration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,9 @@ fileprivate extension SourceCodeFragment {
case .nuget(let names):
let params = [SourceCodeFragment(strings: names)]
self.init(enum: "nuget", subnodes: params)
case .pkg(let names):
let params = [SourceCodeFragment(strings: names)]
self.init(enum: "pkg", subnodes: params)
}
}

Expand Down
2 changes: 2 additions & 0 deletions Sources/PackageModel/Platform.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public struct Platform: Equatable, Hashable, Codable, Sendable {
public static let windows: Platform = Platform(name: "windows", oldestSupportedVersion: .unknown)
public static let wasi: Platform = Platform(name: "wasi", oldestSupportedVersion: .unknown)
public static let openbsd: Platform = Platform(name: "openbsd", oldestSupportedVersion: .unknown)
public static let freebsd: Platform = Platform(name: "freebsd", oldestSupportedVersion: .unknown)


}

Expand Down
1 change: 1 addition & 0 deletions Sources/PackageModel/PlatformRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public struct PlatformRegistry {
.macOS,
.macCatalyst,
.openbsd,
.freebsd,
.tvOS,
.visionOS,
.wasi,
Expand Down
2 changes: 1 addition & 1 deletion Sources/SPMBuildCore/BinaryTarget+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ extension Triple.OS {
/// Returns a representation of the receiver that can be compared with platform strings declared in an XCFramework.
fileprivate var asXCFrameworkPlatformString: String? {
switch self {
case .darwin, .linux, .wasi, .win32, .openbsd, .noneOS:
case .darwin, .linux, .wasi, .win32, .openbsd, .freebsd, .noneOS:
return nil // XCFrameworks do not support any of these platforms today.
case .macosx:
return "macos"
Expand Down
2 changes: 2 additions & 0 deletions Sources/SPMBuildCore/BuildParameters/BuildParameters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ public struct BuildParameters: Encodable {
return .windows
} else if self.triple.isOpenBSD() {
return .openbsd
} else if self.triple.isFreeBSD() {
return .freebsd
} else {
return .linux
}
Expand Down
8 changes: 8 additions & 0 deletions Sources/XCBuildSupport/PIFBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1727,6 +1727,9 @@ extension [PackageCondition] {
case .openbsd:
result += PIF.PlatformFilter.openBSDFilters

case .freebsd:
result += PIF.PlatformFilter.freeBSDFilters

default:
assertionFailure("Unhandled platform condition: \(condition)")
}
Expand Down Expand Up @@ -1789,6 +1792,11 @@ extension PIF.PlatformFilter {
.init(platform: "openbsd"),
]

/// FreeBSD filters.
public static let freeBSDFilters: [PIF.PlatformFilter] = [
.init(platform: "freebsd"),
]

/// WebAssembly platform filters.
public static let webAssemblyFilters: [PIF.PlatformFilter] = [
.init(platform: "wasi"),
Expand Down
2 changes: 1 addition & 1 deletion Tests/BasicsTests/Archiver/UniversalArchiverTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ final class UniversalArchiverTests: XCTestCase {
inputArchivePath = AbsolutePath(#file).parentDirectory
.appending(components: "Inputs", "invalid_archive.zip")
await XCTAssertAsyncThrowsError(try await archiver.extract(from: inputArchivePath, to: tmpdir)) { error in
#if os(Windows)
#if os(Windows) || os(FreeBSD)
XCTAssertMatch((error as? StringError)?.description, .contains("Unrecognized archive format"))
#else
XCTAssertMatch((error as? StringError)?.description, .contains("End-of-central-directory signature not found"))
Expand Down
3 changes: 2 additions & 1 deletion Tests/BasicsTests/Archiver/ZipArchiverTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ final class ZipArchiverTests: XCTestCase {
let inputArchivePath = AbsolutePath(#file).parentDirectory
.appending(components: "Inputs", "invalid_archive.zip")
await XCTAssertAsyncThrowsError(try await archiver.extract(from: inputArchivePath, to: tmpdir)) { error in
#if os(Windows)
#if os(Windows) || os(FreeBSD)
// On FreeBSD, unzip (bsdunzip) is backed by libarchive
XCTAssertMatch((error as? StringError)?.description, .contains("Unrecognized archive format"))
#else
XCTAssertMatch((error as? StringError)?.description, .contains("End-of-central-directory signature not found"))
Expand Down
Loading