Skip to content
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

Add android support, that uses new swift-foundation for Android #5024

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions Sources/CoreFoundation/include/ForSwiftFoundationOnly.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@
#include <sys/stat.h>
#include <sys/syscall.h>
#include <termios.h>
#include <linux/fcntl.h>
#ifdef __swift__
// The linux/stat header is private in the Android modulemap.
#pragma clang module import posix_filesystem.linux_stat
#else
#include <linux/stat.h>
#endif
#elif TARGET_OS_WASI
#include <fcntl.h>
#include <sys/stat.h>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ typedef char * Class;
#include <pthread.h>
#endif

#if TARGET_OS_ANDROID
#define HAVE_STRLCPY 1
#define HAVE_STRLCAT 1
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we should consider doing this via the build configuration.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we've been doing this in the headers because build configuration is spread across several systems (cmake, SPM), and they do not all support the same features.


#if TARGET_OS_WIN32
#define BOOL WINDOWS_BOOL

Expand Down
4 changes: 4 additions & 0 deletions Sources/Foundation/CGFloat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 6 additions & 1 deletion Sources/Foundation/FileHandle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -324,7 +329,7 @@ open class FileHandle : NSObject, @unchecked Sendable {
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)
}
}
Expand Down
10 changes: 7 additions & 3 deletions Sources/Foundation/FileManager+POSIX.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -398,13 +402,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)
Expand Down Expand Up @@ -578,7 +582,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
Expand Down
2 changes: 2 additions & 0 deletions Sources/Foundation/FileManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import WinSDK

#if os(WASI)
import WASILibc
#elseif canImport(Android)
import Android
#endif

#if os(Windows)
Expand Down
9 changes: 5 additions & 4 deletions Sources/Foundation/Host.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
import WinSDK
#endif

#if os(Android)
// Android Glibc differs a little with respect to the Linux Glibc.
#if canImport(Android)
import Android
// 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.
Expand All @@ -24,8 +25,8 @@ import WinSDK
}

