Skip to content

Add speculative support for OpenBSD. #890

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

Merged
merged 3 commits into from
Jan 6, 2025
Merged
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
2 changes: 1 addition & 1 deletion Documentation/Porting.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ platform conditional and provide a stub implementation:
+++ b/Sources/Testing/Support/FileHandle.swift

var isTTY: Bool {
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || os(WASI)
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI)
// ...
+#elseif os(Classic)
+ return false
Expand Down
8 changes: 4 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ let package = Package(
cxxSettings: .packageSettings,
swiftSettings: .packageSettings,
linkerSettings: [
.linkedLibrary("execinfo", .when(platforms: [.custom("freebsd")]))
.linkedLibrary("execinfo", .when(platforms: [.custom("freebsd"), .openbsd]))
]
),
.testTarget(
Expand Down Expand Up @@ -127,7 +127,7 @@ let package = Package(
)

// BUG: swift-package-manager-#6367
#if !os(Windows) && !os(FreeBSD)
#if !os(Windows) && !os(FreeBSD) && !os(OpenBSD)
package.targets.append(contentsOf: [
.testTarget(
name: "TestingMacrosTests",
Expand Down Expand Up @@ -156,7 +156,7 @@ extension Array where Element == PackageDescription.SwiftSetting {

.define("SWT_NO_EXIT_TESTS", .when(platforms: [.iOS, .watchOS, .tvOS, .visionOS, .wasi, .android])),
.define("SWT_NO_PROCESS_SPAWNING", .when(platforms: [.iOS, .watchOS, .tvOS, .visionOS, .wasi, .android])),
.define("SWT_NO_SNAPSHOT_TYPES", .when(platforms: [.linux, .custom("freebsd"), .windows, .wasi])),
.define("SWT_NO_SNAPSHOT_TYPES", .when(platforms: [.linux, .custom("freebsd"), .openbsd, .windows, .wasi])),
.define("SWT_NO_DYNAMIC_LINKING", .when(platforms: [.wasi])),
.define("SWT_NO_PIPES", .when(platforms: [.wasi])),
]
Expand Down Expand Up @@ -191,7 +191,7 @@ extension Array where Element == PackageDescription.CXXSetting {
result += [
.define("SWT_NO_EXIT_TESTS", .when(platforms: [.iOS, .watchOS, .tvOS, .visionOS, .wasi, .android])),
.define("SWT_NO_PROCESS_SPAWNING", .when(platforms: [.iOS, .watchOS, .tvOS, .visionOS, .wasi, .android])),
.define("SWT_NO_SNAPSHOT_TYPES", .when(platforms: [.linux, .custom("freebsd"), .windows, .wasi])),
.define("SWT_NO_SNAPSHOT_TYPES", .when(platforms: [.linux, .custom("freebsd"), .openbsd, .windows, .wasi])),
.define("SWT_NO_DYNAMIC_LINKING", .when(platforms: [.wasi])),
.define("SWT_NO_PIPES", .when(platforms: [.wasi])),
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,23 @@ private func _compressContentsOfDirectory(at directoryURL: URL) async throws ->
//
// On Linux (which does not have FreeBSD's version of tar(1)), we can use
// zip(1) instead.
//
// OpenBSD's tar(1) does not support writing PKZIP archives, and /usr/bin/zip
// tool is an optional install, so we check if it's present before trying to
// execute it.
#if os(Linux)
let archiverPath = "/usr/bin/zip"
#elseif SWT_TARGET_OS_APPLE || os(FreeBSD)
let archiverPath = "/usr/bin/tar"
#elseif os(OpenBSD)
let archiverPath = "/usr/local/bin/zip"
var isDirectory = false
if !FileManager.default.fileExists(atPath: archiverPath, isDirectory: &isDirectory) || isDirectory {
throw CocoaError(.fileNoSuchFile, userInfo: [
NSLocalizedDescriptionKey: "The 'zip' package is not installed.",
NSFilePathErrorKey: archiverPath
])
}
#elseif os(Windows)
guard let archiverPath = _archiverPath else {
throw CocoaError(.fileWriteUnknown, userInfo: [
Expand All @@ -187,7 +200,7 @@ private func _compressContentsOfDirectory(at directoryURL: URL) async throws ->

let sourcePath = directoryURL.fileSystemPath
let destinationPath = temporaryURL.fileSystemPath
#if os(Linux)
#if os(Linux) || os(OpenBSD)
// The zip command constructs relative paths from the current working
// directory rather than from command-line arguments.
process.arguments = [destinationPath, "--recurse-paths", "."]
Expand Down
6 changes: 3 additions & 3 deletions Sources/Testing/ABI/EntryPoints/EntryPoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,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(FreeBSD) || os(Android)
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android)
if let termVariable = Environment.variable(named: "TERM") {
return termVariable != "dumb"
}
Expand All @@ -678,7 +678,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(FreeBSD) || os(Android)
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android)
if let termVariable = Environment.variable(named: "TERM") {
return strstr(termVariable, "256") != nil
}
Expand All @@ -700,7 +700,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(FreeBSD) || os(Android)
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android)
if let colortermVariable = Environment.variable(named: "COLORTERM") {
return strstr(colortermVariable, "truecolor") != nil
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Testing/ABI/EntryPoints/SwiftPMEntryPoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(FreeBSD) || os(Android) || os(WASI)
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI)
EX_UNAVAILABLE
#elseif os(Windows)
CInt(ERROR_NOT_FOUND)
Expand Down
2 changes: 1 addition & 1 deletion Sources/Testing/Events/Recorder/Event.Symbol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,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(FreeBSD) || os(Android) || os(WASI)
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI)
switch self {
case .default:
// Unicode: WHITE DIAMOND
Expand Down
10 changes: 6 additions & 4 deletions Sources/Testing/ExitTests/ExitCondition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ public enum ExitCondition: Sendable {
/// | macOS | [`<stdlib.h>`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/_Exit.3.html), [`<sysexits.h>`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/sysexits.3.html) |
/// | Linux | [`<stdlib.h>`](https://sourceware.org/glibc/manual/latest/html_node/Exit-Status.html), `<sysexits.h>` |
/// | FreeBSD | [`<stdlib.h>`](https://man.freebsd.org/cgi/man.cgi?exit(3)), [`<sysexits.h>`](https://man.freebsd.org/cgi/man.cgi?sysexits(3)) |
/// | OpenBSD | [`<stdlib.h>`](https://man.openbsd.org/exit.3), [`<sysexits.h>`](https://man.openbsd.org/sysexits.3) |
/// | Windows | [`<stdlib.h>`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure) |
///
/// 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&ndash;255) of the exit
/// code.
/// On macOS, FreeBSD, OpenBSD, 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&ndash;255) of
/// the exit code.
case exitCode(_ exitCode: CInt)

/// The process terminated with the given signal.
Expand All @@ -70,6 +71,7 @@ public enum ExitCondition: Sendable {
/// | macOS | [`<signal.h>`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/signal.3.html) |
/// | Linux | [`<signal.h>`](https://sourceware.org/glibc/manual/latest/html_node/Standard-Signals.html) |
/// | FreeBSD | [`<signal.h>`](https://man.freebsd.org/cgi/man.cgi?signal(3)) |
/// | OpenBSD | [`<signal.h>`](https://man.openbsd.org/signal.3) |
/// | Windows | [`<signal.h>`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/signal-constants) |
case signal(_ signal: CInt)
}
Expand Down
18 changes: 13 additions & 5 deletions Sources/Testing/ExitTests/ExitTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ extension ExitTest {
// SEE: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/coredump.c#n610
var rl = rlimit(rlim_cur: 1, rlim_max: 1)
_ = setrlimit(CInt(RLIMIT_CORE.rawValue), &rl)
#elseif os(FreeBSD)
// As with Linux, disable the generation core files. FreeBSD does not, as
// far as I can tell, special-case RLIMIT_CORE=1.
#elseif os(FreeBSD) || os(OpenBSD)
// As with Linux, disable the generation core files. The BSDs do not, as far
// as I can tell, special-case RLIMIT_CORE=1.
var rl = rlimit(rlim_cur: 0, rlim_max: 0)
_ = setrlimit(RLIMIT_CORE, &rl)
#elseif os(Windows)
Expand Down Expand Up @@ -152,6 +152,14 @@ extension ExitTest {
}
#endif

#if os(OpenBSD)
// OpenBSD does not have posix_spawn_file_actions_addclosefrom_np().
// However, it does have closefrom(2), which we call here as a best effort.
if let from = Environment.variable(named: "SWT_CLOSEFROM").flatMap(CInt.init) {
_ = closefrom(from)
}
#endif

do {
try await body()
} catch {
Expand Down Expand Up @@ -344,7 +352,7 @@ extension ExitTest {
}

var fd: CInt?
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD)
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD)
fd = CInt(backChannelEnvironmentVariable)
#elseif os(Windows)
if let handle = UInt(backChannelEnvironmentVariable).flatMap(HANDLE.init(bitPattern:)) {
Expand Down Expand Up @@ -541,7 +549,7 @@ extension ExitTest {
// known environment variable to the corresponding file descriptor
// (HANDLE on Windows.)
var backChannelEnvironmentVariable: String?
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD)
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD)
backChannelEnvironmentVariable = backChannelWriteEnd.withUnsafePOSIXFileDescriptor { fd in
fd.map(String.init(describing:))
}
Expand Down
19 changes: 11 additions & 8 deletions Sources/Testing/ExitTests/SpawnProcess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal import _TestingInternals

/// A platform-specific value identifying a process running on the current
/// system.
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD)
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD)
typealias ProcessID = pid_t
#elseif os(Windows)
typealias ProcessID = HANDLE
Expand Down Expand Up @@ -62,13 +62,13 @@ func spawnExecutable(
) throws -> ProcessID {
// Darwin and Linux differ in their optionality for the posix_spawn types we
// use, so use this typealias to paper over the differences.
#if SWT_TARGET_OS_APPLE || os(FreeBSD)
#if SWT_TARGET_OS_APPLE || os(FreeBSD) || os(OpenBSD)
typealias P<T> = T?
#elseif os(Linux)
typealias P<T> = T
#endif

#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD)
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD)
return try withUnsafeTemporaryAllocation(of: P<posix_spawn_file_actions_t>.self, capacity: 1) { fileActions in
let fileActions = fileActions.baseAddress!
guard 0 == posix_spawn_file_actions_init(fileActions) else {
Expand Down Expand Up @@ -105,9 +105,7 @@ func spawnExecutable(
}

// Forward standard I/O streams and any explicitly added file handles.
#if os(Linux) || os(FreeBSD)
var highestFD = CInt(-1)
#endif
var highestFD = max(STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)
func inherit(_ fileHandle: borrowing FileHandle, as standardFD: CInt? = nil) throws {
try fileHandle.withUnsafePOSIXFileDescriptor { fd in
guard let fd else {
Expand All @@ -118,9 +116,8 @@ func spawnExecutable(
} else {
#if SWT_TARGET_OS_APPLE
_ = posix_spawn_file_actions_addinherit_np(fileActions, fd)
#elseif os(Linux) || os(FreeBSD)
highestFD = max(highestFD, fd)
#endif
highestFD = max(highestFD, fd)
}
}
}
Expand Down Expand Up @@ -156,6 +153,12 @@ func spawnExecutable(
// `swt_posix_spawn_file_actions_addclosefrom_np` to guard the
// availability of this function.
_ = posix_spawn_file_actions_addclosefrom_np(fileActions, highestFD + 1)
#elseif os(OpenBSD)
// OpenBSD does not have posix_spawn_file_actions_addclosefrom_np().
// However, it does have closefrom(2), which we can call from within the
// spawned child process if we control its execution.
var environment = environment
environment["SWT_CLOSEFROM"] = String(describing: highestFD + 1)
#else
#warning("Platform-specific implementation missing: cannot close unused file descriptors")
#endif
Expand Down
14 changes: 8 additions & 6 deletions Sources/Testing/ExitTests/WaitFor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#if !SWT_NO_PROCESS_SPAWNING
internal import _TestingInternals

#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD)
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD)
/// Block the calling thread, wait for the target process to exit, and return
/// a value describing the conditions under which it exited.
///
Expand Down Expand Up @@ -78,14 +78,14 @@ func wait(for pid: consuming pid_t) async throws -> ExitCondition {

return try _blockAndWait(for: pid)
}
#elseif SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD)
#elseif SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD)
/// A mapping of awaited child PIDs to their corresponding Swift continuations.
private let _childProcessContinuations = Locked<[pid_t: CheckedContinuation<ExitCondition, any Error>]>()

/// A condition variable used to suspend the waiter thread created by
/// `_createWaitThread()` when there are no child processes to await.
private nonisolated(unsafe) let _waitThreadNoChildrenCondition = {
#if os(FreeBSD)
#if os(FreeBSD) || os(OpenBSD)
let result = UnsafeMutablePointer<pthread_cond_t?>.allocate(capacity: 1)
#else
let result = UnsafeMutablePointer<pthread_cond_t>.allocate(capacity: 1)
Expand Down Expand Up @@ -136,7 +136,7 @@ private let _createWaitThread: Void = {

// Create the thread. It will run immediately; because it runs in an infinite
// loop, we aren't worried about detaching or joining it.
#if SWT_TARGET_OS_APPLE || os(FreeBSD)
#if SWT_TARGET_OS_APPLE || os(FreeBSD) || os(OpenBSD)
var thread: pthread_t?
#else
var thread = pthread_t()
Expand All @@ -147,14 +147,16 @@ private let _createWaitThread: Void = {
{ _ in
// Set the thread name to help with diagnostics. Note that different
// platforms support different thread name lengths. See MAXTHREADNAMESIZE
// on Darwin, TASK_COMM_LEN on Linux, and MAXCOMLEN on FreeBSD. We try to
// maximize legibility in the available space.
// on Darwin, TASK_COMM_LEN on Linux, MAXCOMLEN on FreeBSD, and _MAXCOMLEN
// on OpenBSD. We try to maximize legibility in the available space.
#if SWT_TARGET_OS_APPLE
_ = pthread_setname_np("Swift Testing exit test monitor")
#elseif os(Linux)
_ = swt_pthread_setname_np(pthread_self(), "SWT ExT monitor")
#elseif os(FreeBSD)
_ = pthread_set_name_np(pthread_self(), "SWT ex test monitor")
#elseif os(OpenBSD)
_ = pthread_set_name_np(pthread_self(), "SWT exit test monitor")
#else
#warning("Platform-specific implementation missing: thread naming unavailable")
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ extension Backtrace {
result[i] = SymbolicatedAddress(address: address, offset: offset, symbolName: symbolName)
}
}
#elseif os(Linux) || os(FreeBSD) || os(Android)
#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || 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
Expand Down
4 changes: 2 additions & 2 deletions Sources/Testing/SourceAttribution/Backtrace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) || os(FreeBSD)
#elseif os(Linux) || os(FreeBSD) || os(OpenBSD)
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))
Expand Down Expand Up @@ -181,7 +181,7 @@ extension Backtrace {
/// crash. To avoid said crash, we'll keep a strong reference to the
/// object (abandoning memory until the process exits.)
/// ([swift-#62985](https://github.com/swiftlang/swift/issues/62985))
#if os(Windows) || os(FreeBSD)
#if os(Windows) || os(FreeBSD) || os(OpenBSD)
nonisolated(unsafe) var errorObject: AnyObject?
#else
nonisolated(unsafe) weak var errorObject: AnyObject?
Expand Down
10 changes: 9 additions & 1 deletion Sources/Testing/Support/Additions/CommandLineAdditions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ extension CommandLine {
return String(cString: buffer.baseAddress!)
}
}
#elseif os(OpenBSD)
// OpenBSD does not have API to get a path to the running executable. Use
// arguments[0]. We do a basic sniff test for a path-like string, but
// otherwise return argv[0] verbatim.
guard let argv0 = arguments.first, argv0.contains("/") else {
throw CError(rawValue: ENOEXEC)
}
return argv0
#elseif os(Windows)
var result: String?
#if DEBUG
Expand Down Expand Up @@ -87,7 +95,7 @@ extension CommandLine {
return arguments[0]
#else
#warning("Platform-specific implementation missing: executable path unavailable")
return ""
throw SystemError(description: "The executable path of the current process could not be determined.")
#endif
}
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/Testing/Support/CError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ func strerror(_ errorCode: CInt) -> String {
_ = strerror_s(buffer.baseAddress!, buffer.count, errorCode)
return strnlen(buffer.baseAddress!, buffer.count)
}
#elseif os(FreeBSD)
// FreeBSD's implementation of strerror() is not thread-safe.
#elseif os(FreeBSD) || os(OpenBSD)
// FreeBSD's/OpenBSD's implementation of strerror() is not thread-safe.
String(unsafeUninitializedCapacity: 1024) { buffer in
_ = strerror_r(errorCode, buffer.baseAddress!, buffer.count)
return strnlen(buffer.baseAddress!, buffer.count)
Expand Down
6 changes: 3 additions & 3 deletions Sources/Testing/Support/Environment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ enum Environment {
}
}

#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || os(WASI)
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI)
/// Get all environment variables from a POSIX environment block.
///
/// - Parameters:
Expand Down Expand Up @@ -103,7 +103,7 @@ enum Environment {
}
#endif
return _get(fromEnviron: _NSGetEnviron()!.pointee!)
#elseif os(Linux) || os(FreeBSD) || os(Android)
#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android)
_get(fromEnviron: swt_environ())
#elseif os(WASI)
_get(fromEnviron: __wasilibc_get_environ())
Expand Down Expand Up @@ -170,7 +170,7 @@ enum Environment {
}
return nil
}
#elseif SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || os(WASI)
#elseif SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI)
getenv(name).flatMap { String(validatingCString: $0) }
#elseif os(Windows)
name.withCString(encodedAs: UTF16.self) { name in
Expand Down
Loading