From 1c734616ea9c90056370b67f20678b4c71c8efb9 Mon Sep 17 00:00:00 2001 From: Andrew Druk Date: Sat, 1 Mar 2025 12:12:21 +0200 Subject: [PATCH] Add swift-foundation patches to fix android build --- .../0001-fix-the-android-build.patch | 80 +++++++++ ...ix-the-LP32-armv7-i686-android-build.patch | 169 ++++++++++++++++++ 2 files changed, 249 insertions(+) create mode 100644 patches/swift-foundation/0001-fix-the-android-build.patch create mode 100644 patches/swift-foundation/0002-fix-the-LP32-armv7-i686-android-build.patch diff --git a/patches/swift-foundation/0001-fix-the-android-build.patch b/patches/swift-foundation/0001-fix-the-android-build.patch new file mode 100644 index 0000000..b60424c --- /dev/null +++ b/patches/swift-foundation/0001-fix-the-android-build.patch @@ -0,0 +1,80 @@ +diff --git a/Sources/FoundationEssentials/Platform.swift b/Sources/FoundationEssentials/Platform.swift +index 6eb3acc..72dbf88 100644 +--- a/Sources/FoundationEssentials/Platform.swift ++++ b/Sources/FoundationEssentials/Platform.swift +@@ -29,8 +29,7 @@ fileprivate let _pageSize: Int = { + // WebAssembly defines a fixed page size + fileprivate let _pageSize: Int = 65_536 + #elseif os(Android) +-import Bionic +-import unistd ++import Android + fileprivate let _pageSize: Int = Int(getpagesize()) + #elseif canImport(Glibc) + import Glibc +@@ -142,7 +141,7 @@ extension Platform { + typealias Operation = (Input, UnsafeMutablePointer, UnsafeMutablePointer, Int, UnsafeMutablePointer?>) -> Int32 + #endif + +- private static func withUserGroupBuffer(_ input: Input, _ output: Output, sizeProperty: Int32, operation: Operation, block: (Output) throws -> R) rethrows -> R? { ++ private static func withUserGroupBuffer(_ input: Input, _ output: Output, sizeProperty: Int32, operation: Operation, block: (Output) throws -> R?) rethrows -> R? { + var bufferLen = sysconf(sizeProperty) + if bufferLen == -1 { + bufferLen = 4096 // Generous default size estimate +@@ -172,31 +171,51 @@ extension Platform { + + static func name(forUID uid: uid_t) -> String? { + withUserGroupBuffer(uid, passwd(), sizeProperty: Int32(_SC_GETPW_R_SIZE_MAX), operation: getpwuid_r) { +- String(cString: $0.pw_name) ++ // Android's pw_name `char *`` is nullable when it should be non-null. ++ // FIXME: avoid the coerce cast workaround once https://github.com/android/ndk/issues/2098 is fixed. ++ let pw_name: UnsafeMutablePointer? = $0.pw_name ++ return pw_name.flatMap { String(cString: $0) } + } + } + + static func fullName(forUID uid: uid_t) -> String? { + withUserGroupBuffer(uid, passwd(), sizeProperty: Int32(_SC_GETPW_R_SIZE_MAX), operation: getpwuid_r) { +- String(cString: $0.pw_gecos) ++#if os(Android) && _pointerBitWidth(_32) ++ // pw_gecos isn't available on 32-bit Android. ++ let pw_gecos: UnsafeMutablePointer? = nil ++#else ++ // Android's pw_gecos `char *`` is nullable, so always coerce to a nullable pointer ++ // in order to be compatible with Android. ++ let pw_gecos: UnsafeMutablePointer? = $0.pw_gecos ++#endif ++ return pw_gecos.flatMap { String(cString: $0) } + } + } + + static func name(forGID gid: gid_t) -> String? { + withUserGroupBuffer(gid, group(), sizeProperty: Int32(_SC_GETGR_R_SIZE_MAX), operation: getgrgid_r) { +- String(cString: $0.gr_name) ++ // Android's gr_name `char *`` is nullable when it should be non-null. ++ // FIXME: avoid the coerce cast workaround once https://github.com/android/ndk/issues/2098 is fixed. ++ let gr_name: UnsafeMutablePointer? = $0.gr_name ++ return gr_name.flatMap { String(cString: $0) } + } + } + + static func homeDirectory(forUserName userName: String) -> String? { + withUserGroupBuffer(userName, passwd(), sizeProperty: Int32(_SC_GETPW_R_SIZE_MAX), operation: getpwnam_r) { +- String(cString: $0.pw_dir) ++ // Android's pw_dir `char *`` is nullable when it should be non-null. ++ // FIXME: avoid the coerce cast workaround once https://github.com/android/ndk/issues/2098 is fixed. ++ let pw_dir: UnsafeMutablePointer? = $0.pw_dir ++ return pw_dir.flatMap { String(cString: $0) } + } + } + + static func homeDirectory(forUID uid: uid_t) -> String? { + withUserGroupBuffer(uid, passwd(), sizeProperty: Int32(_SC_GETPW_R_SIZE_MAX), operation: getpwuid_r) { +- String(cString: $0.pw_dir) ++ // Android's pw_dir `char *`` is nullable when it should be non-null. ++ // FIXME: avoid the coerce cast workaround once https://github.com/android/ndk/issues/2098 is fixed. ++ let pw_dir: UnsafeMutablePointer? = $0.pw_dir ++ return pw_dir.flatMap { String(cString: $0) } + } + } + } diff --git a/patches/swift-foundation/0002-fix-the-LP32-armv7-i686-android-build.patch b/patches/swift-foundation/0002-fix-the-LP32-armv7-i686-android-build.patch new file mode 100644 index 0000000..09244fe --- /dev/null +++ b/patches/swift-foundation/0002-fix-the-LP32-armv7-i686-android-build.patch @@ -0,0 +1,169 @@ +From 1194ec526d02c76fe7f71bc1c18a784a478e53b1 Mon Sep 17 00:00:00 2001 +From: Alex Lorenz +Date: Wed, 14 Aug 2024 10:56:25 -0700 +Subject: [PATCH] [android] fix the LP32 armv7/i686 android build + +--- + Sources/FoundationEssentials/Data/Data+Reading.swift | 2 +- + .../FileManager/FileManager+Basics.swift | 4 ++-- + .../FileManager/FileManager+Files.swift | 7 ++++--- + .../FileManager/FileManager+Utilities.swift | 8 ++++---- + .../FileManager/FileOperations+Enumeration.swift | 2 +- + .../FoundationEssentials/FileManager/FileOperations.swift | 2 +- + .../FoundationEssentials/ProcessInfo/ProcessInfo.swift | 5 ++++- + Sources/FoundationEssentials/String/String+Path.swift | 2 +- + 8 files changed, 18 insertions(+), 14 deletions(-) + +diff --git a/Sources/FoundationEssentials/Data/Data+Reading.swift b/Sources/FoundationEssentials/Data/Data+Reading.swift +index 612681d..8f611af 100644 +--- a/Sources/FoundationEssentials/Data/Data+Reading.swift ++++ b/Sources/FoundationEssentials/Data/Data+Reading.swift +@@ -327,7 +327,7 @@ internal func readBytesFromFile(path inPath: PathOrURL, reportProgress: Bool, ma + } + + let fileSize = min(Int(clamping: filestat.st_size), maxLength ?? Int.max) +- let fileType = filestat.st_mode & S_IFMT ++ let fileType = mode_t(filestat.st_mode) & S_IFMT + #if !NO_FILESYSTEM + let shouldMap = shouldMapFileDescriptor(fd, path: inPath, options: options) + #else +diff --git a/Sources/FoundationEssentials/FileManager/FileManager+Basics.swift b/Sources/FoundationEssentials/FileManager/FileManager+Basics.swift +index 9896b35..4c05723 100644 +--- a/Sources/FoundationEssentials/FileManager/FileManager+Basics.swift ++++ b/Sources/FoundationEssentials/FileManager/FileManager+Basics.swift +@@ -223,7 +223,7 @@ internal struct _FileManagerImpl { + var statBuf = stat() + let fd = open(path, 0, 0) + guard fd >= 0 else { return nil } +- if fstat(fd, &statBuf) < 0 || statBuf.st_mode & S_IFMT == S_IFDIR { ++ if fstat(fd, &statBuf) < 0 || mode_t(statBuf.st_mode) & S_IFMT == S_IFDIR { + close(fd) + return nil + } +@@ -242,7 +242,7 @@ internal struct _FileManagerImpl { + } + + /* check for being same type */ +- if myInfo.st_mode & S_IFMT != otherInfo.st_mode & S_IFMT { ++ if mode_t(myInfo.st_mode) & S_IFMT != mode_t(otherInfo.st_mode) & S_IFMT { + return false + } + +diff --git a/Sources/FoundationEssentials/FileManager/FileManager+Files.swift b/Sources/FoundationEssentials/FileManager/FileManager+Files.swift +index 4b628c8..346f4ae 100644 +--- a/Sources/FoundationEssentials/FileManager/FileManager+Files.swift ++++ b/Sources/FoundationEssentials/FileManager/FileManager+Files.swift +@@ -162,7 +162,8 @@ extension stat { + } + + fileprivate var fileAttributes: [FileAttributeKey : Any] { +- let fileType = st_mode.fileType ++ // On 32 bit Android, st_mode is UInt32. ++ let fileType = mode_t(st_mode).fileType + var result: [FileAttributeKey : Any] = [ + .size : _writeFileAttributePrimitive(st_size, as: UInt.self), + .modificationDate : modificationDate, +@@ -387,7 +388,7 @@ extension _FileManagerImpl { + guard stat(rep, &fileInfo) == 0 else { + return (false, false) + } +- let isDir = (fileInfo.st_mode & S_IFMT) == S_IFDIR ++ let isDir = (mode_t(fileInfo.st_mode) & S_IFMT) == S_IFDIR + return (true, isDir) + } + #endif +@@ -466,7 +467,7 @@ extension _FileManagerImpl { + return false + } + +- if ((dirInfo.st_mode & S_ISVTX) != 0) && fileManager.fileExists(atPath: path) { ++ if ((mode_t(dirInfo.st_mode) & S_ISVTX) != 0) && fileManager.fileExists(atPath: path) { + // its sticky so verify that we own the file + // otherwise we answer YES on the principle that if + // we create files we can delete them +diff --git a/Sources/FoundationEssentials/FileManager/FileManager+Utilities.swift b/Sources/FoundationEssentials/FileManager/FileManager+Utilities.swift +index 525bef7..0b80db1 100644 +--- a/Sources/FoundationEssentials/FileManager/FileManager+Utilities.swift ++++ b/Sources/FoundationEssentials/FileManager/FileManager+Utilities.swift +@@ -51,19 +51,19 @@ extension FILETIME { + #if !os(Windows) + extension stat { + var isDirectory: Bool { +- (self.st_mode & S_IFMT) == S_IFDIR ++ (mode_t(self.st_mode) & S_IFMT) == S_IFDIR + } + + var isRegular: Bool { +- (self.st_mode & S_IFMT) == S_IFREG ++ (mode_t(self.st_mode) & S_IFMT) == S_IFREG + } + + var isSymbolicLink: Bool { +- (self.st_mode & S_IFMT) == S_IFLNK ++ (mode_t(self.st_mode) & S_IFMT) == S_IFLNK + } + + var isSpecial: Bool { +- let type = self.st_mode & S_IFMT ++ let type = mode_t(self.st_mode) & S_IFMT + return type == S_IFBLK || type == S_IFCHR + } + } +diff --git a/Sources/FoundationEssentials/FileManager/FileOperations+Enumeration.swift b/Sources/FoundationEssentials/FileManager/FileOperations+Enumeration.swift +index 2c9a02f..500da1d 100644 +--- a/Sources/FoundationEssentials/FileManager/FileOperations+Enumeration.swift ++++ b/Sources/FoundationEssentials/FileManager/FileOperations+Enumeration.swift +@@ -367,7 +367,7 @@ struct _POSIXDirectoryContentsSequence: Sequence { + let statDir = directoryPath + "/" + fileName + if stat(statDir, &statBuf) == 0 { + // #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +- if (statBuf.st_mode & S_IFMT) == S_IFDIR { ++ if (mode_t(statBuf.st_mode) & S_IFMT) == S_IFDIR { + isDirectory = true + } + } +diff --git a/Sources/FoundationEssentials/FileManager/FileOperations.swift b/Sources/FoundationEssentials/FileManager/FileOperations.swift +index 14c6fd8..93972b0 100644 +--- a/Sources/FoundationEssentials/FileManager/FileOperations.swift ++++ b/Sources/FoundationEssentials/FileManager/FileOperations.swift +@@ -870,7 +870,7 @@ enum _FileOperations { + + #if !os(WASI) // WASI doesn't have fchmod for now + // Set the file permissions using fchmod() instead of when open()ing to avoid umask() issues +- let permissions = fileInfo.st_mode & ~S_IFMT ++ let permissions = mode_t(fileInfo.st_mode) & ~S_IFMT + guard fchmod(dstfd, permissions) == 0 else { + try delegate.throwIfNecessary(errno, String(cString: srcPtr), String(cString: dstPtr)) + return +diff --git a/Sources/FoundationEssentials/ProcessInfo/ProcessInfo.swift b/Sources/FoundationEssentials/ProcessInfo/ProcessInfo.swift +index 485f606..0d8680e 100644 +--- a/Sources/FoundationEssentials/ProcessInfo/ProcessInfo.swift ++++ b/Sources/FoundationEssentials/ProcessInfo/ProcessInfo.swift +@@ -199,7 +199,10 @@ final class _ProcessInfo: Sendable { + } + + var fullUserName: String { +-#if canImport(Darwin) || os(Android) || canImport(Glibc) || canImport(Musl) ++#if os(Android) && (arch(i386) || arch(arm)) ++ // On LP32 Android, pw_gecos doesn't exist and is presumed to be NULL. ++ return "" ++#elseif canImport(Darwin) || os(Android) || canImport(Glibc) || canImport(Musl) + let (euid, _) = Platform.getUGIDs() + if let fullName = Platform.fullName(forUID: euid) { + return fullName +diff --git a/Sources/FoundationEssentials/String/String+Path.swift b/Sources/FoundationEssentials/String/String+Path.swift +index 3185c1f..0c377cf 100644 +--- a/Sources/FoundationEssentials/String/String+Path.swift ++++ b/Sources/FoundationEssentials/String/String+Path.swift +@@ -760,7 +760,7 @@ extension String { + if lstat(buffer.baseAddress!, &statBuf) < 0 { + return nil + } +- if statBuf.st_mode & S_IFMT == S_IFLNK { ++ if mode_t(statBuf.st_mode) & S_IFMT == S_IFLNK { + /* Examples: + * fspath == /foo/bar0baz/quux/froboz + * linkx == /tic/tac/toe +-- +2.46.0 +