// getnameinfo uses size_t for its 4th and 6th arguments.
private func getnameinfo(_ addr: UnsafePointer<sockaddr>?, _ addrlen: socklen_t, _ host: UnsafeMutablePointer<Int8>?, _ hostlen: socklen_t, _ serv: UnsafeMutablePointer<Int8>?, _ servlen: socklen_t, _ flags: Int32) -> Int32 {
return Glibc.getnameinfo(addr, addrlen, host, Int(hostlen), serv, Int(servlen), flags)
private func getnameinfo(_ addr: UnsafePointer<sockaddr>, _ addrlen: socklen_t, _ host: UnsafeMutablePointer<Int8>?, _ hostlen: socklen_t, _ serv: UnsafeMutablePointer<Int8>?, _ servlen: socklen_t, _ flags: Int32) -> Int32 {
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.
Expand Down
5 changes: 5 additions & 0 deletions Sources/Foundation/NSData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#if !os(WASI)
import Dispatch
#endif
#if canImport(Android)
import Android
#endif

extension NSData {
public typealias ReadingOptions = Data.ReadingOptions
Expand Down Expand Up @@ -469,6 +472,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)
Expand Down
2 changes: 2 additions & 0 deletions Sources/Foundation/NSError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import Darwin
import Glibc
#elseif canImport(CRT)
import CRT
#elseif canImport(Android)
import Android
#endif

@_implementationOnly import CoreFoundation
Expand Down
2 changes: 2 additions & 0 deletions Sources/Foundation/NSLock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#if canImport(Glibc)
import Glibc
#elseif canImport(Android)
import Android
#endif

#if os(Windows)
Expand Down
2 changes: 2 additions & 0 deletions Sources/Foundation/NSPathUtilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
@_implementationOnly import CoreFoundation
#if os(Windows)
import WinSDK
#elseif canImport(Android)
import Android
#elseif os(WASI)
import WASILibc
// CoreFoundation brings <errno.h> but it conflicts with WASILibc.errno
Expand Down
3 changes: 3 additions & 0 deletions Sources/Foundation/NSPlatform.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions Sources/Foundation/NSSwiftRuntime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ internal import Synchronization
@_exported import Glibc
#elseif canImport(Musl)
@_exported import Musl
#elseif canImport(Bionic)
@_exported import Bionic
compnerd marked this conversation as resolved.
Show resolved Hide resolved
#elseif os(WASI)
@_exported import WASILibc
#elseif os(Windows)
Expand Down
2 changes: 2 additions & 0 deletions Sources/Foundation/NSURL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 8 additions & 3 deletions Sources/Foundation/Port.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,20 +107,25 @@ fileprivate let FOUNDATION_SOCK_STREAM = SOCK_STREAM
fileprivate let FOUNDATION_IPPROTO_TCP = IPPROTO_TCP
#endif

#if canImport(Glibc) && !os(Android) && !os(OpenBSD)
#if canImport(Glibc) && !os(OpenBSD)
import Glibc
fileprivate let FOUNDATION_SOCK_STREAM = Int32(SOCK_STREAM.rawValue)
fileprivate let FOUNDATION_IPPROTO_TCP = Int32(IPPROTO_TCP)
#endif

#if canImport(Glibc) && os(Android) || os(OpenBSD)
#if canImport(Glibc) && os(OpenBSD)
import Glibc
fileprivate let FOUNDATION_SOCK_STREAM = Int32(SOCK_STREAM)
fileprivate let FOUNDATION_IPPROTO_TCP = Int32(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 FOUNDATION_SOCK_STREAM = Int32(Android.SOCK_STREAM)
fileprivate let FOUNDATION_IPPROTO_TCP = Int32(Android.IPPROTO_TCP)
fileprivate let INADDR_ANY: in_addr_t = 0
#endif


Expand Down
9 changes: 9 additions & 0 deletions Sources/Foundation/Process.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import struct WinSDK.HANDLE

#if canImport(Darwin)
import Darwin
#elseif canImport(Android)
import Android
#endif

internal import Synchronization
Expand Down Expand Up @@ -930,6 +932,13 @@ open class Process: NSObject, @unchecked Sendable {
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)))
Expand Down
2 changes: 2 additions & 0 deletions Sources/Foundation/Thread.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import WinSDK
import Glibc
#elseif canImport(Musl)
import Musl
#elseif canImport(Android)
import Android
#endif

// WORKAROUND_SR9811
Expand Down
2 changes: 2 additions & 0 deletions Sources/FoundationNetworking/HTTPCookie.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import Foundation

#if os(Windows)
import WinSDK
#elseif canImport(Android)
import Android
#endif

public struct HTTPCookiePropertyKey : RawRepresentable, Equatable, Hashable, Sendable {
Expand Down
3 changes: 3 additions & 0 deletions Sources/plutil/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions Sources/xdgTestHelper/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import FoundationNetworking
#endif
#if os(Windows)
import WinSDK
#elseif os(Android)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canImport(Android)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, I modified this in my pull hyp#1 instead.

import Android
#endif

enum HelperCheckStatus : Int32 {
Expand Down
2 changes: 2 additions & 0 deletions Tests/Foundation/FTPServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import Dispatch
import Glibc
#elseif canImport(Darwin)
import Darwin
#elseif canImport(Android)
import Android
#endif

final class ServerSemaphore : Sendable {
Expand Down
2 changes: 2 additions & 0 deletions Tests/Foundation/HTTPServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import Dispatch
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(Android)
import Android
#endif

#if !os(Windows)
Expand Down
4 changes: 3 additions & 1 deletion Tests/Foundation/TestFileHandle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import Dispatch
#if os(Windows)
import WinSDK
#elseif canImport(Android)
import Android
#endif

class TestFileHandle : XCTestCase {
Expand Down Expand Up @@ -111,7 +113,7 @@ class TestFileHandle : XCTestCase {
#else
var fds: [Int32] = [-1, -1]
fds.withUnsafeMutableBufferPointer { (pointer) -> Void in
pipe(pointer.baseAddress)
pipe(pointer.baseAddress!)
}

close(fds[1])
Expand Down
8 changes: 8 additions & 0 deletions Tests/Foundation/TestNSData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
import XCTest
@testable import Foundation

#if canImport(Android)
import Android
#endif

class TestNSData: XCTestCase {

class AllOnesImmutableData : NSData {
Expand Down Expand Up @@ -213,6 +217,8 @@ class TestNSData: XCTestCase {
let permission = try fileManager.attributesOfItem(atPath: url.path)[.posixPermissions] as? Int
#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
Expand All @@ -236,6 +242,8 @@ class TestNSData: XCTestCase {
let permission = try fileManager.attributesOfItem(atPath: url.path)[.posixPermissions] as? Int
#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
Expand Down
3 changes: 3 additions & 0 deletions Tests/Foundation/TestProcess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
//

import Synchronization
#if canImport(Android)
import Android
#endif

class TestProcess : XCTestCase {

Expand Down
2 changes: 2 additions & 0 deletions Tests/Foundation/TestSocketPort.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
//
#if os(Windows)
import WinSDK
#elseif canImport(Android)
import Android
#endif

class TestPortDelegateWithBlock: NSObject, PortDelegate {
Expand Down
2 changes: 1 addition & 1 deletion Tests/Foundation/TestTimeZone.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ class TestTimeZone: XCTestCase {
var lt = tm()
localtime_r(&t, &lt)
let zoneName = NSTimeZone.system.abbreviation() ?? "Invalid Abbreviation"
let expectedName = String(cString: lt.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
Expand Down
4 changes: 4 additions & 0 deletions Tests/Foundation/TestURL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down