From 66ede866b21d2c2b546f4020cd7f8afcffae3776 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 29 Feb 2024 10:20:27 -0800 Subject: [PATCH 1/9] Foundation: repair the build for Android API level 28+ The newer level introduces APIs with additional nullability attribution. This causes issues as the attribution sometimes collides with expectations. Unwrap more cases to appease the nullability attributes. One problematic area of this change is the handling for `Process.run()`. The posix spawn APIs are described as: ``` typedef struct __posix_spawnattr* posix_spawnattr_t; int posix_spawnattr_init(posix_spawnattr_t _Nonnull * _Nonnull __attr); ``` As the inner `_Nonnull` appertains to `posix_spawnattr_t`, it expects a non-null pointer to a non-null pointer. However, as `struct __posix_spawnattr` is opaque, we cannot allocate space for it and thus must be acceptable to take a pointer to null to permit the allocation. --- Sources/Foundation/FileHandle.swift | 2 +- Sources/Foundation/FileManager+POSIX.swift | 24 +++++++++++++--------- Sources/Foundation/FileManager.swift | 8 ++++---- Sources/Foundation/Host.swift | 2 +- Sources/Foundation/Process.swift | 7 +++++++ 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Sources/Foundation/FileHandle.swift b/Sources/Foundation/FileHandle.swift index 72ab09a3f6..d90234039d 100644 --- a/Sources/Foundation/FileHandle.swift +++ b/Sources/Foundation/FileHandle.swift @@ -324,7 +324,7 @@ open class FileHandle : NSObject { let data = mmap(nil, mapSize, PROT_READ, MAP_PRIVATE, _fd, 0) // Swift does not currently expose MAP_FAILURE if data != UnsafeMutableRawPointer(bitPattern: -1) { - return NSData.NSDataReadResult(bytes: data!, length: mapSize) { buffer, length in + return NSData.NSDataReadResult(bytes: data, length: mapSize) { buffer, length in munmap(buffer, length) } } diff --git a/Sources/Foundation/FileManager+POSIX.swift b/Sources/Foundation/FileManager+POSIX.swift index 73d8171832..3d8cf06cb0 100644 --- a/Sources/Foundation/FileManager+POSIX.swift +++ b/Sources/Foundation/FileManager+POSIX.swift @@ -803,17 +803,19 @@ extension FileManager { let ps = UnsafeMutablePointer?>.allocate(capacity: 2) ps.initialize(to: UnsafeMutablePointer(mutating: fsRep)) ps.advanced(by: 1).initialize(to: nil) - let stream = fts_open(ps, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR | FTS_NOSTAT, nil) + let stream = ps.withMemoryRebound(to: UnsafeMutablePointer.self, capacity: 2) { + fts_open($0, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR | FTS_NOSTAT, nil) + } ps.deinitialize(count: 2) ps.deallocate() - if stream != nil { + if let stream { defer { fts_close(stream) } - while let current = fts_read(stream)?.pointee { - let itemPath = string(withFileSystemRepresentation: current.fts_path, length: Int(current.fts_pathlen)) + while let current = fts_read(stream)?.pointee, let fts_path = current.fts_path { + let itemPath = string(withFileSystemRepresentation: fts_path, length: Int(current.fts_pathlen)) guard alreadyConfirmed || shouldRemoveItemAtPath(itemPath, isURL: isURL) else { continue } @@ -821,11 +823,11 @@ extension FileManager { do { switch Int32(current.fts_info) { case FTS_DEFAULT, FTS_F, FTS_NSOK, FTS_SL, FTS_SLNONE: - if unlink(current.fts_path) == -1 { + if unlink(fts_path) == -1 { throw _NSErrorWithErrno(errno, reading: false, path: itemPath) } case FTS_DP: - if rmdir(current.fts_path) == -1 { + if rmdir(fts_path) == -1 { throw _NSErrorWithErrno(errno, reading: false, path: itemPath) } case FTS_DNR, FTS_ERR, FTS_NS: @@ -1171,7 +1173,9 @@ extension FileManager { defer { ps.deallocate() } ps.initialize(to: UnsafeMutablePointer(mutating: fsRep)) ps.advanced(by: 1).initialize(to: nil) - return fts_open(ps, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR | FTS_NOSTAT, nil) + return ps.withMemoryRebound(to: UnsafeMutablePointer.self, capacity: 2) { + fts_open($0, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR | FTS_NOSTAT, nil) + } } if _stream == nil { throw _NSErrorWithErrno(errno, reading: true, url: url) @@ -1218,13 +1222,13 @@ extension FileManager { _current = fts_read(stream) while let current = _current { - let filename = FileManager.default.string(withFileSystemRepresentation: current.pointee.fts_path, length: Int(current.pointee.fts_pathlen)) + let filename = FileManager.default.string(withFileSystemRepresentation: current.pointee.fts_path!, length: Int(current.pointee.fts_pathlen)) switch Int32(current.pointee.fts_info) { case FTS_D: let (showFile, skipDescendants) = match(filename: filename, to: _options, isDir: true) if skipDescendants { - fts_set(_stream, _current, FTS_SKIP) + fts_set(stream, _current!, FTS_SKIP) } if showFile { return URL(fileURLWithPath: filename, isDirectory: true) @@ -1398,7 +1402,7 @@ extension FileManager { let finalErrno = originalItemURL.withUnsafeFileSystemRepresentation { (originalFS) -> Int32? in return newItemURL.withUnsafeFileSystemRepresentation { (newItemFS) -> Int32? in // This is an atomic operation in many OSes, but is not guaranteed to be atomic by the standard. - if rename(newItemFS, originalFS) == 0 { + if rename(newItemFS!, originalFS!) == 0 { return nil } else { return errno diff --git a/Sources/Foundation/FileManager.swift b/Sources/Foundation/FileManager.swift index fdd8411511..0b229748f6 100644 --- a/Sources/Foundation/FileManager.swift +++ b/Sources/Foundation/FileManager.swift @@ -579,13 +579,13 @@ open class FileManager : NSObject { #elseif os(WASI) let type = FileAttributeType(statMode: mode_t(s.st_mode)) #else - if let pwd = getpwuid(s.st_uid), pwd.pointee.pw_name != nil { - let name = String(cString: pwd.pointee.pw_name) + if let pwd = getpwuid(s.st_uid), let pw_name = pwd.pointee.pw_name { + let name = String(cString: pw_name) result[.ownerAccountName] = name } - if let grd = getgrgid(s.st_gid), grd.pointee.gr_name != nil { - let name = String(cString: grd.pointee.gr_name) + if let grd = getgrgid(s.st_gid), let gr_name = grd.pointee.gr_name { + let name = String(cString: gr_name) result[.groupOwnerAccountName] = name } diff --git a/Sources/Foundation/Host.swift b/Sources/Foundation/Host.swift index b5205ebb76..ffba6c4093 100644 --- a/Sources/Foundation/Host.swift +++ b/Sources/Foundation/Host.swift @@ -24,7 +24,7 @@ import WinSDK } // getnameinfo uses size_t for its 4th and 6th arguments. - private func getnameinfo(_ addr: UnsafePointer?, _ addrlen: socklen_t, _ host: UnsafeMutablePointer?, _ hostlen: socklen_t, _ serv: UnsafeMutablePointer?, _ servlen: socklen_t, _ flags: Int32) -> Int32 { + private func getnameinfo(_ addr: UnsafePointer, _ addrlen: socklen_t, _ host: UnsafeMutablePointer?, _ hostlen: socklen_t, _ serv: UnsafeMutablePointer?, _ servlen: socklen_t, _ flags: Int32) -> Int32 { return Glibc.getnameinfo(addr, addrlen, host, Int(hostlen), serv, Int(servlen), flags) } diff --git a/Sources/Foundation/Process.swift b/Sources/Foundation/Process.swift index 0f32045e49..68118a7608 100644 --- a/Sources/Foundation/Process.swift +++ b/Sources/Foundation/Process.swift @@ -928,6 +928,13 @@ open class Process: NSObject { var spawnAttrs: posix_spawnattr_t? = nil #else var spawnAttrs: posix_spawnattr_t = posix_spawnattr_t() +#endif +#if os(Android) + guard var spawnAttrs else { + throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: [ + NSURLErrorKey:self.executableURL! + ]) + } #endif try _throwIfPosixError(posix_spawnattr_init(&spawnAttrs)) try _throwIfPosixError(posix_spawnattr_setflags(&spawnAttrs, .init(POSIX_SPAWN_SETPGROUP))) From 44773d2810d3454db3de915d5e7c4eab2a1479b6 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 30 Apr 2024 09:03:02 -0700 Subject: [PATCH 2/9] [android] android build fixes --- CMakeLists.txt | 8 ++++++++ Sources/Foundation/Data.swift | 7 +++++++ Sources/Foundation/FileHandle.swift | 5 +++++ Sources/Foundation/FileManager+POSIX.swift | 8 ++++++-- Sources/Foundation/FileManager.swift | 16 ++++++++++------ Sources/Foundation/Host.swift | 3 ++- Sources/Foundation/NSData.swift | 2 ++ Sources/Foundation/NSError.swift | 2 ++ Sources/Foundation/NSLock.swift | 2 ++ Sources/Foundation/NSPathUtilities.swift | 2 +- Sources/Foundation/NSSwiftRuntime.swift | 2 ++ Sources/Foundation/NSURL.swift | 2 ++ Sources/Foundation/Port.swift | 12 +++++++++--- Sources/Foundation/Thread.swift | 2 ++ Sources/Tools/plutil/main.swift | 3 +++ 15 files changed, 63 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dac9a46f1..a929bec001 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,14 @@ if(HAS_LIBDISPATCH_API) find_package(Threads REQUIRED) endif() +# CMake's Threads adds '-pthread' flag to the interface link +# libraries, which isn't supported by Swift. This is not enabled +# when building with MSVC, but it trips up the Android build, so +# we need to clear out the threads INTERFACE_LINK_LIBRARIES. +if (CMAKE_SYSTEM_NAME STREQUAL "Android") + set_property(TARGET Threads::Threads PROPERTY INTERFACE_LINK_LIBRARIES "") +endif() + set(SAVED_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) set(BUILD_SHARED_LIBS NO) add_subdirectory(CoreFoundation EXCLUDE_FROM_ALL) diff --git a/Sources/Foundation/Data.swift b/Sources/Foundation/Data.swift index 9e5c9faf38..1ff532c670 100644 --- a/Sources/Foundation/Data.swift +++ b/Sources/Foundation/Data.swift @@ -42,6 +42,13 @@ @usableFromInline let memset = WASILibc.memset @usableFromInline let memcpy = WASILibc.memcpy @usableFromInline let memcmp = WASILibc.memcmp +#elseif canImport(Android) +@usableFromInline let calloc = Android.calloc +@usableFromInline let malloc = Android.malloc +@usableFromInline let free = Android.free +@usableFromInline let memset = Android.memset +@usableFromInline let memcpy = Android.memcpy +@usableFromInline let memcmp = Android.memcmp #endif #if !canImport(Darwin) diff --git a/Sources/Foundation/FileHandle.swift b/Sources/Foundation/FileHandle.swift index d90234039d..7c777254f3 100644 --- a/Sources/Foundation/FileHandle.swift +++ b/Sources/Foundation/FileHandle.swift @@ -34,6 +34,11 @@ import WASILibc fileprivate let _read = WASILibc.read(_:_:_:) fileprivate let _write = WASILibc.write(_:_:_:) fileprivate let _close = WASILibc.close(_:) +#elseif canImport(Android) +import Android +fileprivate let _read = Android.read(_:_:_:) +fileprivate let _write = Android.write(_:_:_:) +fileprivate let _close = Android.close(_:) #endif #if canImport(WinSDK) diff --git a/Sources/Foundation/FileManager+POSIX.swift b/Sources/Foundation/FileManager+POSIX.swift index 3d8cf06cb0..b3d6317e01 100644 --- a/Sources/Foundation/FileManager+POSIX.swift +++ b/Sources/Foundation/FileManager+POSIX.swift @@ -11,6 +11,10 @@ internal func &(left: UInt32, right: mode_t) -> mode_t { return mode_t(left) & right } +#elseif os(Android) +internal func &(left: mode_t, right: Int32) -> mode_t { + return left & mode_t(right) +} #endif #if os(WASI) @@ -409,7 +413,7 @@ extension FileManager { if !parent.isEmpty && !fileExists(atPath: parent, isDirectory: &isDir) { try createDirectory(atPath: parent, withIntermediateDirectories: true, attributes: attributes) } - if mkdir(pathFsRep, S_IRWXU | S_IRWXG | S_IRWXO) != 0 { + if mkdir(pathFsRep, mode_t(S_IRWXU) | mode_t(S_IRWXG) | mode_t(S_IRWXO)) != 0 { let posixError = errno if posixError == EEXIST && fileExists(atPath: path, isDirectory: &isDir) && isDir.boolValue { // Continue; if there is an existing file and it is a directory, that is still a success. @@ -428,7 +432,7 @@ extension FileManager { throw _NSErrorWithErrno(EEXIST, reading: false, path: path) } } else { - if mkdir(pathFsRep, S_IRWXU | S_IRWXG | S_IRWXO) != 0 { + if mkdir(pathFsRep, mode_t(S_IRWXU) | mode_t(S_IRWXG) | mode_t(S_IRWXO)) != 0 { throw _NSErrorWithErrno(errno, reading: false, path: path) } else if let attr = attributes { try self.setAttributes(attr, ofItemAtPath: path) diff --git a/Sources/Foundation/FileManager.swift b/Sources/Foundation/FileManager.swift index 0b229748f6..962206fb2b 100644 --- a/Sources/Foundation/FileManager.swift +++ b/Sources/Foundation/FileManager.swift @@ -25,6 +25,10 @@ import WinSDK import WASILibc #endif +#if os(Android) +import Android +#endif + #if os(Windows) internal typealias NativeFSRCharType = WCHAR internal let NativeFSREncoding = String.Encoding.utf16LittleEndian.rawValue @@ -1342,12 +1346,12 @@ public struct FileAttributeType : RawRepresentable, Equatable, Hashable { #else internal init(statMode: mode_t) { switch statMode & S_IFMT { - case S_IFCHR: self = .typeCharacterSpecial - case S_IFDIR: self = .typeDirectory - case S_IFBLK: self = .typeBlockSpecial - case S_IFREG: self = .typeRegular - case S_IFLNK: self = .typeSymbolicLink - case S_IFSOCK: self = .typeSocket + case mode_t(S_IFCHR): self = .typeCharacterSpecial + case mode_t(S_IFDIR): self = .typeDirectory + case mode_t(S_IFBLK): self = .typeBlockSpecial + case mode_t(S_IFREG): self = .typeRegular + case mode_t(S_IFLNK): self = .typeSymbolicLink + case mode_t(S_IFSOCK): self = .typeSocket default: self = .typeUnknown } } diff --git a/Sources/Foundation/Host.swift b/Sources/Foundation/Host.swift index ffba6c4093..02f301ac54 100644 --- a/Sources/Foundation/Host.swift +++ b/Sources/Foundation/Host.swift @@ -13,6 +13,7 @@ import WinSDK #endif #if os(Android) + import Android // Android Glibc differs a little with respect to the Linux Glibc. // IFF_LOOPBACK is part of the enumeration net_device_flags, which needs to @@ -25,7 +26,7 @@ import WinSDK // getnameinfo uses size_t for its 4th and 6th arguments. private func getnameinfo(_ addr: UnsafePointer, _ addrlen: socklen_t, _ host: UnsafeMutablePointer?, _ hostlen: socklen_t, _ serv: UnsafeMutablePointer?, _ servlen: socklen_t, _ flags: Int32) -> Int32 { - return Glibc.getnameinfo(addr, addrlen, host, Int(hostlen), serv, Int(servlen), flags) + return Android.getnameinfo(addr, addrlen, host, Int(hostlen), serv, Int(servlen), flags) } // getifaddrs and freeifaddrs are not available in Android 6.0 or earlier, so call these functions dynamically. diff --git a/Sources/Foundation/NSData.swift b/Sources/Foundation/NSData.swift index aaeeb9aeca..83a5b2b22f 100644 --- a/Sources/Foundation/NSData.swift +++ b/Sources/Foundation/NSData.swift @@ -495,6 +495,8 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { let createMode = Int(Musl.S_IRUSR) | Int(Musl.S_IWUSR) | Int(Musl.S_IRGRP) | Int(Musl.S_IWGRP) | Int(Musl.S_IROTH) | Int(Musl.S_IWOTH) #elseif canImport(WASILibc) let createMode = Int(WASILibc.S_IRUSR) | Int(WASILibc.S_IWUSR) | Int(WASILibc.S_IRGRP) | Int(WASILibc.S_IWGRP) | Int(WASILibc.S_IROTH) | Int(WASILibc.S_IWOTH) +#elseif canImport(Android) + let createMode = Int(Android.S_IRUSR) | Int(Android.S_IWUSR) | Int(Android.S_IRGRP) | Int(Android.S_IWGRP) | Int(Android.S_IROTH) | Int(Android.S_IWOTH) #endif guard let fh = FileHandle(path: path, flags: flags, createMode: createMode) else { throw _NSErrorWithErrno(errno, reading: false, path: path) diff --git a/Sources/Foundation/NSError.swift b/Sources/Foundation/NSError.swift index fc87a4d648..f05b503a2e 100644 --- a/Sources/Foundation/NSError.swift +++ b/Sources/Foundation/NSError.swift @@ -16,6 +16,8 @@ import Darwin import Glibc #elseif canImport(CRT) import CRT +#elseif canImport(Android) +import Android #endif @_implementationOnly import CoreFoundation diff --git a/Sources/Foundation/NSLock.swift b/Sources/Foundation/NSLock.swift index 0513bfd96e..5ca93cde37 100644 --- a/Sources/Foundation/NSLock.swift +++ b/Sources/Foundation/NSLock.swift @@ -11,6 +11,8 @@ #if canImport(Glibc) import Glibc +#elseif canImport(Android) +import Android #endif #if os(Windows) diff --git a/Sources/Foundation/NSPathUtilities.swift b/Sources/Foundation/NSPathUtilities.swift index 91e7ccba44..532d451049 100644 --- a/Sources/Foundation/NSPathUtilities.swift +++ b/Sources/Foundation/NSPathUtilities.swift @@ -803,7 +803,7 @@ internal func _NSCreateTemporaryFile(_ filePath: String) throws -> (Int32, Strin } // Set the file mode to match macOS - guard fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) != -1 else { + guard fchmod(fd, mode_t(S_IRUSR) | mode_t(S_IWUSR) | mode_t(S_IRGRP) | mode_t(S_IWGRP) | mode_t(S_IROTH) | mode_t(S_IWOTH)) != -1 else { let _errno = errno close(fd) throw _NSErrorWithErrno(_errno, reading: false, path: pathResult) diff --git a/Sources/Foundation/NSSwiftRuntime.swift b/Sources/Foundation/NSSwiftRuntime.swift index c079ed6259..c15217ab05 100644 --- a/Sources/Foundation/NSSwiftRuntime.swift +++ b/Sources/Foundation/NSSwiftRuntime.swift @@ -18,6 +18,8 @@ @_exported import Glibc #elseif canImport(Musl) @_exported import Musl +#elseif canImport(Android) +@_exported import Android #elseif os(WASI) @_exported import WASILibc #elseif os(Windows) diff --git a/Sources/Foundation/NSURL.swift b/Sources/Foundation/NSURL.swift index 4d31e2ba9c..6169613b29 100644 --- a/Sources/Foundation/NSURL.swift +++ b/Sources/Foundation/NSURL.swift @@ -22,6 +22,8 @@ import Darwin import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #endif // NOTE: this represents PLATFORM_PATH_STYLE diff --git a/Sources/Foundation/Port.swift b/Sources/Foundation/Port.swift index c53263f0ef..9f1823fe90 100644 --- a/Sources/Foundation/Port.swift +++ b/Sources/Foundation/Port.swift @@ -90,22 +90,28 @@ open class SocketPort: Port {} #else -#if canImport(Glibc) && !os(Android) && !os(OpenBSD) +#if canImport(Glibc) && !os(OpenBSD) import Glibc fileprivate let SOCK_STREAM = Int32(Glibc.SOCK_STREAM.rawValue) fileprivate let SOCK_DGRAM = Int32(Glibc.SOCK_DGRAM.rawValue) fileprivate let IPPROTO_TCP = Int32(Glibc.IPPROTO_TCP) #endif -#if canImport(Glibc) && os(Android) || os(OpenBSD) +#if canImport(Glibc) && os(OpenBSD) import Glibc fileprivate let SOCK_STREAM = Int32(Glibc.SOCK_STREAM) fileprivate let SOCK_DGRAM = Int32(Glibc.SOCK_DGRAM) fileprivate let IPPROTO_TCP = Int32(Glibc.IPPROTO_TCP) fileprivate let INADDR_ANY: in_addr_t = 0 -#if os(OpenBSD) fileprivate let INADDR_LOOPBACK = 0x7f000001 #endif + +#if canImport(Android) +import Android +fileprivate let SOCK_STREAM = Int32(Android.SOCK_STREAM) +fileprivate let SOCK_DGRAM = Int32(Android.SOCK_DGRAM) +fileprivate let IPPROTO_TCP = Int32(Android.IPPROTO_TCP) +fileprivate let INADDR_ANY: in_addr_t = 0 #endif diff --git a/Sources/Foundation/Thread.swift b/Sources/Foundation/Thread.swift index 166a5d3fe5..4f401987b4 100644 --- a/Sources/Foundation/Thread.swift +++ b/Sources/Foundation/Thread.swift @@ -17,6 +17,8 @@ import WinSDK import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #endif // WORKAROUND_SR9811 diff --git a/Sources/Tools/plutil/main.swift b/Sources/Tools/plutil/main.swift index d71d9ba9a2..bc35a1720d 100644 --- a/Sources/Tools/plutil/main.swift +++ b/Sources/Tools/plutil/main.swift @@ -15,6 +15,9 @@ import Glibc #elseif canImport(Musl) import Foundation import Musl +#elseif canImport(Android) +import Foundation +import Android #elseif canImport(CRT) import Foundation import CRT From 69cfa2789cb87acfbd5708f98c6ff6bbf6e3f5d9 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Mon, 6 May 2024 18:15:43 -0700 Subject: [PATCH 3/9] [android] fix android test builds to ensure they work with new Android overlay module --- Tests/Foundation/FTPServer.swift | 2 ++ Tests/Foundation/HTTPServer.swift | 2 ++ Tests/Foundation/Tests/TestFileHandle.swift | 9 ++++++++- Tests/Foundation/Tests/TestNSData.swift | 4 ++++ Tests/Foundation/Tests/TestTimeZone.swift | 7 ++++++- Tests/Foundation/main.swift | 2 ++ 6 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Tests/Foundation/FTPServer.swift b/Tests/Foundation/FTPServer.swift index 8bb4a9d779..a09fcae5f3 100644 --- a/Tests/Foundation/FTPServer.swift +++ b/Tests/Foundation/FTPServer.swift @@ -15,6 +15,8 @@ import Dispatch import Glibc #elseif canImport(Darwin) import Darwin +#elseif canImport(Android) + import Android #endif public class ServerSemaphore { diff --git a/Tests/Foundation/HTTPServer.swift b/Tests/Foundation/HTTPServer.swift index 5af9fb9c52..4616a3f6ab 100644 --- a/Tests/Foundation/HTTPServer.swift +++ b/Tests/Foundation/HTTPServer.swift @@ -21,6 +21,8 @@ import Dispatch import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #endif #if !os(Windows) diff --git a/Tests/Foundation/Tests/TestFileHandle.swift b/Tests/Foundation/Tests/TestFileHandle.swift index 5416c41c4e..82655a29da 100644 --- a/Tests/Foundation/Tests/TestFileHandle.swift +++ b/Tests/Foundation/Tests/TestFileHandle.swift @@ -111,7 +111,14 @@ class TestFileHandle : XCTestCase { #else var fds: [Int32] = [-1, -1] fds.withUnsafeMutableBufferPointer { (pointer) -> Void in - pipe(pointer.baseAddress) + let baseAddress = pointer.baseAddress +#if canImport(Android) + // pipe takes in a non-nullable pointer in the Android NDK only. + guard let baseAddress else { + return + } +#endif + pipe(baseAddress) } close(fds[1]) diff --git a/Tests/Foundation/Tests/TestNSData.swift b/Tests/Foundation/Tests/TestNSData.swift index 2c84f63360..7f72e0d0b8 100644 --- a/Tests/Foundation/Tests/TestNSData.swift +++ b/Tests/Foundation/Tests/TestNSData.swift @@ -589,6 +589,8 @@ class TestNSData: LoopbackServerTest { let permission = try fileManager._permissionsOfItem(atPath: url.path) #if canImport(Darwin) let expected = Int(S_IRUSR) | Int(S_IWUSR) | Int(S_IRGRP) | Int(S_IWGRP) | Int(S_IROTH) | Int(S_IWOTH) +#elseif canImport(Android) + let expected = Int(Android.S_IRUSR) | Int(Android.S_IWUSR) | Int(Android.S_IRGRP) | Int(Android.S_IWGRP) | Int(Android.S_IROTH) | Int(Android.S_IWOTH) #else let expected = Int(Glibc.S_IRUSR) | Int(Glibc.S_IWUSR) | Int(Glibc.S_IRGRP) | Int(Glibc.S_IWGRP) | Int(Glibc.S_IROTH) | Int(Glibc.S_IWOTH) #endif @@ -612,6 +614,8 @@ class TestNSData: LoopbackServerTest { let permission = try fileManager._permissionsOfItem(atPath: url.path) #if canImport(Darwin) let expected = Int(S_IRUSR) | Int(S_IWUSR) | Int(S_IRGRP) | Int(S_IWGRP) | Int(S_IROTH) | Int(S_IWOTH) +#elseif canImport(Android) + let expected = Int(Android.S_IRUSR) | Int(Android.S_IWUSR) | Int(Android.S_IRGRP) | Int(Android.S_IWGRP) | Int(Android.S_IROTH) | Int(Android.S_IWOTH) #else let expected = Int(Glibc.S_IRUSR) | Int(Glibc.S_IWUSR) | Int(Glibc.S_IRGRP) | Int(Glibc.S_IWGRP) | Int(Glibc.S_IROTH) | Int(Glibc.S_IWOTH) #endif diff --git a/Tests/Foundation/Tests/TestTimeZone.swift b/Tests/Foundation/Tests/TestTimeZone.swift index 5e15c00026..5c679b384a 100644 --- a/Tests/Foundation/Tests/TestTimeZone.swift +++ b/Tests/Foundation/Tests/TestTimeZone.swift @@ -160,7 +160,12 @@ class TestTimeZone: XCTestCase { var lt = tm() localtime_r(&t, <) let zoneName = NSTimeZone.system.abbreviation() ?? "Invalid Abbreviation" - let expectedName = String(cString: lt.tm_zone, encoding: .ascii) ?? "Invalid Zone" + // tm_zone is nullable in the Android NDK only. + let tm_zone: UnsafePointer? = lt.tm_zone + guard let tm_zone else { + return + } + let expectedName = String(cString: tm_zone, encoding: .ascii) ?? "Invalid Zone" XCTAssertEqual(zoneName, expectedName, "expected name \"\(expectedName)\" is not equal to \"\(zoneName)\"") } #endif diff --git a/Tests/Foundation/main.swift b/Tests/Foundation/main.swift index e6c7b35bc1..643c0c120c 100644 --- a/Tests/Foundation/main.swift +++ b/Tests/Foundation/main.swift @@ -13,6 +13,8 @@ import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif canImport(CRT) import CRT #endif From f3e12fb93c649c5374afa8e6ad617197a7ea5820 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 28 May 2024 08:55:15 -0700 Subject: [PATCH 4/9] Make ForSwiftFoundationOnly an explicit submodule that doesn't re-export This allows us to prevent the ambiguity for various STATX defines from linux/stat.h when building for Android, as those are defined in the Android platform module --- CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h | 1 + CoreFoundation/Base.subproj/module.modulemap | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h index cc1ba84355..5bd1e28303 100644 --- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h +++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h @@ -64,6 +64,7 @@ #include #include #include +#include #elif TARGET_OS_WASI #include #include diff --git a/CoreFoundation/Base.subproj/module.modulemap b/CoreFoundation/Base.subproj/module.modulemap index fe4c0a68aa..8e95a17651 100644 --- a/CoreFoundation/Base.subproj/module.modulemap +++ b/CoreFoundation/Base.subproj/module.modulemap @@ -1,6 +1,12 @@ framework module CoreFoundation [extern_c] [system] { umbrella header "CoreFoundation.h" explicit module CFPlugInCOM { header "CFPlugInCOM.h" } + explicit module ForSwiftFoundationOnly { + header "ForSwiftFoundationOnly.h" + // Do not re-export imported Clang modules to avoid pulling in + // system headers like linux/stat.h whose constants might conflict + // with constants from the platform module. + } export * module * { From 95e05dbe652afeb0289d912ff5960732c7dd31db Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 28 May 2024 10:47:08 -0700 Subject: [PATCH 5/9] more android fixes to simplify PR --- Sources/Foundation/Data.swift | 2 ++ Sources/Foundation/FileManager+POSIX.swift | 8 ++------ Sources/Foundation/FileManager.swift | 14 +++++++------- Sources/Foundation/Host.swift | 4 ++-- Sources/Foundation/NSPathUtilities.swift | 2 +- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/Sources/Foundation/Data.swift b/Sources/Foundation/Data.swift index 1ff532c670..57e17e58aa 100644 --- a/Sources/Foundation/Data.swift +++ b/Sources/Foundation/Data.swift @@ -64,6 +64,8 @@ internal func malloc_good_size(_ size: Int) -> Int { import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #elseif canImport(WASILibc) import WASILibc #endif diff --git a/Sources/Foundation/FileManager+POSIX.swift b/Sources/Foundation/FileManager+POSIX.swift index b3d6317e01..3d8cf06cb0 100644 --- a/Sources/Foundation/FileManager+POSIX.swift +++ b/Sources/Foundation/FileManager+POSIX.swift @@ -11,10 +11,6 @@ internal func &(left: UInt32, right: mode_t) -> mode_t { return mode_t(left) & right } -#elseif os(Android) -internal func &(left: mode_t, right: Int32) -> mode_t { - return left & mode_t(right) -} #endif #if os(WASI) @@ -413,7 +409,7 @@ extension FileManager { if !parent.isEmpty && !fileExists(atPath: parent, isDirectory: &isDir) { try createDirectory(atPath: parent, withIntermediateDirectories: true, attributes: attributes) } - if mkdir(pathFsRep, mode_t(S_IRWXU) | mode_t(S_IRWXG) | mode_t(S_IRWXO)) != 0 { + if mkdir(pathFsRep, S_IRWXU | S_IRWXG | S_IRWXO) != 0 { let posixError = errno if posixError == EEXIST && fileExists(atPath: path, isDirectory: &isDir) && isDir.boolValue { // Continue; if there is an existing file and it is a directory, that is still a success. @@ -432,7 +428,7 @@ extension FileManager { throw _NSErrorWithErrno(EEXIST, reading: false, path: path) } } else { - if mkdir(pathFsRep, mode_t(S_IRWXU) | mode_t(S_IRWXG) | mode_t(S_IRWXO)) != 0 { + if mkdir(pathFsRep, S_IRWXU | S_IRWXG | S_IRWXO) != 0 { throw _NSErrorWithErrno(errno, reading: false, path: path) } else if let attr = attributes { try self.setAttributes(attr, ofItemAtPath: path) diff --git a/Sources/Foundation/FileManager.swift b/Sources/Foundation/FileManager.swift index 962206fb2b..2b83c4817f 100644 --- a/Sources/Foundation/FileManager.swift +++ b/Sources/Foundation/FileManager.swift @@ -25,7 +25,7 @@ import WinSDK import WASILibc #endif -#if os(Android) +#if canImport(Android) import Android #endif @@ -1346,12 +1346,12 @@ public struct FileAttributeType : RawRepresentable, Equatable, Hashable { #else internal init(statMode: mode_t) { switch statMode & S_IFMT { - case mode_t(S_IFCHR): self = .typeCharacterSpecial - case mode_t(S_IFDIR): self = .typeDirectory - case mode_t(S_IFBLK): self = .typeBlockSpecial - case mode_t(S_IFREG): self = .typeRegular - case mode_t(S_IFLNK): self = .typeSymbolicLink - case mode_t(S_IFSOCK): self = .typeSocket + case S_IFCHR: self = .typeCharacterSpecial + case S_IFDIR: self = .typeDirectory + case S_IFBLK: self = .typeBlockSpecial + case S_IFREG: self = .typeRegular + case S_IFLNK: self = .typeSymbolicLink + case S_IFSOCK: self = .typeSocket default: self = .typeUnknown } } diff --git a/Sources/Foundation/Host.swift b/Sources/Foundation/Host.swift index 02f301ac54..dc65b35379 100644 --- a/Sources/Foundation/Host.swift +++ b/Sources/Foundation/Host.swift @@ -12,9 +12,9 @@ import WinSDK #endif -#if os(Android) +#if canImport(Android) import Android - // Android Glibc differs a little with respect to the Linux Glibc. + // Android Bionic differs a little with respect to the Linux Glibc. // IFF_LOOPBACK is part of the enumeration net_device_flags, which needs to // convert to UInt32. diff --git a/Sources/Foundation/NSPathUtilities.swift b/Sources/Foundation/NSPathUtilities.swift index 532d451049..91e7ccba44 100644 --- a/Sources/Foundation/NSPathUtilities.swift +++ b/Sources/Foundation/NSPathUtilities.swift @@ -803,7 +803,7 @@ internal func _NSCreateTemporaryFile(_ filePath: String) throws -> (Int32, Strin } // Set the file mode to match macOS - guard fchmod(fd, mode_t(S_IRUSR) | mode_t(S_IWUSR) | mode_t(S_IRGRP) | mode_t(S_IWGRP) | mode_t(S_IROTH) | mode_t(S_IWOTH)) != -1 else { + guard fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) != -1 else { let _errno = errno close(fd) throw _NSErrorWithErrno(_errno, reading: false, path: pathResult) From 1f56e95e1ce119f6dc4b58ef2b556a8963899126 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 28 May 2024 13:40:17 -0700 Subject: [PATCH 6/9] fix cross platform build issue --- Sources/Foundation/FileManager+POSIX.swift | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Sources/Foundation/FileManager+POSIX.swift b/Sources/Foundation/FileManager+POSIX.swift index 3d8cf06cb0..570fbe709a 100644 --- a/Sources/Foundation/FileManager+POSIX.swift +++ b/Sources/Foundation/FileManager+POSIX.swift @@ -803,8 +803,13 @@ extension FileManager { let ps = UnsafeMutablePointer?>.allocate(capacity: 2) ps.initialize(to: UnsafeMutablePointer(mutating: fsRep)) ps.advanced(by: 1).initialize(to: nil) - let stream = ps.withMemoryRebound(to: UnsafeMutablePointer.self, capacity: 2) { - fts_open($0, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR | FTS_NOSTAT, nil) + let stream = ps.withMemoryRebound(to: UnsafeMutablePointer.self, capacity: 2) { rebound_ps in +#if canImport(Android) + let arg = rebound_ps +#else + let arg = ps +#endif + return fts_open(arg, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR | FTS_NOSTAT, nil) } ps.deinitialize(count: 2) ps.deallocate() @@ -1173,8 +1178,13 @@ extension FileManager { defer { ps.deallocate() } ps.initialize(to: UnsafeMutablePointer(mutating: fsRep)) ps.advanced(by: 1).initialize(to: nil) - return ps.withMemoryRebound(to: UnsafeMutablePointer.self, capacity: 2) { - fts_open($0, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR | FTS_NOSTAT, nil) + return ps.withMemoryRebound(to: UnsafeMutablePointer.self, capacity: 2) { rebound_ps in +#if canImport(Android) + let arg = rebound_ps +#else + let arg = ps +#endif + return fts_open(arg, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR | FTS_NOSTAT, nil) } } if _stream == nil { From acd234a6b56b49ae315089b8d881a323908679d4 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Fri, 14 Jun 2024 17:12:42 -0700 Subject: [PATCH 7/9] Update pthread cmake config --- CMakeLists.txt | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a929bec001..2c867745e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,20 +70,16 @@ include(XCTest) set(CF_DEPLOYMENT_SWIFT YES CACHE BOOL "Build for Swift" FORCE) -set(CMAKE_THREAD_PREFER_PTHREAD TRUE) -set(THREADS_PREFER_PTHREAD_FLAG OFF) if(HAS_LIBDISPATCH_API) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + set(THREADS_PREFER_PTHREAD_FLAG OFF) + if(ANDROID) + set(CMAKE_THREAD_LIBS_INIT "-lc") + set(THREADS_HAVE_PTHREAD_ARG FALSE) + endif() find_package(Threads REQUIRED) endif() -# CMake's Threads adds '-pthread' flag to the interface link -# libraries, which isn't supported by Swift. This is not enabled -# when building with MSVC, but it trips up the Android build, so -# we need to clear out the threads INTERFACE_LINK_LIBRARIES. -if (CMAKE_SYSTEM_NAME STREQUAL "Android") - set_property(TARGET Threads::Threads PROPERTY INTERFACE_LINK_LIBRARIES "") -endif() - set(SAVED_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) set(BUILD_SHARED_LIBS NO) add_subdirectory(CoreFoundation EXCLUDE_FROM_ALL) From 15bdffe4730a31a9a8726af3229447e7fc2f1fa3 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Fri, 14 Jun 2024 17:13:28 -0700 Subject: [PATCH 8/9] switch to internal Android import and re-export Bionic instead --- Sources/Foundation/CGFloat.swift | 4 ++++ Sources/Foundation/FileManager+POSIX.swift | 4 ++++ Sources/Foundation/FileManager.swift | 4 +--- Sources/Foundation/NSData.swift | 3 +++ Sources/Foundation/NSPathUtilities.swift | 2 ++ Sources/Foundation/NSPlatform.swift | 3 +++ Sources/Foundation/NSSwiftRuntime.swift | 4 ++-- Sources/Foundation/Process.swift | 2 ++ Sources/FoundationNetworking/HTTPCookie.swift | 2 ++ 9 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Sources/Foundation/CGFloat.swift b/Sources/Foundation/CGFloat.swift index ffe3a6c6ff..c59977f88a 100644 --- a/Sources/Foundation/CGFloat.swift +++ b/Sources/Foundation/CGFloat.swift @@ -7,6 +7,10 @@ // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // +#if canImport(Android) +import Android +#endif + @frozen public struct CGFloat: Sendable { #if arch(i386) || arch(arm) || arch(wasm32) diff --git a/Sources/Foundation/FileManager+POSIX.swift b/Sources/Foundation/FileManager+POSIX.swift index 570fbe709a..893917bade 100644 --- a/Sources/Foundation/FileManager+POSIX.swift +++ b/Sources/Foundation/FileManager+POSIX.swift @@ -7,6 +7,10 @@ // #if !os(Windows) +#if canImport(Android) +import Android +#endif + #if os(Android) && (arch(i386) || arch(arm)) // struct stat.st_mode is UInt32 internal func &(left: UInt32, right: mode_t) -> mode_t { return mode_t(left) & right diff --git a/Sources/Foundation/FileManager.swift b/Sources/Foundation/FileManager.swift index 2b83c4817f..5ce6dca8d2 100644 --- a/Sources/Foundation/FileManager.swift +++ b/Sources/Foundation/FileManager.swift @@ -23,9 +23,7 @@ import WinSDK #if os(WASI) import WASILibc -#endif - -#if canImport(Android) +#elseif canImport(Android) import Android #endif diff --git a/Sources/Foundation/NSData.swift b/Sources/Foundation/NSData.swift index 83a5b2b22f..ef755b7197 100644 --- a/Sources/Foundation/NSData.swift +++ b/Sources/Foundation/NSData.swift @@ -11,6 +11,9 @@ #if !os(WASI) import Dispatch #endif +#if canImport(Android) +import Android +#endif extension NSData { public struct ReadingOptions : OptionSet { diff --git a/Sources/Foundation/NSPathUtilities.swift b/Sources/Foundation/NSPathUtilities.swift index 91e7ccba44..9e5dbd9628 100644 --- a/Sources/Foundation/NSPathUtilities.swift +++ b/Sources/Foundation/NSPathUtilities.swift @@ -10,6 +10,8 @@ @_implementationOnly import CoreFoundation #if os(Windows) import WinSDK +#elseif canImport(Android) +import Android #elseif os(WASI) import WASILibc // CoreFoundation brings but it conflicts with WASILibc.errno diff --git a/Sources/Foundation/NSPlatform.swift b/Sources/Foundation/NSPlatform.swift index a18090265d..5424f5bb92 100644 --- a/Sources/Foundation/NSPlatform.swift +++ b/Sources/Foundation/NSPlatform.swift @@ -10,6 +10,9 @@ #if os(macOS) || os(iOS) fileprivate let _NSPageSize = Int(vm_page_size) #elseif os(Linux) || os(Android) || os(OpenBSD) +#if canImport(Android) +import Android +#endif fileprivate let _NSPageSize = Int(getpagesize()) #elseif os(Windows) import WinSDK diff --git a/Sources/Foundation/NSSwiftRuntime.swift b/Sources/Foundation/NSSwiftRuntime.swift index c15217ab05..8d3305c355 100644 --- a/Sources/Foundation/NSSwiftRuntime.swift +++ b/Sources/Foundation/NSSwiftRuntime.swift @@ -18,8 +18,8 @@ @_exported import Glibc #elseif canImport(Musl) @_exported import Musl -#elseif canImport(Android) -@_exported import Android +#elseif canImport(Bionic) +@_exported import Bionic #elseif os(WASI) @_exported import WASILibc #elseif os(Windows) diff --git a/Sources/Foundation/Process.swift b/Sources/Foundation/Process.swift index 68118a7608..ee90279021 100644 --- a/Sources/Foundation/Process.swift +++ b/Sources/Foundation/Process.swift @@ -18,6 +18,8 @@ import struct WinSDK.HANDLE #if canImport(Darwin) import Darwin +#elseif canImport(Android) +import Android #endif extension Process { diff --git a/Sources/FoundationNetworking/HTTPCookie.swift b/Sources/FoundationNetworking/HTTPCookie.swift index 0534780e7b..33519e41b2 100644 --- a/Sources/FoundationNetworking/HTTPCookie.swift +++ b/Sources/FoundationNetworking/HTTPCookie.swift @@ -15,6 +15,8 @@ import Foundation #if os(Windows) import WinSDK +#elseif canImport(Android) +import Android #endif public struct HTTPCookiePropertyKey : RawRepresentable, Equatable, Hashable { From 40b15f2c28162641dd4a7915187c251c4da3bbde Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Fri, 14 Jun 2024 17:13:44 -0700 Subject: [PATCH 9/9] fix tests --- Tests/Foundation/Tests/TestFileHandle.swift | 11 +++-------- Tests/Foundation/Tests/TestNSData.swift | 4 ++++ Tests/Foundation/Tests/TestProcess.swift | 4 ++++ Tests/Foundation/Tests/TestSocketPort.swift | 2 ++ Tests/Foundation/Tests/TestTimeZone.swift | 7 +------ Tests/Foundation/Tests/TestURL.swift | 4 ++++ Tests/Tools/XDGTestHelper/main.swift | 2 ++ 7 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Tests/Foundation/Tests/TestFileHandle.swift b/Tests/Foundation/Tests/TestFileHandle.swift index 82655a29da..0ff23a595b 100644 --- a/Tests/Foundation/Tests/TestFileHandle.swift +++ b/Tests/Foundation/Tests/TestFileHandle.swift @@ -19,6 +19,8 @@ import Dispatch #if os(Windows) import WinSDK +#elseif canImport(Android) +import Android #endif class TestFileHandle : XCTestCase { @@ -111,14 +113,7 @@ class TestFileHandle : XCTestCase { #else var fds: [Int32] = [-1, -1] fds.withUnsafeMutableBufferPointer { (pointer) -> Void in - let baseAddress = pointer.baseAddress -#if canImport(Android) - // pipe takes in a non-nullable pointer in the Android NDK only. - guard let baseAddress else { - return - } -#endif - pipe(baseAddress) + pipe(pointer.baseAddress!) } close(fds[1]) diff --git a/Tests/Foundation/Tests/TestNSData.swift b/Tests/Foundation/Tests/TestNSData.swift index 7f72e0d0b8..2279819805 100644 --- a/Tests/Foundation/Tests/TestNSData.swift +++ b/Tests/Foundation/Tests/TestNSData.swift @@ -17,6 +17,10 @@ import CoreFoundation #endif #endif +#if canImport(Android) +import Android +#endif + class TestNSData: LoopbackServerTest { class AllOnesImmutableData : NSData { diff --git a/Tests/Foundation/Tests/TestProcess.swift b/Tests/Foundation/Tests/TestProcess.swift index 642456d541..86444cc88d 100644 --- a/Tests/Foundation/Tests/TestProcess.swift +++ b/Tests/Foundation/Tests/TestProcess.swift @@ -7,6 +7,10 @@ // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // +#if canImport(Android) +import Android +#endif + class TestProcess : XCTestCase { func test_exit0() throws { diff --git a/Tests/Foundation/Tests/TestSocketPort.swift b/Tests/Foundation/Tests/TestSocketPort.swift index 32366ea510..454fbfd511 100644 --- a/Tests/Foundation/Tests/TestSocketPort.swift +++ b/Tests/Foundation/Tests/TestSocketPort.swift @@ -8,6 +8,8 @@ // #if os(Windows) import WinSDK +#elseif canImport(Android) +import Android #endif class TestPortDelegateWithBlock: NSObject, PortDelegate { diff --git a/Tests/Foundation/Tests/TestTimeZone.swift b/Tests/Foundation/Tests/TestTimeZone.swift index 5c679b384a..373e21b263 100644 --- a/Tests/Foundation/Tests/TestTimeZone.swift +++ b/Tests/Foundation/Tests/TestTimeZone.swift @@ -160,12 +160,7 @@ class TestTimeZone: XCTestCase { var lt = tm() localtime_r(&t, <) let zoneName = NSTimeZone.system.abbreviation() ?? "Invalid Abbreviation" - // tm_zone is nullable in the Android NDK only. - let tm_zone: UnsafePointer? = lt.tm_zone - guard let tm_zone else { - return - } - let expectedName = String(cString: tm_zone, encoding: .ascii) ?? "Invalid Zone" + let expectedName = String(cString: lt.tm_zone!, encoding: .ascii) ?? "Invalid Zone" XCTAssertEqual(zoneName, expectedName, "expected name \"\(expectedName)\" is not equal to \"\(zoneName)\"") } #endif diff --git a/Tests/Foundation/Tests/TestURL.swift b/Tests/Foundation/Tests/TestURL.swift index b0d90812d8..ab3ea47842 100644 --- a/Tests/Foundation/Tests/TestURL.swift +++ b/Tests/Foundation/Tests/TestURL.swift @@ -7,6 +7,10 @@ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // +#if canImport(Android) +import Android +#endif + let kURLTestParsingTestsKey = "ParsingTests" let kURLTestTitleKey = "In-Title" diff --git a/Tests/Tools/XDGTestHelper/main.swift b/Tests/Tools/XDGTestHelper/main.swift index d2a36e2b11..6d43cd17a2 100644 --- a/Tests/Tools/XDGTestHelper/main.swift +++ b/Tests/Tools/XDGTestHelper/main.swift @@ -19,6 +19,8 @@ import FoundationNetworking #endif #if os(Windows) import WinSDK +#elseif os(Android) +import Android #endif enum HelperCheckStatus : Int32 {