From b844a3e7c8ec02f9e50dde8086f25dcb2b6102d5 Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Thu, 12 Sep 2024 09:05:59 -0400 Subject: [PATCH] Add platform-specific branches for FreeBSD. This PR adds support for FreeBSD where we have platform-specific code. Most changes simply involve changing `os(Linux)` to `os(Linux) || os(FreeBSD)`, although there is some actual platform-specific code and at least one spot where Darwin and FreeBSD share an implementation but Linux does not. > [!NOTE] > This new code is minimally tested. The Swift project does not officially > support FreeBSD. --- .../Testing/ABI/EntryPoints/EntryPoint.swift | 6 +++--- .../ABI/EntryPoints/SwiftPMEntryPoint.swift | 2 +- .../Events/Recorder/Event.Symbol.swift | 2 +- Sources/Testing/ExitTests/ExitCondition.swift | 9 +++++--- Sources/Testing/ExitTests/ExitTest.swift | 19 +++++++++-------- Sources/Testing/ExitTests/WaitFor.swift | 11 +++++++--- .../Backtrace+Symbolication.swift | 14 ++++++------- .../Testing/SourceAttribution/Backtrace.swift | 2 +- .../Additions/CommandLineAdditions.swift | 14 +++++++++++++ Sources/Testing/Support/Environment.swift | 6 +++--- Sources/Testing/Support/FileHandle.swift | 10 ++++----- Sources/Testing/Support/GetSymbol.swift | 6 +++--- Sources/Testing/Support/Locked.swift | 10 ++++----- Sources/Testing/Support/Versions.swift | 2 +- .../Traits/Tags/Tag.Color+Loading.swift | 4 ++-- Sources/_TestingInternals/Discovery.cpp | 2 +- Sources/_TestingInternals/include/Stubs.h | 2 +- Tests/TestingTests/ABIEntryPointTests.swift | 2 +- Tests/TestingTests/ExitTestTests.swift | 21 +++++++++++++------ .../Support/EnvironmentTests.swift | 2 +- .../Support/FileHandleTests.swift | 4 ++-- 21 files changed, 90 insertions(+), 60 deletions(-) diff --git a/Sources/Testing/ABI/EntryPoints/EntryPoint.swift b/Sources/Testing/ABI/EntryPoints/EntryPoint.swift index 976aa7725..1164a2944 100644 --- a/Sources/Testing/ABI/EntryPoints/EntryPoint.swift +++ b/Sources/Testing/ABI/EntryPoints/EntryPoint.swift @@ -673,7 +673,7 @@ extension Event.ConsoleOutputRecorder.Options { /// Whether or not the system terminal claims to support 16-color ANSI escape /// codes. private static var _terminalSupports16ColorANSIEscapeCodes: Bool { -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) if let termVariable = Environment.variable(named: "TERM") { return termVariable != "dumb" } @@ -695,7 +695,7 @@ extension Event.ConsoleOutputRecorder.Options { /// Whether or not the system terminal claims to support 256-color ANSI escape /// codes. private static var _terminalSupports256ColorANSIEscapeCodes: Bool { -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) if let termVariable = Environment.variable(named: "TERM") { return strstr(termVariable, "256") != nil } @@ -717,7 +717,7 @@ extension Event.ConsoleOutputRecorder.Options { /// Whether or not the system terminal claims to support true-color ANSI /// escape codes. private static var _terminalSupportsTrueColorANSIEscapeCodes: Bool { -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) if let colortermVariable = Environment.variable(named: "COLORTERM") { return strstr(colortermVariable, "truecolor") != nil } diff --git a/Sources/Testing/ABI/EntryPoints/SwiftPMEntryPoint.swift b/Sources/Testing/ABI/EntryPoints/SwiftPMEntryPoint.swift index 772caf5ac..52e4d2a54 100644 --- a/Sources/Testing/ABI/EntryPoints/SwiftPMEntryPoint.swift +++ b/Sources/Testing/ABI/EntryPoints/SwiftPMEntryPoint.swift @@ -24,7 +24,7 @@ private import _TestingInternals /// /// This constant is not part of the public interface of the testing library. var EXIT_NO_TESTS_FOUND: CInt { -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || os(WASI) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || os(WASI) EX_UNAVAILABLE #elseif os(Windows) CInt(ERROR_NOT_FOUND) diff --git a/Sources/Testing/Events/Recorder/Event.Symbol.swift b/Sources/Testing/Events/Recorder/Event.Symbol.swift index 53ed83de0..6bec7eb13 100644 --- a/Sources/Testing/Events/Recorder/Event.Symbol.swift +++ b/Sources/Testing/Events/Recorder/Event.Symbol.swift @@ -100,7 +100,7 @@ extension Event.Symbol { /// be used to represent it in text-based output. The value of this property /// is platform-dependent. public var unicodeCharacter: Character { -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || os(WASI) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || os(WASI) switch self { case .default: // Unicode: WHITE DIAMOND diff --git a/Sources/Testing/ExitTests/ExitCondition.swift b/Sources/Testing/ExitTests/ExitCondition.swift index ed6552e09..946374b39 100644 --- a/Sources/Testing/ExitTests/ExitCondition.swift +++ b/Sources/Testing/ExitTests/ExitCondition.swift @@ -42,11 +42,13 @@ public enum ExitCondition: Sendable { /// |-|-| /// | macOS | [``](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/_Exit.3.html), [``](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/sysexits.3.html) | /// | Linux | [``](https://sourceware.org/glibc/manual/latest/html_node/Exit-Status.html), `` | + /// | FreeBSD | ``, `` | /// | Windows | [``](https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure) | /// - /// On macOS and Windows, the full exit code reported by the process is - /// yielded to the parent process. Linux and other POSIX-like systems may only - /// reliably report the low unsigned 8 bits (0–255) of the exit code. + /// On macOS, FreeBSD, and Windows, the full exit code reported by the process + /// is yielded to the parent process. Linux and other POSIX-like systems may + /// only reliably report the low unsigned 8 bits (0–255) of the exit + /// code. case exitCode(_ exitCode: CInt) /// The process terminated with the given signal. @@ -61,6 +63,7 @@ public enum ExitCondition: Sendable { /// |-|-| /// | macOS | [``](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/signal.3.html) | /// | Linux | [``](https://sourceware.org/glibc/manual/latest/html_node/Standard-Signals.html) | + /// | FreeBSD | `` | /// | Windows | [``](https://learn.microsoft.com/en-us/cpp/c-runtime-library/signal-constants) | /// /// On Windows, by default, the C runtime will terminate a process with exit diff --git a/Sources/Testing/ExitTests/ExitTest.swift b/Sources/Testing/ExitTests/ExitTest.swift index 6ef1d8175..4a92e7908 100644 --- a/Sources/Testing/ExitTests/ExitTest.swift +++ b/Sources/Testing/ExitTests/ExitTest.swift @@ -47,10 +47,10 @@ public struct ExitTest: Sendable { EXCEPTION_DEFAULT, THREAD_STATE_NONE ) -#elseif os(Linux) - // On Linux, disable the generation of core files (although they will often - // be disabled by default.) If a particular Linux distro performs additional - // crash diagnostics, we may want to special-case them as well if we can. +#elseif os(Linux) || os(FreeBSD) + // On Linux and FreeBSD, disable the generation of core files (although they + // will often be disabled by default.) If a particular Linux distro performs + // additional crash diagnostics, we may want to special-case them as well if we can. var rl = rlimit(rlim_cur: 0, rlim_max: 0) _ = setrlimit(CInt(RLIMIT_CORE.rawValue), &rl) #elseif os(Windows) @@ -322,13 +322,14 @@ extension ExitTest { for key in childEnvironment.keys where key.starts(with: "XCTest") { childEnvironment.removeValue(forKey: key) } -#elseif os(Linux) +#endif + if childEnvironment["SWIFT_BACKTRACE"] == nil { // Disable interactive backtraces unless explicitly enabled to reduce - // the noise level during the exit test. Only needed on Linux. + // the noise level during the exit test. childEnvironment["SWIFT_BACKTRACE"] = "enable=no" } -#endif + // Insert a specific variable that tells the child process which exit test // to run. try JSON.withEncoding(of: exitTest.sourceLocation) { json in @@ -364,11 +365,11 @@ extension ExitTest { // use, so use this typealias to paper over the differences. #if SWT_TARGET_OS_APPLE typealias P = T? -#elseif os(Linux) +#elseif os(Linux) || os(FreeBSD) typealias P = T #endif -#if SWT_TARGET_OS_APPLE || os(Linux) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) let pid = try withUnsafeTemporaryAllocation(of: P.self, capacity: 1) { fileActions in guard 0 == posix_spawn_file_actions_init(fileActions.baseAddress!) else { throw CError(rawValue: swt_errno()) diff --git a/Sources/Testing/ExitTests/WaitFor.swift b/Sources/Testing/ExitTests/WaitFor.swift index ebce204b1..15fed9918 100644 --- a/Sources/Testing/ExitTests/WaitFor.swift +++ b/Sources/Testing/ExitTests/WaitFor.swift @@ -12,7 +12,7 @@ internal import _TestingInternals -#if SWT_TARGET_OS_APPLE || os(Linux) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) /// Block the calling thread, wait for the target process to exit, and return /// a value describing the conditions under which it exited. /// @@ -104,11 +104,16 @@ private let _createWaitThreadImpl: Void = { { _ in // Set the thread name to help with diagnostics. Note that different // platforms support different thread name lengths. See MAXTHREADNAMESIZE - // on Darwin and TASK_COMM_LEN on Linux. + // on Darwin, TASK_COMM_LEN on Linux, and MAXCOMLEN on FreeBSD. We try to + // maximize legibility in the available space. #if SWT_TARGET_OS_APPLE _ = pthread_setname_np("Swift Testing exit test monitor") -#else +#elseif os(Linux) _ = pthread_setname_np(pthread_self(), "SWT ExT monitor") +#elseif os(FreeBSD) + _ = pthread_set_name_np(pthread_self(), "SWT ex test monitor") +#else +#warning("Platform-specific implementation missing: thread naming unavailable") #endif // Run an infinite loop that waits for child processes to terminate and diff --git a/Sources/Testing/SourceAttribution/Backtrace+Symbolication.swift b/Sources/Testing/SourceAttribution/Backtrace+Symbolication.swift index 21b39dfed..6d7e9d568 100644 --- a/Sources/Testing/SourceAttribution/Backtrace+Symbolication.swift +++ b/Sources/Testing/SourceAttribution/Backtrace+Symbolication.swift @@ -70,14 +70,12 @@ extension Backtrace { result[i] = SymbolicatedAddress(address: address, offset: offset, symbolName: symbolName) } } -#elseif os(Linux) - // Although Linux has dladdr(), it does not have symbol names from ELF - // binaries by default. The standard library's backtracing functionality has - // implemented sufficient ELF/DWARF parsing to be able to symbolicate Linux - // backtraces. TODO: adopt the standard library's Backtrace on Linux - // Note that this means on Linux we don't have demangling capability (since - // we don't have the mangled symbol names in the first place) so this code - // does not check the mode argument. +#elseif os(Linux) || os(FreeBSD) || os(Android) + // Although these platforms have dladdr(), they do not have symbol names + // from DWARF binaries by default, only from shared libraries. The standard + // library's backtracing functionality has implemented sufficient ELF/DWARF + // parsing to be able to symbolicate Linux backtraces. + // TODO: adopt the standard library's Backtrace on these platforms #elseif os(Windows) _withDbgHelpLibrary { hProcess in guard let hProcess else { diff --git a/Sources/Testing/SourceAttribution/Backtrace.swift b/Sources/Testing/SourceAttribution/Backtrace.swift index 8e1914790..abbd7c7cb 100644 --- a/Sources/Testing/SourceAttribution/Backtrace.swift +++ b/Sources/Testing/SourceAttribution/Backtrace.swift @@ -69,7 +69,7 @@ public struct Backtrace: Sendable { initializedCount = addresses.withMemoryRebound(to: UnsafeMutableRawPointer.self) { addresses in .init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count))) } -#elseif os(Linux) +#elseif os(Linux) || os(FreeBSD) initializedCount = .init(clamping: backtrace(addresses.baseAddress!, .init(clamping: addresses.count))) #elseif os(Windows) initializedCount = Int(clamping: RtlCaptureStackBackTrace(0, ULONG(clamping: addresses.count), addresses.baseAddress!, nil)) diff --git a/Sources/Testing/Support/Additions/CommandLineAdditions.swift b/Sources/Testing/Support/Additions/CommandLineAdditions.swift index ccfce6e31..c354e386a 100644 --- a/Sources/Testing/Support/Additions/CommandLineAdditions.swift +++ b/Sources/Testing/Support/Additions/CommandLineAdditions.swift @@ -38,6 +38,20 @@ extension CommandLine { buffer[readCount] = 0 // NUL-terminate the string. return String(cString: buffer.baseAddress!) } +#elseif os(FreeBSD) + var mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1] + try mib.withUnsafeMutableBufferPointer { mib in + var bufferCount = 0 + guard 0 == sysctl(mib.baseAddress!, .init(mib.count), nil, &bufferCount, nil, 0) else { + throw CError(rawValue: swt_errno()) + } + return try withUnsafeTemporaryAllocation(of: CChar.self, capacity: bufferCount) { buffer in + guard 0 == sysctl(mib.baseAddress!, .init(mib.count), buffer.baseAddress!, &bufferCount, nil, 0) else { + throw CError(rawValue: swt_errno()) + } + return String(cString: buffer.baseAddress!) + } + } #elseif os(Windows) return try withUnsafeTemporaryAllocation(of: wchar_t.self, capacity: Int(MAX_PATH) * 2) { buffer in guard 0 != GetModuleFileNameW(nil, buffer.baseAddress!, DWORD(buffer.count)) else { diff --git a/Sources/Testing/Support/Environment.swift b/Sources/Testing/Support/Environment.swift index 4d835d53c..e10505877 100644 --- a/Sources/Testing/Support/Environment.swift +++ b/Sources/Testing/Support/Environment.swift @@ -42,7 +42,7 @@ enum Environment { } } -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || os(WASI) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || os(WASI) /// Get all environment variables from a POSIX environment block. /// /// - Parameters: @@ -103,7 +103,7 @@ enum Environment { } #endif return _get(fromEnviron: _NSGetEnviron()!.pointee!) -#elseif os(Linux) || os(Android) +#elseif os(Linux) || os(FreeBSD) || os(Android) _get(fromEnviron: swt_environ()) #elseif os(WASI) _get(fromEnviron: __wasilibc_get_environ()) @@ -170,7 +170,7 @@ enum Environment { } return nil } -#elseif SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || os(WASI) +#elseif SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || os(WASI) getenv(name).flatMap { String(validatingCString: $0) } #elseif os(Windows) name.withCString(encodedAs: UTF16.self) { name in diff --git a/Sources/Testing/Support/FileHandle.swift b/Sources/Testing/Support/FileHandle.swift index 224aea1c3..2e1c67841 100644 --- a/Sources/Testing/Support/FileHandle.swift +++ b/Sources/Testing/Support/FileHandle.swift @@ -156,7 +156,7 @@ struct FileHandle: ~Copyable, Sendable { /// descriptor, `nil` is passed to `body`. borrowing func withUnsafePOSIXFileDescriptor(_ body: (CInt?) throws -> R) rethrows -> R { try withUnsafeCFILEHandle { handle in -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || os(WASI) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || os(WASI) let fd = fileno(handle) #elseif os(Windows) let fd = _fileno(handle) @@ -215,7 +215,7 @@ struct FileHandle: ~Copyable, Sendable { /// other threads. borrowing func withLock(_ body: () throws -> R) rethrows -> R { try withUnsafeCFILEHandle { handle in -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) flockfile(handle) defer { funlockfile(handle) @@ -250,7 +250,7 @@ extension FileHandle { // If possible, reserve enough space in the resulting buffer to contain // the contents of the file being read. var size: Int? -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || os(WASI) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || os(WASI) withUnsafePOSIXFileDescriptor { fd in var s = stat() if let fd, 0 == fstat(fd, &s) { @@ -388,7 +388,7 @@ extension FileHandle { extension FileHandle { /// Is this file handle a TTY or PTY? var isTTY: Bool { -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || os(WASI) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || os(WASI) // If stderr is a TTY and TERM is set, that's good enough for us. withUnsafePOSIXFileDescriptor { fd in if let fd, 0 != isatty(fd), let term = Environment.variable(named: "TERM"), !term.isEmpty { @@ -414,7 +414,7 @@ extension FileHandle { /// Is this file handle a pipe or FIFO? var isPipe: Bool { -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || os(WASI) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || os(WASI) withUnsafePOSIXFileDescriptor { fd in guard let fd else { return false diff --git a/Sources/Testing/Support/GetSymbol.swift b/Sources/Testing/Support/GetSymbol.swift index 33358f070..3d4eb32d8 100644 --- a/Sources/Testing/Support/GetSymbol.swift +++ b/Sources/Testing/Support/GetSymbol.swift @@ -13,7 +13,7 @@ internal import _TestingInternals #if !SWT_NO_DYNAMIC_LINKING /// The platform-specific type of a loaded image handle. -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) typealias ImageAddress = UnsafeMutableRawPointer #elseif os(Windows) typealias ImageAddress = HMODULE @@ -28,7 +28,7 @@ typealias ImageAddress = Never /// and cannot be imported directly into Swift. As well, `RTLD_DEFAULT` is only /// defined on Linux when `_GNU_SOURCE` is defined, so it is not sufficient to /// declare a wrapper function in the internal module's Stubs.h file. -#if SWT_TARGET_OS_APPLE +#if SWT_TARGET_OS_APPLE || os(FreeBSD) private nonisolated(unsafe) let RTLD_DEFAULT = ImageAddress(bitPattern: -2) #elseif os(Android) && _pointerBitWidth(_32) private nonisolated(unsafe) let RTLD_DEFAULT = ImageAddress(bitPattern: UInt(0xFFFFFFFF)) @@ -59,7 +59,7 @@ private nonisolated(unsafe) let RTLD_DEFAULT = ImageAddress(bitPattern: 0) /// calling `EnumProcessModules()` and iterating over the returned handles /// looking for one containing the given function. func symbol(in handle: ImageAddress? = nil, named symbolName: String) -> UnsafeRawPointer? { -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) dlsym(handle ?? RTLD_DEFAULT, symbolName).map(UnsafeRawPointer.init) #elseif os(Windows) symbolName.withCString { symbolName in diff --git a/Sources/Testing/Support/Locked.swift b/Sources/Testing/Support/Locked.swift index 5481b1117..df18319d0 100644 --- a/Sources/Testing/Support/Locked.swift +++ b/Sources/Testing/Support/Locked.swift @@ -36,7 +36,7 @@ struct Locked: RawRepresentable, Sendable where T: Sendable { /// To keep the implementation of this type as simple as possible, /// `pthread_mutex_t` is used on Apple platforms instead of `os_unfair_lock` /// or `OSAllocatedUnfairLock`. -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) private typealias _Lock = pthread_mutex_t #elseif os(Windows) private typealias _Lock = SRWLOCK @@ -52,7 +52,7 @@ struct Locked: RawRepresentable, Sendable where T: Sendable { private final class _Storage: ManagedBuffer { deinit { withUnsafeMutablePointerToElements { lock in -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) _ = pthread_mutex_destroy(lock) #elseif os(Windows) // No deinitialization needed. @@ -71,7 +71,7 @@ struct Locked: RawRepresentable, Sendable where T: Sendable { init(rawValue: T) { _storage = _Storage.create(minimumCapacity: 1, makingHeaderWith: { _ in rawValue }) _storage.withUnsafeMutablePointerToElements { lock in -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) _ = pthread_mutex_init(lock, nil) #elseif os(Windows) InitializeSRWLock(lock) @@ -101,7 +101,7 @@ struct Locked: RawRepresentable, Sendable where T: Sendable { /// concurrency tools. nonmutating func withLock(_ body: (inout T) throws -> R) rethrows -> R { try _storage.withUnsafeMutablePointers { rawValue, lock in -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) _ = pthread_mutex_lock(lock) defer { _ = pthread_mutex_unlock(lock) @@ -121,7 +121,7 @@ struct Locked: RawRepresentable, Sendable where T: Sendable { } } -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) /// Acquire the lock and invoke a function while it is held, yielding both the /// protected value and a reference to the lock itself. /// diff --git a/Sources/Testing/Support/Versions.swift b/Sources/Testing/Support/Versions.swift index 7bb68ab25..592722486 100644 --- a/Sources/Testing/Support/Versions.swift +++ b/Sources/Testing/Support/Versions.swift @@ -31,7 +31,7 @@ let operatingSystemVersion: String = { default: return "\(productVersion) (\(buildNumber))" } -#elseif !SWT_NO_UNAME && (SWT_TARGET_OS_APPLE || os(Linux) || os(WASI)) +#elseif !SWT_NO_UNAME && (SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD)) var name = utsname() if 0 == uname(&name) { let release = withUnsafeBytes(of: name.release) { release in diff --git a/Sources/Testing/Traits/Tags/Tag.Color+Loading.swift b/Sources/Testing/Traits/Tags/Tag.Color+Loading.swift index 899eaa031..3e3682e6f 100644 --- a/Sources/Testing/Traits/Tags/Tag.Color+Loading.swift +++ b/Sources/Testing/Traits/Tags/Tag.Color+Loading.swift @@ -11,7 +11,7 @@ private import _TestingInternals #if !SWT_NO_FILE_IO -#if os(macOS) || (os(iOS) && targetEnvironment(macCatalyst)) || os(Linux) +#if os(macOS) || (os(iOS) && targetEnvironment(macCatalyst)) || os(Linux) || os(FreeBSD) /// The path to the current user's home directory, if known. private var _homeDirectoryPath: String? { #if SWT_TARGET_OS_APPLE @@ -57,7 +57,7 @@ var swiftTestingDirectoryPath: String? { // The (default) name of the .swift-testing directory. let swiftTestingDirectoryName = ".swift-testing" -#if os(macOS) || (os(iOS) && targetEnvironment(macCatalyst)) || os(Linux) +#if os(macOS) || (os(iOS) && targetEnvironment(macCatalyst)) || os(Linux) || os(FreeBSD) if let homeDirectoryPath = _homeDirectoryPath { return appendPathComponent(swiftTestingDirectoryName, to: homeDirectoryPath) } diff --git a/Sources/_TestingInternals/Discovery.cpp b/Sources/_TestingInternals/Discovery.cpp index bd8f4a114..6e0551829 100644 --- a/Sources/_TestingInternals/Discovery.cpp +++ b/Sources/_TestingInternals/Discovery.cpp @@ -306,7 +306,7 @@ static void enumerateTypeMetadataSections(const SectionEnumerator& body) { } } -#elif defined(__linux__) || defined(_WIN32) || defined(__wasi__) || defined(__ANDROID__) +#elif defined(__linux__) || defined(__FreeBSD__) || defined(_WIN32) || defined(__wasi__) || defined(__ANDROID__) #pragma mark - Linux/Windows implementation /// Specifies the address range corresponding to a section. diff --git a/Sources/_TestingInternals/include/Stubs.h b/Sources/_TestingInternals/include/Stubs.h index b02eb4b0c..47d97681c 100644 --- a/Sources/_TestingInternals/include/Stubs.h +++ b/Sources/_TestingInternals/include/Stubs.h @@ -85,7 +85,7 @@ static LANGID swt_MAKELANGID(int p, int s) { } #endif -#if defined(__linux__) || defined(__ANDROID__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__ANDROID__) /// The environment block. /// /// By POSIX convention, the environment block variable is declared in client diff --git a/Tests/TestingTests/ABIEntryPointTests.swift b/Tests/TestingTests/ABIEntryPointTests.swift index c1dd6494b..3dded5e8a 100644 --- a/Tests/TestingTests/ABIEntryPointTests.swift +++ b/Tests/TestingTests/ABIEntryPointTests.swift @@ -127,7 +127,7 @@ struct ABIEntryPointTests { passing arguments: __CommandLineArguments_v0, recordHandler: @escaping @Sendable (_ recordJSON: UnsafeRawBufferPointer) -> Void = { _ in } ) async throws -> Bool { -#if !os(Linux) && !os(Android) && !SWT_NO_DYNAMIC_LINKING +#if !os(Linux) && !os(FreeBSD) && !os(Android) && !SWT_NO_DYNAMIC_LINKING // Get the ABI entry point by dynamically looking it up at runtime. // // NOTE: The standard Linux linker does not allow exporting symbols from diff --git a/Tests/TestingTests/ExitTestTests.swift b/Tests/TestingTests/ExitTestTests.swift index fad1da180..5c4ab7b47 100644 --- a/Tests/TestingTests/ExitTestTests.swift +++ b/Tests/TestingTests/ExitTestTests.swift @@ -204,12 +204,21 @@ private import _TestingInternals #if !os(Linux) @Test("Exit test reports > 8 bits of the exit code") func fullWidthExitCode() async { - // On macOS and Linux, we use waitid() which per POSIX should report the - // full exit code, not just the low 8 bits. This behaviour is not - // well-documented and while Darwin correctly reports the full value, Linux - // does not (at least as of this writing) and other POSIX-like systems may - // also have issues. This test serves as a canary when adding new platforms - // that we need to document the difference. + // On POSIX-like platforms, we use waitid() which per POSIX should report + // the full exit code, not just the low 8 bits. This behaviour is not + // well-documented and not all platforms (as of this writing) report the + // full value: + // + // | Platform | Bits Reported | + // |----------------------|----------------| + // | Darwin | 32 | + // | Linux | 8 | + // | Windows | 32 (see below) | + // | FreeBSD | 32 | + // + // Other platforms may also have issues reporting the full value. This test + // serves as a canary when adding new platforms that we need to document the + // difference. // // Windows does not have the 8-bit exit code restriction and always reports // the full CInt value back to the testing library. diff --git a/Tests/TestingTests/Support/EnvironmentTests.swift b/Tests/TestingTests/Support/EnvironmentTests.swift index 0735da7e9..a4fb8ddd9 100644 --- a/Tests/TestingTests/Support/EnvironmentTests.swift +++ b/Tests/TestingTests/Support/EnvironmentTests.swift @@ -90,7 +90,7 @@ extension Environment { environment[name] = value } return true -#elseif SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || os(WASI) +#elseif SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || os(WASI) if let value { return 0 == setenv(name, value, 1) } diff --git a/Tests/TestingTests/Support/FileHandleTests.swift b/Tests/TestingTests/Support/FileHandleTests.swift index 7d9d5545a..977264010 100644 --- a/Tests/TestingTests/Support/FileHandleTests.swift +++ b/Tests/TestingTests/Support/FileHandleTests.swift @@ -14,7 +14,7 @@ private import _TestingInternals #if !SWT_NO_FILE_IO // NOTE: we don't run these tests on iOS (etc.) because processes on those // platforms are sandboxed and do not have arbitrary filesystem access. -#if os(macOS) || os(Linux) || os(Android) || os(Windows) +#if os(macOS) || os(Linux) || os(FreeBSD) || os(Android) || os(Windows) @Suite("FileHandle Tests") struct FileHandleTests { // FileHandle is non-copyable, so it cannot yet be used as a test parameter. @@ -224,7 +224,7 @@ func temporaryDirectory() throws -> String { } return try #require(Environment.variable(named: "TMPDIR")) } -#elseif os(Linux) +#elseif os(Linux) || os(FreeBSD) "/tmp" #elseif os(Android) Environment.variable(named: "TMPDIR") ?? "/data/local/tmp"