Skip to content

Commit

Permalink
Add swift-foundation patches to fix android build
Browse files Browse the repository at this point in the history
  • Loading branch information
andriydruk committed Mar 1, 2025
1 parent 090f9e9 commit 1c73461
Show file tree
Hide file tree
Showing 2 changed files with 249 additions and 0 deletions.
80 changes: 80 additions & 0 deletions patches/swift-foundation/0001-fix-the-android-build.patch
Original file line number Diff line number Diff line change
@@ -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, Output> = (Input, UnsafeMutablePointer<Output>, UnsafeMutablePointer<CChar>, Int, UnsafeMutablePointer<UnsafeMutablePointer<Output>?>) -> Int32
#endif

- private static func withUserGroupBuffer<Input, Output, R>(_ input: Input, _ output: Output, sizeProperty: Int32, operation: Operation<Input, Output>, block: (Output) throws -> R) rethrows -> R? {
+ private static func withUserGroupBuffer<Input, Output, R>(_ input: Input, _ output: Output, sizeProperty: Int32, operation: Operation<Input, Output>, 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<CChar>? = $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<CChar>? = 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<CChar>? = $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<CChar>? = $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<CChar>? = $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<CChar>? = $0.pw_dir
+ return pw_dir.flatMap { String(cString: $0) }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
From 1194ec526d02c76fe7f71bc1c18a784a478e53b1 Mon Sep 17 00:00:00 2001
From: Alex Lorenz <[email protected]>
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

0 comments on commit 1c73461

Please sign in to comment.