Skip to content

Commit 16f83dd

Browse files
johnno1962parkera
authored andcommitted
Port of Foundation to Android (swiftlang#622)
* Port of Foundation to Android * Port of Foundation to Android * Missing -lcurl for Linux builds of Foundation * README and script tidy-up * Response to comments * NSGeonetry, Operation queues fixed * More reponses to comments * NSLog now working * Update README * Update README * CGFloat.swift problems resolved, NSGeometry, NSScanner.swift updated * Glibc is already an @_exported import in NSSwiftRuntime.swift * Glibc is already an @_exported import in NSSwiftRuntime.swift * #import <stdarg.h> problem went away with rebuild * Update scripts * move to SEEK_* macros * Better logging and restructuring * CONST_STRING_DECL() problem resolved * Jira for CFStringGetCString() crash with zero length strings * Only use heap if required in logging * Reinstate fix for SR-2666 * Reinstate fix for SR-2666 * Ensure NSUnimplemented() functions logged * one true brace style * Final tweaks?
1 parent c2ecbeb commit 16f83dd

28 files changed

+302
-22
lines changed

Diff for: CoreFoundation/Base.subproj/CFInternal.h

+10
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,16 @@ CF_PRIVATE Boolean __CFProcessIsRestricted();
339339
#define STACK_BUFFER_DECL(T, N, C) T N[C]
340340
#endif
341341

342+
#ifdef __ANDROID__
343+
// Avoids crashes on Android
344+
// https://bugs.swift.org/browse/SR-2587
345+
// https://bugs.swift.org/browse/SR-2588
346+
// Seemed to be a linker/relocation? problem.
347+
// CFStrings using CONST_STRING_DECL() were not working
348+
// Applies reference to _NSCFConstantString's isa here
349+
// rather than using a linker option to create an alias.
350+
#define __CFConstantStringClassReference _TMC10Foundation19_NSCFConstantString
351+
#endif
342352

343353
CF_EXPORT void * __CFConstantStringClassReferencePtr;
344354
#if defined(__CONSTANT_CFSTRINGS__)

Diff for: CoreFoundation/Base.subproj/CFPlatform.c

+4
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,11 @@ const char *_CFProcessPath(void) {
157157

158158
#if DEPLOYMENT_TARGET_LINUX
159159
#include <unistd.h>
160+
#if __has_include(<syscall.h>)
160161
#include <syscall.h>
162+
#else
163+
#include <sys/syscall.h>
164+
#endif
161165

162166
Boolean _CFIsMainThread(void) {
163167
return syscall(SYS_gettid) == getpid();

Diff for: CoreFoundation/Base.subproj/CFUtilities.c

+42-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
#if DEPLOYMENT_TARGET_WINDOWS
2626
#include <process.h>
2727
#endif
28+
#ifdef __ANDROID__
29+
#include <android/log.h>
30+
#endif
2831
#include <math.h>
2932
#include <string.h>
3033
#include <stdio.h>
@@ -764,7 +767,45 @@ void CFLog(CFLogLevel lev, CFStringRef format, ...) {
764767
#if DEPLOYMENT_RUNTIME_SWIFT
765768
// Temporary as Swift cannot import varag C functions
766769
void CFLog1(CFLogLevel lev, CFStringRef message) {
770+
#ifdef __ANDROID__
771+
android_LogPriority priority = ANDROID_LOG_UNKNOWN;
772+
switch (lev) {
773+
case kCFLogLevelEmergency: priority = ANDROID_LOG_FATAL; break;
774+
case kCFLogLevelAlert: priority = ANDROID_LOG_ERROR; break;
775+
case kCFLogLevelCritical: priority = ANDROID_LOG_ERROR; break;
776+
case kCFLogLevelError: priority = ANDROID_LOG_ERROR; break;
777+
case kCFLogLevelWarning: priority = ANDROID_LOG_WARN; break;
778+
case kCFLogLevelNotice: priority = ANDROID_LOG_WARN; break;
779+
case kCFLogLevelInfo: priority = ANDROID_LOG_INFO; break;
780+
case kCFLogLevelDebug: priority = ANDROID_LOG_DEBUG; break;
781+
}
782+
783+
if (message == NULL) message = CFSTR("NULL");
784+
785+
char stack_buffer[1024] = { 0 };
786+
char *buffer = &stack_buffer[0];
787+
CFStringEncoding encoding = kCFStringEncodingUTF8;
788+
CFIndex maxLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(message), encoding) + 1;
789+
790+
if (maxLength > sizeof(stack_buffer) / sizeof(stack_buffer[0])) {
791+
buffer = calloc(sizeof(char), maxLength);
792+
}
793+
794+
if (maxLength == 1) {
795+
// was crashing with zero length strings
796+
// https://bugs.swift.org/browse/SR-2666
797+
strcpy(buffer, " "); // log empty string
798+
}
799+
else
800+
CFStringGetCString(message, buffer, maxLength, encoding);
801+
802+
const char *tag = "Swift"; // process name not available from NDK
803+
__android_log_print(priority, tag, "%s", buffer);
804+
805+
if (buffer != &stack_buffer[0]) free(buffer);
806+
#else
767807
CFLog(lev, CFSTR("%@"), message);
808+
#endif
768809
}
769810
#endif
770811

@@ -1265,7 +1306,7 @@ CFDictionaryRef __CFGetEnvironment() {
12651306
extern char **environ;
12661307
char **envp = environ;
12671308
#elif DEPLOYMENT_TARGET_LINUX
1268-
#ifndef environ
1309+
#if !defined(environ) && !defined(__ANDROID__)
12691310
#define environ __environ
12701311
#endif
12711312
char **envp = environ;

Diff for: CoreFoundation/Base.subproj/CoreFoundation_Prefix.h

+6
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,11 @@ typedef int boolean_t;
178178

179179
#include <pthread.h>
180180

181+
#ifdef __ANDROID__
182+
typedef unsigned long fd_mask;
183+
#endif
184+
185+
#ifndef __ANDROID__
181186
CF_INLINE size_t
182187
strlcpy(char * dst, const char * src, size_t maxlen) {
183188
const size_t srclen = strlen(src);
@@ -203,6 +208,7 @@ strlcat(char * dst, const char * src, size_t maxlen) {
203208
}
204209
return dstlen + srclen;
205210
}
211+
#endif
206212

207213
#define issetugid() 0
208214

Diff for: CoreFoundation/Base.subproj/SwiftRuntime/CoreFoundation.h

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
#include <string.h>
4040
#include <time.h>
4141

42+
#if __has_include(<netdb.h>)
43+
#include <netdb.h> // for NSHost.swift
44+
#endif
45+
4246
#if defined(__STDC_VERSION__) && (199901L <= __STDC_VERSION__)
4347

4448
#include <inttypes.h>

Diff for: CoreFoundation/NumberDate.subproj/CFTimeZone.c

+4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@
3232
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
3333
#include <dirent.h>
3434
#include <unistd.h>
35+
#if __has_include(<sys/fcntl.h>)
3536
#include <sys/fcntl.h>
37+
#else
38+
#include <fcntl.h>
39+
#endif
3640
#endif
3741
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3842
#include <tzfile.h>

Diff for: CoreFoundation/PlugIn.subproj/CFBundle_InfoPlist.c

+2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525

2626
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_FREEBSD
2727
#include <dirent.h>
28+
#if __has_include(<sys/sysctl.h>)
2829
#include <sys/sysctl.h>
30+
#endif
2931
#include <sys/mman.h>
3032
#endif
3133

Diff for: CoreFoundation/PlugIn.subproj/CFBundle_Resources.c

+2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333

3434
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX
3535
#include <unistd.h>
36+
#if __has_include(<sys/sysctl.h>)
3637
#include <sys/sysctl.h>
38+
#endif
3739
#include <sys/stat.h>
3840
#include <dirent.h>
3941
#endif

Diff for: CoreFoundation/URL.subproj/CFURL.c

+4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@
3030
#include <unistd.h>
3131
#include <sys/stat.h>
3232
#include <sys/types.h>
33+
#if __has_include(<sys/syslog.h>)
3334
#include <sys/syslog.h>
35+
#else
36+
#include <syslog.h>
37+
#endif
3438
#include <CoreFoundation/CFURLPriv.h>
3539
#endif
3640

Diff for: Foundation/NSData.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
423423
repeat {
424424
#if os(OSX) || os(iOS)
425425
bytesWritten = Darwin.write(fd, buf.advanced(by: length - bytesRemaining), bytesRemaining)
426-
#elseif os(Linux)
426+
#elseif os(Linux) || os(Android)
427427
bytesWritten = Glibc.write(fd, buf.advanced(by: length - bytesRemaining), bytesRemaining)
428428
#endif
429429
} while (bytesWritten < 0 && errno == EINTR)
@@ -444,7 +444,7 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
444444
// Preserve permissions.
445445
var info = stat()
446446
if lstat(path, &info) == 0 {
447-
mode = info.st_mode
447+
mode = mode_t(info.st_mode)
448448
} else if errno != ENOENT && errno != ENAMETOOLONG {
449449
throw _NSErrorWithErrno(errno, reading: false, path: path)
450450
}

Diff for: Foundation/NSFileHandle.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ open class FileHandle : NSObject, NSSecureCoding {
7171
}
7272
}
7373
} else {
74-
let offset = lseek(_fd, 0, L_INCR)
74+
let offset = lseek(_fd, 0, SEEK_CUR)
7575
if offset < 0 {
7676
fatalError("Unable to fetch current file offset")
7777
}
78-
if statbuf.st_size > offset {
78+
if off_t(statbuf.st_size) > offset {
7979
var remaining = size_t(statbuf.st_size - offset)
8080
remaining = min(remaining, size_t(length))
8181

@@ -128,19 +128,19 @@ open class FileHandle : NSObject, NSSecureCoding {
128128
// TODO: Error handling.
129129

130130
open var offsetInFile: UInt64 {
131-
return UInt64(lseek(_fd, 0, L_INCR))
131+
return UInt64(lseek(_fd, 0, SEEK_CUR))
132132
}
133133

134134
open func seekToEndOfFile() -> UInt64 {
135-
return UInt64(lseek(_fd, 0, L_XTND))
135+
return UInt64(lseek(_fd, 0, SEEK_END))
136136
}
137137

138138
open func seek(toFileOffset offset: UInt64) {
139-
lseek(_fd, off_t(offset), L_SET)
139+
lseek(_fd, off_t(offset), SEEK_SET)
140140
}
141141

142142
open func truncateFile(atOffset offset: UInt64) {
143-
if lseek(_fd, off_t(offset), L_SET) == 0 {
143+
if lseek(_fd, off_t(offset), SEEK_SET) == 0 {
144144
ftruncate(_fd, off_t(offset))
145145
}
146146
}

Diff for: Foundation/NSFileManager.swift

+13-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313
import Glibc
1414
#endif
1515

16+
#if os(Android) // struct stat.st_mode is UInt32
17+
internal func &(left: UInt32, right: mode_t) -> mode_t {
18+
return mode_t(left) & right
19+
}
20+
#endif
21+
1622
import CoreFoundation
1723

1824
open class FileManager : NSObject {
@@ -123,10 +129,10 @@ open class FileManager : NSObject {
123129
}
124130
#if os(OSX) || os(iOS)
125131
let modeT = number.uint16Value
126-
#elseif os(Linux)
132+
#elseif os(Linux) || os(Android)
127133
let modeT = number.uint32Value
128134
#endif
129-
if chmod(path, modeT) != 0 {
135+
if chmod(path, mode_t(modeT)) != 0 {
130136
fatalError("errno \(errno)")
131137
}
132138
} else {
@@ -246,11 +252,11 @@ open class FileManager : NSObject {
246252
}
247253
#if os(OSX) || os(iOS)
248254
let tempEntryType = entryType
249-
#elseif os(Linux)
255+
#elseif os(Linux) || os(Android)
250256
let tempEntryType = Int(entryType)
251257
#endif
252258

253-
if tempEntryType == DT_DIR {
259+
if tempEntryType == Int(DT_DIR) {
254260
let subPath: String = path + "/" + entryName
255261

256262
let entries = try subpathsOfDirectory(atPath: subPath)
@@ -279,6 +285,8 @@ open class FileManager : NSObject {
279285

280286
#if os(OSX) || os(iOS)
281287
let ti = (TimeInterval(s.st_mtimespec.tv_sec) - kCFAbsoluteTimeIntervalSince1970) + (1.0e-9 * TimeInterval(s.st_mtimespec.tv_nsec))
288+
#elseif os(Android)
289+
let ti = (TimeInterval(s.st_mtime) - kCFAbsoluteTimeIntervalSince1970) + (1.0e-9 * TimeInterval(s.st_mtime_nsec))
282290
#else
283291
let ti = (TimeInterval(s.st_mtim.tv_sec) - kCFAbsoluteTimeIntervalSince1970) + (1.0e-9 * TimeInterval(s.st_mtim.tv_nsec))
284292
#endif
@@ -361,7 +369,7 @@ open class FileManager : NSObject {
361369
throw _NSErrorWithErrno(errno, reading: true, path: path)
362370
}
363371

364-
return self.string(withFileSystemRepresentation: buf, length: len)
372+
return self.string(withFileSystemRepresentation: buf, length: Int(len))
365373
}
366374

367375
open func copyItem(atPath srcPath: String, toPath dstPath: String) throws {

Diff for: Foundation/NSLocale.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ open class NSLocale: NSObject, NSCopying, NSSecureCoding {
1818
private var _prefs: UnsafeMutableRawPointer? = nil
1919
#if os(OSX) || os(iOS)
2020
private var _lock = pthread_mutex_t()
21-
#elseif os(Linux)
21+
#elseif os(Linux) || os(Android)
2222
private var _lock = Int32(0)
2323
#endif
2424
private var _nullLocale = false

Diff for: Foundation/NSObjCRuntime.swift

+3
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ internal func NSRequiresConcreteImplementation(_ fn: String = #function, file: S
196196
}
197197

198198
internal func NSUnimplemented(_ fn: String = #function, file: StaticString = #file, line: UInt = #line) -> Never {
199+
#if os(Android)
200+
NSLog("\(fn) is not yet implemented. \(file):\(line)")
201+
#endif
199202
fatalError("\(fn) is not yet implemented", file: file, line: line)
200203
}
201204

Diff for: Foundation/NSOperation.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
#if DEPLOYMENT_ENABLE_LIBDISPATCH
1111
import Dispatch
12-
#if os(Linux)
12+
#if os(Linux) || os(Android)
1313
import CoreFoundation
1414
private func pthread_main_np() -> Int32 {
1515
return _CFIsMainThread() ? 1 : 0

Diff for: Foundation/NSSwiftRuntime.swift

+7-1
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,16 @@ import CoreFoundation
1414
// This mimics the behavior of the swift sdk overlay on Darwin
1515
#if os(OSX) || os(iOS)
1616
@_exported import Darwin
17-
#elseif os(Linux)
17+
#elseif os(Linux) || os(Android)
1818
@_exported import Glibc
1919
#endif
2020

21+
#if os(Android) // shim required for bzero
22+
@_transparent func bzero(_ ptr: UnsafeMutableRawPointer, _ size: size_t) {
23+
memset(ptr, 0, size)
24+
}
25+
#endif
26+
2127
public typealias ObjCBool = Bool
2228

2329
internal class __NSCFType : NSObject {

Diff for: Foundation/NSTask.swift

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
88
//
99

10+
#if !os(Android) // not available
1011
import CoreFoundation
1112

1213
#if os(OSX) || os(iOS)
@@ -455,3 +456,4 @@ private func posix(_ code: Int32) {
455456
default: fatalError("POSIX command failed with error: \(code)")
456457
}
457458
}
459+
#endif

Diff for: Foundation/NSThread.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ open class Thread : NSObject {
133133
internal var _main: (Void) -> Void = {}
134134
#if os(OSX) || os(iOS)
135135
private var _thread: pthread_t? = nil
136-
#elseif os(Linux)
136+
#elseif os(Linux) || os(Android)
137137
private var _thread = pthread_t()
138138
#endif
139139
internal var _attr = pthread_attr_t()

Diff for: Foundation/NSURL.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ open class NSURL : NSObject, NSSecureCoding, NSCopying {
496496

497497
open var password: String? {
498498
let absoluteURL = CFURLCopyAbsoluteURL(_cfObject)
499-
#if os(Linux)
499+
#if os(Linux) || os(Android)
500500
let passwordRange = CFURLGetByteRangeForComponent(absoluteURL, kCFURLComponentPassword, nil)
501501
#else
502502
let passwordRange = CFURLGetByteRangeForComponent(absoluteURL, .password, nil)

Diff for: Foundation/NSXMLNode.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ open class XMLNode: NSObject, NSCopying {
8383
public static let nodePromoteSignificantWhitespace = Options(rawValue: 1 << 28)
8484
public static let nodePreserveEmptyElements = Options([.nodeExpandEmptyElement, .nodeCompactEmptyElement])
8585
public static let nodePreserveQuotes = Options([.nodeUseSingleQuotes, .nodeUseDoubleQuotes])
86-
public static let nodePreserveAll = Options(rawValue: Options([.nodePreserveNamespaceOrder, .nodePreserveAttributeOrder, .nodePreserveEntities, .nodePreservePrefixes, .nodePreserveCDATA, .nodePreserveEmptyElements, .nodePreserveQuotes, .nodePreserveWhitespace, .nodePreserveDTD, .nodePreserveCharacterReferences]).rawValue | UInt(bitPattern: 0xFFF00000))
86+
public static let nodePreserveAll = Options(rawValue: 0xFFF00000).union([.nodePreserveNamespaceOrder, .nodePreserveAttributeOrder, .nodePreserveEntities, .nodePreservePrefixes, .nodePreserveCDATA, .nodePreserveEmptyElements, .nodePreserveQuotes, .nodePreserveWhitespace, .nodePreserveDTD, .nodePreserveCharacterReferences])
8787
}
8888

8989
open override func copy() -> Any {

0 commit comments

Comments
 (0)