diff --git a/ChangeLog b/ChangeLog index 9f9f2e3bc..f04641796 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,59 @@ +2019-05-23 Frederik Seiffert + + * configure: + * configure.ac: + Link against libandroid on Android. + * Headers/Foundation/NSBundle.h: + * Source/NSBundle.m: + Added methods for passing Android asset manager from Java to GNUstep + and for getting AAsset/AAssetDir for given path in main bundle. + Skip app bundle suffix check on Android. Extended bundle resource + paths backbone to check for known paths directly on Android as we + can't enumerate directories. + Extended -localizations method to check for known localizations + directly (requires setting userLanguages in NSUserDefaults). + Extracted path cache cleaning into separate method. + * Source/GSFileHandle.h: + * Source/GSFileHandle.m: + Added file handle support for reading Android assets from main bundle. + * Source/NSData.m: + Added support for reading Android assets from main bundle in + readContentsOfFile(). This is also used by all other + -initWithContentsOfFile: and related methods from other classes. + * Source/NSFileManager.m: + Added support for Android assets from main bundle in + fileExistsAtPath:isDirectory:, isReadableFileAtPath:, + NSDirectoryEnumerator, and copying from assets. Extended + GSAttrDictionary with basic support for Android assets. + * Source/NSProcessInfo.m: + Added +initialize method to auto-initialize NSProcessInfo on Android + using fake executable path "/data/data//exe" (Android + apps don't have a real executable path). + +2019-05-20 Frederik Seiffert + + * Source/NSLog.m: Have all logs go to syslog on android. + * Source/NSThread.m: Spinlock implementation using builtins as + implemented by David in libobjc2 + * Source/NSRunLoop.m + * Headers/GNUstepBase/config.h.in: + * configure.ac: + This updates the libdispatch runloop integration to be compatible with + the Swift corelibs libdispatch release at + (https://github.com/apple/swift-corelibs-libdispatch). + + In that release, the main queue handle and drain functions have been + renamed with a "_4CF" (for CoreFoundation) suffix and have moved to + private.h, so we now check for the existance of this header and + function names. + + Note that libdispatch must be compiled with + INSTALL_PRIVATE_HEADERS=YES. + + Also fixes the checks for the HAVE_LIBDISPATCH_RUNLOOP define (was + inverted) and ensures that both the handle and drain functions are + available. + 2019-02-16 Richard Frith-Macdonald * Source/NSString.m: Removed public functions which could conflict diff --git a/Headers/Foundation/NSBundle.h b/Headers/Foundation/NSBundle.h index ef97f923e..76b8bbb4f 100644 --- a/Headers/Foundation/NSBundle.h +++ b/Headers/Foundation/NSBundle.h @@ -36,6 +36,10 @@ extern "C" { #import #import +#ifdef __ANDROID__ +#include +#endif + @class NSString; @class NSArray; @class NSDictionary; @@ -540,6 +544,47 @@ GS_EXPORT NSString* const NSLoadedClasses; ofType: (NSString*)extension inDirectory: (NSString*)bundlePath; +/** Cleans up the path cache for the bundle. */ +- (void) cleanPathCache; + +#ifdef __ANDROID__ + +/** + * Sets the Java Android asset manager. + * The developer can call this method to enable asset loading via NSBundle. + */ ++ (void) setJavaAssetManager: (jobject)jassetManager withJNIEnv: (JNIEnv *)env; + +/** + * Returns the native Android asset manager. + */ ++ (AAssetManager *) assetManager; + +/** + * Returns the Android asset for the given path if path is in main bundle + * resources and asset exists. + * Uses `AASSET_MODE_UNKNOWN` to open the asset if it exists. + * The returned object must be released using AAsset_close(). + */ ++ (AAsset *) assetForPath: (NSString *)path; + +/** + * Returns the Android asset for the given path if path is in main bundle + * resources and asset exists. + * Uses the given mode to open the AAsset if it exists. + * The returned object must be released using AAsset_close(). + */ ++ (AAsset *) assetForPath: (NSString *)path withMode: (int)mode; + +/** + * Returns the Android asset dir for the given path if path is in main bundle + * resources and the asset directory exists. + * The returned object must be released using AAssetDir_close(). + */ ++ (AAssetDir *) assetDirForPath: (NSString *)path; + +#endif /* __ANDROID__ */ + @end #endif /* GNUSTEP */ @@ -603,7 +648,7 @@ GS_EXPORT NSString* const NSLoadedClasses; *

*/ #define NSLocalizedString(key, comment) \ - [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil] + [[NSBundle mainBundle] localizedStringForKey: (key) value: @"" table: nil] /** * This function (macro) does the same as @@ -621,7 +666,7 @@ GS_EXPORT NSString* const NSLoadedClasses; * different table. */ #define NSLocalizedStringFromTable(key, tbl, comment) \ - [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:(tbl)] + [[NSBundle mainBundle] localizedStringForKey: (key) value: @"" table: (tbl)] /** * This function is the full-blown localization function (it @@ -637,7 +682,7 @@ GS_EXPORT NSString* const NSLoadedClasses; * use when translating the string. */ #define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) \ - [bundle localizedStringForKey:(key) value:@"" table:(tbl)] + [bundle localizedStringForKey: (key) value: @"" table: (tbl)] #if defined(__cplusplus) diff --git a/Headers/GNUstepBase/config.h.in b/Headers/GNUstepBase/config.h.in index 390b53603..79896e758 100644 --- a/Headers/GNUstepBase/config.h.in +++ b/Headers/GNUstepBase/config.h.in @@ -216,6 +216,9 @@ /* Define to 1 if you have the `dispatch_main_queue_drain_np' function. */ #undef HAVE_DISPATCH_MAIN_QUEUE_DRAIN_NP +/* Define to 1 if you have the header file. */ +#undef HAVE_DISPATCH_PRIVATE_H + /* Define to 1 if you have the `dladdr' function. */ #undef HAVE_DLADDR @@ -767,6 +770,14 @@ /* Define to 1 if you have the `_Block_copy' function. */ #undef HAVE__BLOCK_COPY +/* Define to 1 if you have the `_dispatch_get_main_queue_handle_4CF' function. + */ +#undef HAVE__DISPATCH_GET_MAIN_QUEUE_HANDLE_4CF + +/* Define to 1 if you have the `_dispatch_main_queue_callback_4CF' function. + */ +#undef HAVE__DISPATCH_MAIN_QUEUE_CALLBACK_4CF + /* Define to 1 if you have the `__builtin_extract_return_address' function. */ #undef HAVE___BUILTIN_EXTRACT_RETURN_ADDRESS diff --git a/Source/GSFileHandle.h b/Source/GSFileHandle.h index 0db80e679..e4e507180 100644 --- a/Source/GSFileHandle.h +++ b/Source/GSFileHandle.h @@ -35,6 +35,10 @@ #include #endif +#ifdef __ANDROID__ +#include +#endif + struct sockaddr_in; /** @@ -69,6 +73,9 @@ struct sockaddr_in; #if defined(_WIN32) WSAEVENT event; #endif +#ifdef __ANDROID__ + AAsset *asset; +#endif #endif } diff --git a/Source/GSFileHandle.m b/Source/GSFileHandle.m index 5b91f04ae..cb814ac4a 100644 --- a/Source/GSFileHandle.m +++ b/Source/GSFileHandle.m @@ -285,6 +285,13 @@ static GSTcpTune *tune = nil; do { +#ifdef __ANDROID__ + if (asset) + { + result = AAsset_read(asset, buf, len); + } + else +#endif #if USE_ZLIB if (gzDescriptor != 0) { @@ -379,6 +386,14 @@ static GSTcpTune *tune = nil; [self ignoreReadDescriptor]; [self ignoreWriteDescriptor]; +#ifdef __ANDROID__ + if (asset) + { + AAsset_close(asset); + asset = NULL; + } + else +#endif if (closeOnDealloc == YES && descriptor != -1) { [self closeFile]; @@ -1075,6 +1090,15 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr"; if (d < 0) { +#ifdef __ANDROID__ + asset = [NSBundle assetForPath:path withMode:AASSET_MODE_RANDOM]; + if (asset) + { + readOK = YES; + return self; + } +#endif + DESTROY(self); return nil; } @@ -1645,6 +1669,13 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr"; { off_t result = -1; +#ifdef __ANDROID__ + if (asset) + { + result = AAsset_seek(asset, 0, SEEK_CUR); + } + else +#endif if (isStandardFile && descriptor >= 0) { #if USE_ZLIB @@ -1669,6 +1700,13 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr"; { off_t result = -1; +#ifdef __ANDROID__ + if (asset) + { + result = AAsset_seek(asset, 0, SEEK_END); + } + else +#endif if (isStandardFile && descriptor >= 0) { #if USE_ZLIB @@ -1693,6 +1731,13 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr"; { off_t result = -1; +#ifdef __ANDROID__ + if (asset) + { + result = AAsset_seek(asset, (off_t)pos, SEEK_SET); + } + else +#endif if (isStandardFile && descriptor >= 0) { #if USE_ZLIB @@ -1726,6 +1771,15 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr"; [self ignoreWriteDescriptor]; [self setNonBlocking: NO]; + +#ifdef __ANDROID__ + if (asset) + { + AAsset_close(asset); + asset = NULL; + } + else +#endif #if USE_ZLIB if (gzDescriptor != 0) { diff --git a/Source/GSTimSort.m b/Source/GSTimSort.m index fe37f636d..2a9b369e1 100644 --- a/Source/GSTimSort.m +++ b/Source/GSTimSort.m @@ -627,15 +627,11 @@ descriptorOrComparator: (id)descriptorOrComparator while (stackSize > 1) { NSInteger n = stackSize -2; - if ( (n >= 1 - && runStack[n-1].length <= (runStack[n].length - + runStack[n+1].length) - ) - || (n >= 2 - && runStack[n-2].length <= (runStack[n].length - + runStack[n-1].length) - ) - ) + + if ((n >= 1 && runStack[n-1].length + <= (runStack[n].length + runStack[n+1].length)) + || (n >= 2 && runStack[n-2].length + <= (runStack[n].length + runStack[n-1].length))) { if (runStack[n-1].length < runStack[n+1].length) { diff --git a/Source/NSBundle.m b/Source/NSBundle.m index 75528649e..309b7e25a 100644 --- a/Source/NSBundle.m +++ b/Source/NSBundle.m @@ -241,6 +241,11 @@ static NSString *library_combo = nil; #endif +#ifdef __ANDROID__ +static jobject _jassetManager = NULL; +static AAssetManager *_assetManager = NULL; +#endif + /* * Try to find the absolute path of an executable. @@ -264,17 +269,17 @@ AbsolutePathOfExecutable(NSString *path, BOOL atLaunch) NSString *result = nil; env = [[NSProcessInfo processInfo] environment]; - pathlist = [env objectForKey:@"PATH"]; + pathlist = [env objectForKey: @"PATH"]; /* Windows 2000 and perhaps others have "Path" not "PATH" */ if (pathlist == nil) { - pathlist = [env objectForKey:@"Path"]; + pathlist = [env objectForKey: @"Path"]; } #if defined(_WIN32) - patharr = [pathlist componentsSeparatedByString:@";"]; + patharr = [pathlist componentsSeparatedByString: @";"]; #else - patharr = [pathlist componentsSeparatedByString:@":"]; + patharr = [pathlist componentsSeparatedByString: @":"]; #endif /* Add . if not already in path */ if ([patharr indexOfObject: @"."] == NSNotFound) @@ -285,7 +290,7 @@ AbsolutePathOfExecutable(NSString *path, BOOL atLaunch) patharr = [patharr objectEnumerator]; while (nil != (prefix = [patharr nextObject])) { - if ([prefix isEqual:@"."]) + if ([prefix isEqual: @"."]) { if (atLaunch == YES) { @@ -543,13 +548,14 @@ _find_framework(NSString *name) { NSArray *paths; NSFileManager *file_mgr = manager(); - NSString *file_name = [name stringByAppendingPathExtension:@"framework"]; + NSString *file_name; NSString *file_path; NSString *path; NSEnumerator *enumerator; NSCParameterAssert(name != nil); + file_name = [name stringByAppendingPathExtension: @"framework"]; paths = NSSearchPathForDirectoriesInDomains(GSFrameworksDirectory, NSAllDomainsMask,YES); @@ -922,9 +928,9 @@ _find_main_bundle_for_tool(NSString *toolName) for (j = 0; j < [l count]; j++) { if ([[l objectAtIndex: j] pointerValue] - == [[b objectAtIndex:i] pointerValue]) + == [[b objectAtIndex: i] pointerValue]) { - [l removeObjectAtIndex:j]; + [l removeObjectAtIndex: j]; } } } @@ -1382,6 +1388,7 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory) isNonInstalledTool = YES; } +#ifndef __ANDROID__ /* don't check suffix on Android's fake executable path */ if (isApplication == YES) { s = [path lastPathComponent]; @@ -1422,6 +1429,7 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory) } } } +#endif /* !__ANDROID__ */ if (isApplication == NO) { @@ -1805,9 +1813,6 @@ IF_NO_GC( { NSString *identifier = [self bundleIdentifier]; NSUInteger count; - NSUInteger plen = [_path length]; - NSEnumerator *enumerator; - NSString *path; [load_lock lock]; if (_bundles != nil) @@ -1835,38 +1840,7 @@ IF_NO_GC( /* Clean up path cache for this bundle. */ - [pathCacheLock lock]; - enumerator = [pathCache keyEnumerator]; - while (nil != (path = [enumerator nextObject])) - { - if (YES == [path hasPrefix: _path]) - { - if ([path length] == plen) - { - /* Remove the bundle directory path from the cache. - */ - [pathCache removeObjectForKey: path]; - } - else - { - unichar c = [path characterAtIndex: plen]; - - /* if the directory is inside the bundle, remove from cache. - */ - if ('/' == c) - { - [pathCache removeObjectForKey: path]; - } -#if defined(_WIN32) - else if ('\\' == c) - { - [pathCache removeObjectForKey: path]; - } -#endif - } - } - } - [pathCacheLock unlock]; + [self cleanPathCache]; RELEASE(_path); } TEST_RELEASE(_frameworkVersion); @@ -2144,6 +2118,59 @@ IF_NO_GC( addBundlePath(array, contents, primary, subPath, language); } } + +#ifdef __ANDROID__ + /* Android: check subdir and localization directly, as AAssetDir and thereby + * NSDirectoryEnumerator doesn't list directories + */ + NSString *originalPrimary = primary; + if (subPath) + { + primary = [originalPrimary stringByAppendingPathComponent: subPath]; + contents = bundle_directory_readable(primary); + addBundlePath(array, contents, primary, nil, nil); + + if (localization) + { + primary = [primary stringByAppendingPathComponent: + [localization stringByAppendingPathExtension: @"lproj"]]; + contents = bundle_directory_readable(primary); + addBundlePath(array, contents, primary, nil, nil); + } + else + { + NSString *subPathPrimary = primary; + + enumerate = [languages objectEnumerator]; + while ((language = [enumerate nextObject])) + { + primary = [subPathPrimary stringByAppendingPathComponent: + [language stringByAppendingPathExtension: @"lproj"]]; + contents = bundle_directory_readable(primary); + addBundlePath(array, contents, primary, nil, nil); + } + } + } + if (localization) + { + primary = [originalPrimary stringByAppendingPathComponent: + [localization stringByAppendingPathExtension: @"lproj"]]; + contents = bundle_directory_readable(primary); + addBundlePath(array, contents, primary, nil, nil); + } + else + { + enumerate = [languages objectEnumerator]; + while ((language = [enumerate nextObject])) + { + primary = [originalPrimary stringByAppendingPathComponent: + [language stringByAppendingPathExtension: @"lproj"]]; + contents = bundle_directory_readable(primary); + addBundlePath(array, contents, primary, nil, nil); + } + } +#endif /* __ANDROID__ */ + primary = rootPath; contents = bundle_directory_readable(primary); addBundlePath(array, contents, primary, subPath, nil); @@ -2254,7 +2281,7 @@ IF_NO_GC( #if !defined(_WIN32) if (_frameworkVersion) - rootPath = [NSString stringWithFormat:@"%@/Versions/%@", [self bundlePath], + rootPath = [NSString stringWithFormat: @"%@/Versions/%@", [self bundlePath], _frameworkVersion]; else #endif @@ -2525,6 +2552,27 @@ IF_NO_GC( locale = [[locale lastPathComponent] stringByDeletingPathExtension]; [array addObject: locale]; } + +#ifdef __ANDROID__ + // Android: Check known languages for localizations directly, as AAssetDir + // and thereby NSDirectoryEnumerator doesn't list directories and the above + // call to list lproj resources will therefore come up empty. + NSArray *languages = [[NSUserDefaults standardUserDefaults] + stringArrayForKey: @"NSLanguages"]; + + for (locale in languages) + { + NSString *path = [self pathForResource: @"Localizable" + ofType: @"strings" + inDirectory: nil + forLocalization: locale]; + if (path) + { + [array addObject: locale]; + } + } +#endif /* __ANDROID__ */ + return GS_IMMUTABLE(array); } @@ -2732,7 +2780,7 @@ IF_NO_GC( withString: @"_1"]; #if !defined(_WIN32) - path = [_path stringByAppendingPathComponent:@"Versions/Current"]; + path = [_path stringByAppendingPathComponent: @"Versions/Current"]; #else path = _path; #endif @@ -2766,7 +2814,7 @@ IF_NO_GC( { #if !defined(_WIN32) return [_path stringByAppendingPathComponent: - [NSString stringWithFormat:@"Versions/%@/%@", + [NSString stringWithFormat: @"Versions/%@/%@", version, executableName]]; #else return [_path stringByAppendingPathComponent: executableName]; @@ -2795,7 +2843,7 @@ IF_NO_GC( { #if !defined(_WIN32) return [_path stringByAppendingPathComponent: - [NSString stringWithFormat:@"Versions/%@/Resources", + [NSString stringWithFormat: @"Versions/%@/Resources", version]]; #else /* No Versions (that require symlinks) on mswindows */ @@ -2852,7 +2900,7 @@ IF_NO_GC( { #if !defined(_WIN32) return [_path stringByAppendingPathComponent: - [NSString stringWithFormat:@"Versions/%@/PlugIns", + [NSString stringWithFormat: @"Versions/%@/PlugIns", version]]; #else return [_path stringByAppendingPathComponent: @"PlugIns"]; @@ -2880,8 +2928,8 @@ IF_NO_GC( { #if !defined(_WIN32) return [_path stringByAppendingPathComponent: - [NSString stringWithFormat:@"Versions/%@/PrivateFrameworks", - version]]; + [NSString stringWithFormat: @"Versions/%@/PrivateFrameworks", + version]]; #else return [_path stringByAppendingPathComponent: @"PrivateFrameworks"]; #endif @@ -3202,5 +3250,142 @@ IF_NO_GC( return path; } +- (void)cleanPathCache +{ + NSUInteger plen = [_path length]; + NSEnumerator *enumerator; + NSString *path; + + [pathCacheLock lock]; + enumerator = [pathCache keyEnumerator]; + while (nil != (path = [enumerator nextObject])) + { + if (YES == [path hasPrefix: _path]) + { + if ([path length] == plen) + { + /* Remove the bundle directory path from the cache. + */ + [pathCache removeObjectForKey: path]; + } + else + { + unichar c = [path characterAtIndex: plen]; + + /* if the directory is inside the bundle, remove from cache. + */ + if ('/' == c) + { + [pathCache removeObjectForKey: path]; + } +#if defined(_WIN32) + else if ('\\' == c) + { + [pathCache removeObjectForKey: path]; + } +#endif + } + } + } + [pathCacheLock unlock]; + + /* also destroy cached variables depending on bundle paths */ + DESTROY(_infoDict); + DESTROY(_localizations); +} + +#ifdef __ANDROID__ + ++ (AAssetManager *)assetManager +{ + return _assetManager; +} + ++ (void) setJavaAssetManager: (jobject)jassetManager withJNIEnv: (JNIEnv *)env +{ + /* create global reference to Java asset manager to prevent garbage + * collection + */ + _jassetManager = (*env)->NewGlobalRef(env, jassetManager); + + // get native asset manager (may be shared across multiple threads) + _assetManager = AAssetManager_fromJava(env, _jassetManager); + + // clean main bundle path cache in case it was accessed before + [_mainBundle cleanPathCache]; +} + ++ (AAsset *) assetForPath: (NSString *)path +{ + return [self assetForPath: path withMode: AASSET_MODE_UNKNOWN]; +} + ++ (AAsset *) assetForPath: (NSString *)path withMode: (int)mode +{ + AAsset *asset = NULL; + + if (_assetManager && _mainBundle) + { + NSString *resourcePath = [_mainBundle resourcePath]; + + if ([path hasPrefix: resourcePath] + && [path length] > [resourcePath length]) + { + NSString *assetPath; + + assetPath = [path substringFromIndex: [resourcePath length] + 1]; + asset = AAssetManager_open(_assetManager, + [assetPath fileSystemRepresentation], mode); + } + } + + return asset; +} + ++ (AAssetDir *) assetDirForPath: (NSString *)path +{ + AAssetDir *assetDir = NULL; + + if (_assetManager && _mainBundle) + { + NSString *resourcePath = [_mainBundle resourcePath]; + + if ([path hasPrefix: resourcePath]) + { + NSString *assetPath = @""; + + if ([path length] > [resourcePath length]) + { + assetPath = [path substringFromIndex: [resourcePath length] + 1]; + } + + assetDir = AAssetManager_openDir(_assetManager, + [assetPath fileSystemRepresentation]); + + if (assetDir) + { + /* AAssetManager_openDir() always returns an object, + * so we check if the directory exists by ensuring + * it contains a file + */ + BOOL exists = AAssetDir_getNextFileName(assetDir) != NULL; + if (exists) + { + AAssetDir_rewind(assetDir); + } + else + { + AAssetDir_close(assetDir); + assetDir = NULL; + } + } + } + } + + return assetDir; +} + +#endif /* __ANDROID__ */ + @end diff --git a/Source/NSData.m b/Source/NSData.m index 1a3f507a0..d60c37f88 100644 --- a/Source/NSData.m +++ b/Source/NSData.m @@ -242,6 +242,40 @@ readContentsOfFile(NSString *path, void **buf, off_t *len, NSZone *zone) void *tmp = 0; int c; off_t fileLength; + +#ifdef __ANDROID__ + // Android: try using asset manager if path is in main bundle resources + AAsset *asset = [NSBundle assetForPath: path withMode: AASSET_MODE_BUFFER]; + if (asset) + { + fileLength = AAsset_getLength(asset); + + tmp = NSZoneMalloc(zone, fileLength); + if (tmp == 0) + { + NSLog(@"Malloc failed for file (%@) of length %jd - %@", path, + (intmax_t)fileLength, [NSError _last]); + AAsset_close(asset); + goto failure; + } + + int result = AAsset_read(asset, tmp, fileLength); + AAsset_close(asset); + + if (result < 0) + { + NSWarnFLog(@"read of file (%@) contents failed - %@", path, + [NSError errorWithDomain: NSPOSIXErrorDomain + code: result + userInfo: nil]); + goto failure; + } + + *buf = tmp; + *len = fileLength; + return YES; + } +#endif /* __ANDROID__ */ #if defined(_WIN32) thePath = (const unichar*)[path fileSystemRepresentation]; diff --git a/Source/NSFileManager.m b/Source/NSFileManager.m index c741184ca..2770c661c 100644 --- a/Source/NSFileManager.m +++ b/Source/NSFileManager.m @@ -241,7 +241,7 @@ struct _STATB statbuf; _CHAR _path[0]; } -+ (NSDictionary*) attributesAt: (const _CHAR*)lpath ++ (NSDictionary*) attributesAt: (NSString *)path traverseLink: (BOOL)traverse; @end @@ -738,7 +738,7 @@ static NSStringEncoding defaultEncoding; nxtImp = [direnum methodForSelector: @selector(nextObject)]; - urlArray = [NSMutableArray arrayWithCapacity:128]; + urlArray = [NSMutableArray arrayWithCapacity: 128]; while ((tempPath = (*nxtImp)(direnum, @selector(nextObject))) != nil) { NSURL *tempURL; @@ -749,7 +749,7 @@ static NSStringEncoding defaultEncoding; /* we purge files beginning with . */ if (!((mask & NSDirectoryEnumerationSkipsHiddenFiles) - && [lastComponent hasPrefix:@"."])) + && [lastComponent hasPrefix: @"."])) { [urlArray addObject: tempURL]; } @@ -1652,6 +1652,29 @@ static NSStringEncoding defaultEncoding; if (_STAT(lpath, &statbuf) != 0) { +#ifdef __ANDROID__ + /* Android: try using asset manager if path is in + * main bundle resources + */ + AAsset *asset = [NSBundle assetForPath: path]; + if (asset) + { + AAsset_close(asset); + return YES; + } + + AAssetDir *assetDir = [NSBundle assetDirForPath: path]; + if (assetDir) + { + AAssetDir_close(assetDir); + if (isDirectory) + { + *isDirectory = YES; + } + return YES; + } +#endif + return NO; } @@ -1700,6 +1723,17 @@ static NSStringEncoding defaultEncoding; { return YES; } + +#ifdef __ANDROID__ + // Android: try using asset manager if path is in main bundle resources + AAsset *asset = [NSBundle assetForPath: path]; + if (asset) + { + AAsset_close(asset); + return YES; + } +#endif + return NO; } #endif @@ -1929,8 +1963,7 @@ static NSStringEncoding defaultEncoding; { NSDictionary *d; - d = [GSAttrDictionaryClass attributesAt: - [self fileSystemRepresentationWithPath: path] traverseLink: flag]; + d = [GSAttrDictionaryClass attributesAt: path traverseLink: flag]; return d; } @@ -2012,8 +2045,7 @@ static NSStringEncoding defaultEncoding; NSDictionary *d; DESTROY(_lastError); - d = [GSAttrDictionaryClass attributesAt: - [self fileSystemRepresentationWithPath: path] traverseLink: NO]; + d = [GSAttrDictionaryClass attributesAt: path traverseLink: NO]; if (error != NULL) { @@ -2177,8 +2209,8 @@ static NSStringEncoding defaultEncoding; */ - (NSDictionary*) fileSystemAttributesAtPath: (NSString*)path { - return [self attributesOfFileSystemForPath:path - error:NULL]; + return [self attributesOfFileSystemForPath: path + error: NULL]; } /** @@ -2379,6 +2411,9 @@ static NSStringEncoding defaultEncoding; typedef struct _GSEnumeratedDirectory { NSString *path; _DIR *pointer; +#ifdef __ANDROID__ + AAssetDir *assetDir; +#endif } GSEnumeratedDirectory; @@ -2386,6 +2421,12 @@ static inline void gsedRelease(GSEnumeratedDirectory X) { DESTROY(X.path); _CLOSEDIR(X.pointer); +#ifdef __ANDROID__ + if (X.assetDir) + { + AAssetDir_close(X.assetDir); + } +#endif } #define GSI_ARRAY_TYPES 0 @@ -2443,12 +2484,29 @@ static inline void gsedRelease(GSEnumeratedDirectory X) localPath = [_mgr fileSystemRepresentationWithPath: path]; dir_pointer = _OPENDIR(localPath); + +#ifdef __ANDROID__ + AAssetDir *assetDir = NULL; + if (!dir_pointer) + { + /* Android: try using asset manager if path is in + * main bundle resources + */ + assetDir = [NSBundle assetDirForPath: path]; + } + + if (dir_pointer || assetDir) +#else if (dir_pointer) +#endif { GSIArrayItem item; item.ext.path = @""; item.ext.pointer = dir_pointer; +#ifdef __ANDROID__ + item.ext.assetDir = assetDir; +#endif GSIArrayAddItem(_stack, item); } @@ -2535,35 +2593,56 @@ static inline void gsedRelease(GSEnumeratedDirectory X) while (GSIArrayCount(_stack) > 0) { GSEnumeratedDirectory dir = GSIArrayLastItem(_stack).ext; - struct _DIRENT *dirbuf; struct _STATB statbuf; +#if defined(_WIN32) + const wchar_t *dirname = NULL; +#else + const char *dirname = NULL; +#endif - dirbuf = _READDIR(dir.pointer); +#ifdef __ANDROID__ + if (dir.assetDir) + { + /* This will only return files and not directories, which means that + * recursion is not supported. + * See https://issuetracker.google.com/issues/37002833 + */ + dirname = AAssetDir_getNextFileName(dir.assetDir); + } + else if (dir.pointer) +#endif + { + struct _DIRENT *dirbuf = _READDIR(dir.pointer); + if (dirbuf) + { + dirname = dirbuf->d_name; + } + } - if (dirbuf) + if (dirname) { #if defined(_WIN32) /* Skip "." and ".." directory entries */ - if (wcscmp(dirbuf->d_name, L".") == 0 - || wcscmp(dirbuf->d_name, L"..") == 0) + if (wcscmp(dirname, L".") == 0 + || wcscmp(dirname, L"..") == 0) { continue; } /* Name of file to return */ returnFileName = [_mgr - stringWithFileSystemRepresentation: dirbuf->d_name - length: wcslen(dirbuf->d_name)]; + stringWithFileSystemRepresentation: dirname + length: wcslen(dirname)]; #else /* Skip "." and ".." directory entries */ - if (strcmp(dirbuf->d_name, ".") == 0 - || strcmp(dirbuf->d_name, "..") == 0) + if (strcmp(dirname, ".") == 0 + || strcmp(dirname, "..") == 0) { continue; } /* Name of file to return */ returnFileName = [_mgr - stringWithFileSystemRepresentation: dirbuf->d_name - length: strlen(dirbuf->d_name)]; + stringWithFileSystemRepresentation: dirname + length: strlen(dirname)]; #endif /* if we have a null FileName something went wrong (charset?) and we skip it */ if (returnFileName == nil) @@ -2841,6 +2920,9 @@ static inline void gsedRelease(GSEnumeratedDirectory X) int rbytes; int wbytes; char buffer[bufsize]; +#ifdef __ANDROID__ + AAsset *asset = NULL; +#endif attributes = [self fileAttributesAtPath: source traverseLink: NO]; if (nil == attributes) @@ -2859,7 +2941,16 @@ static inline void gsedRelease(GSEnumeratedDirectory X) /* Open the source file. In case of error call the handler. */ sourceFd = open([self fileSystemRepresentationWithPath: source], GSBINIO|O_RDONLY); +#ifdef __ANDROID__ if (sourceFd < 0) + { + // Android: try using asset manager if path is in main bundle resources + asset = [NSBundle assetForPath: source withMode: AASSET_MODE_STREAMING]; + } + if (sourceFd < 0 && asset == NULL) +#else + if (sourceFd < 0) +#endif { return [self _proceedAccordingToHandler: handler forError: @"cannot open file for reading" @@ -2873,6 +2964,13 @@ static inline void gsedRelease(GSEnumeratedDirectory X) GSBINIO|O_WRONLY|O_CREAT|O_TRUNC, fileMode); if (destFd < 0) { +#ifdef __ANDROID__ + if (asset) + { + AAsset_close(asset); + } + else +#endif close (sourceFd); return [self _proceedAccordingToHandler: handler @@ -2886,6 +2984,13 @@ static inline void gsedRelease(GSEnumeratedDirectory X) file. In case of errors call the handler and abort the operation. */ for (i = 0; i < fileSize; i += rbytes) { +#ifdef __ANDROID__ + if (asset) + { + rbytes = AAsset_read(asset, buffer, bufsize); + } + else +#endif rbytes = read (sourceFd, buffer, bufsize); if (rbytes <= 0) { @@ -2893,6 +2998,13 @@ static inline void gsedRelease(GSEnumeratedDirectory X) { break; // End of input file } +#ifdef __ANDROID__ + if (asset) + { + AAsset_close(asset); + } + else +#endif close (sourceFd); close (destFd); @@ -2906,6 +3018,13 @@ static inline void gsedRelease(GSEnumeratedDirectory X) wbytes = write (destFd, buffer, rbytes); if (wbytes != rbytes) { +#ifdef __ANDROID__ + if (asset) + { + AAsset_close(asset); + } + else +#endif close (sourceFd); close (destFd); @@ -2916,6 +3035,13 @@ static inline void gsedRelease(GSEnumeratedDirectory X) toPath: destination]; } } +#ifdef __ANDROID__ + if (asset) + { + AAsset_close(asset); + } + else +#endif close (sourceFd); close (destFd); @@ -3252,12 +3378,16 @@ static inline void gsedRelease(GSEnumeratedDirectory X) static NSSet *fileKeys = nil; -+ (NSDictionary*) attributesAt: (const _CHAR*)lpath ++ (NSDictionary*) attributesAt: (NSString *)path traverseLink: (BOOL)traverse { GSAttrDictionary *d; unsigned l = 0; unsigned i; + const _CHAR *lpath = [defaultManager fileSystemRepresentationWithPath: path]; +#ifdef __ANDROID__ + AAsset *asset = NULL; +#endif if (lpath == 0 || *lpath == 0) { @@ -3275,6 +3405,13 @@ static NSSet *fileKeys = nil; { if (lstat(lpath, &d->statbuf) != 0) { +#ifdef __ANDROID__ + /* Android: try using asset manager if path is in + * main bundle resources + */ + asset = [NSBundle assetForPath: path]; + if (asset == NULL) +#endif DESTROY(d); } } @@ -3282,6 +3419,11 @@ static NSSet *fileKeys = nil; #endif if (_STAT(lpath, &d->statbuf) != 0) { +#ifdef __ANDROID__ + // Android: try using asset manager if path is in main bundle resources + asset = [NSBundle assetForPath: path]; + if (asset == NULL) +#endif DESTROY(d); } if (d != nil) @@ -3290,6 +3432,16 @@ static NSSet *fileKeys = nil; { d->_path[i] = lpath[i]; } +#ifdef __ANDROID__ + if (asset) + { + // set some basic stat values for Android assets + memset(&d->statbuf, 0, sizeof(d->statbuf)); + d->statbuf.st_mode = S_IRUSR; + d->statbuf.st_size = AAsset_getLength(asset); + AAsset_close(asset); + } +#endif } return AUTORELEASE(d); } diff --git a/Source/NSLog.m b/Source/NSLog.m index 35e6fc4f3..f2bc50718 100644 --- a/Source/NSLog.m +++ b/Source/NSLog.m @@ -181,8 +181,10 @@ _NSLog_standard_printf_handler(NSString* message) #else #if defined(HAVE_SYSLOG) +#ifndef __ANDROID__ // always use syslog on Android (no stdout/stderr) if (GSPrivateDefaultsFlag(GSLogSyslog) == YES || write(_NSLogDescriptor, buf, len) != (int)len) +#endif { null_terminated_buf = malloc(sizeof (char) * (len + 1)); strncpy (null_terminated_buf, buf, len); diff --git a/Source/NSObject.m b/Source/NSObject.m index eea533cd4..3c0f5569c 100644 --- a/Source/NSObject.m +++ b/Source/NSObject.m @@ -2580,12 +2580,56 @@ GSPrivateMemorySize(NSObject *self, NSHashTable *exclude) } @implementation NSObject (MemoryFootprint) ++ (NSUInteger) contentSizeInBytesOf: (NSObject*)instance + excluding: (NSHashTable*)exclude +{ + unsigned count; + Ivar *vars; + NSUInteger size = 0; + + if (0 != (vars = class_copyIvarList(self, &count))) + { + while (count-- > 0) + { + const char *type = ivar_getTypeEncoding(vars[count]); + + type = GSSkipTypeQualifierAndLayoutInfo(type); + if ('@' == *type) + { + NSObject *obj = object_getIvar(instance, vars[count]); + + if (obj != nil) + { + size += [obj sizeInBytesExcluding: exclude]; + } + } + } + free(vars); + } + return size; +} + (NSUInteger) sizeInBytesExcluding: (NSHashTable*)exclude { return 0; } - (NSUInteger) sizeInBytesExcluding: (NSHashTable*)exclude { - return GSPrivateMemorySize(self, exclude); + if (0 == NSHashGet(exclude, self)) + { + Class c = object_getClass(self); + NSUInteger size = class_getInstanceSize(c); + + NSHashInsert(exclude, self); + if (size > 0) + { + while (c != Nil) + { + size += [c contentSizeInBytesOf: self excluding: exclude]; + } + c = class_getSuperclass(c); + } + return size; + } + return 0; } @end diff --git a/Source/NSProcessInfo.m b/Source/NSProcessInfo.m index da94da15c..6f395ee3e 100644 --- a/Source/NSProcessInfo.m +++ b/Source/NSProcessInfo.m @@ -943,6 +943,35 @@ extern char **__libc_argv; } } +#elif defined(__ANDROID__) + ++ (void) initialize +{ + if (nil == procLock) procLock = [NSRecursiveLock new]; + if (self == [NSProcessInfo class] + && !_gnu_processName && !_gnu_arguments && !_gnu_environment) + { + FILE *f = fopen("/proc/self/cmdline", "r"); + + if (f) + { + char identifier[BUFSIZ]; + fgets(identifier, sizeof(identifier), f); + fclose(f); + + // construct fake executable path + char *arg0; + asprintf(&arg0, "/data/data/%s/exe", identifier); + + char *argv[] = { arg0 }; + _gnu_process_args(sizeof(argv)/sizeof(char *), argv, NULL); + } + else + { + fprintf(stderr, "Failed to read cmdline\n"); + } + } +} #else + (void) initialize diff --git a/Source/NSRunLoop.m b/Source/NSRunLoop.m index 1746fa3d0..962f04c55 100644 --- a/Source/NSRunLoop.m +++ b/Source/NSRunLoop.m @@ -62,10 +62,12 @@ #include #include -#if HAVE_DISPATCH_GET_MAIN_QUEUE_HANDLE_NP && HAVE_DISPATCH_MAIN_QUEUE_DRAIN_NP +#if HAVE_LIBDISPATCH_RUNLOOP # define RL_INTEGRATE_DISPATCH 1 # ifdef HAVE_DISPATCH_H # include +# elif HAVE_DISPATCH_PRIVATE_H +# include # elif HAVE_DISPATCH_DISPATCH_H # include # endif @@ -398,7 +400,13 @@ static inline BOOL timerInvalidated(NSTimer *t) @implementation GSMainQueueDrainer + (void*) mainQueueFileDescriptor { +#if HAVE_DISPATCH_GET_MAIN_QUEUE_HANDLE_NP return (void*)(uintptr_t)dispatch_get_main_queue_handle_np(); +#elif HAVE__DISPATCH_GET_MAIN_QUEUE_HANDLE_4CF + return (void*)_dispatch_get_main_queue_handle_4CF(); +#else +#error libdispatch missing main queue handle function +#endif } - (void) receivedEvent: (void*)data @@ -406,7 +414,13 @@ static inline BOOL timerInvalidated(NSTimer *t) extra: (void*)extra forMode: (NSString*)mode { +#if HAVE_DISPATCH_MAIN_QUEUE_DRAIN_NP dispatch_main_queue_drain_np(); +#elif HAVE__DISPATCH_MAIN_QUEUE_CALLBACK_4CF + _dispatch_main_queue_callback_4CF(NULL) +#else +#error libdispatch missing main queue callback function +#endif } @end #endif diff --git a/Source/NSThread.m b/Source/NSThread.m index 9419e28b3..c7b35c7ff 100644 --- a/Source/NSThread.m +++ b/Source/NSThread.m @@ -38,21 +38,40 @@ // Dummy implementatation // cleaner than IFDEF'ing the code everywhere #if !(HAVE_PTHREAD_SPIN_LOCK) -#warning no spin_locks, using dummy versions -typedef int pthread_spinlock_t; +typedef volatile int pthread_spinlock_t; int pthread_spin_init(pthread_spinlock_t *lock, int pshared) { -#if DEBUG +#if DEBUG && !__has_builtin(__sync_bool_compare_and_swap) fprintf(stderr,"NSThread.m: Warning this platform does not support spin locks - init.\n"); #endif return 0; } int pthread_spin_lock(pthread_spinlock_t *lock) { +#if __has_builtin(__sync_bool_compare_and_swap) + int count = 0; + // Set the spin lock value to 1 if it is 0. + while(!__sync_bool_compare_and_swap(lock, 0, 1)) + { + count++; + if (0 == count % 10) + { + // If it is already 1, let another thread play with the CPU for a + // bit then try again. + sleep(0); + } + } +#else + #warning no spin_locks, using dummy versions +#endif return 0; } int pthread_spin_unlock(pthread_spinlock_t *lock) { +#if __has_builtin(__sync_bool_compare_and_swap) + __sync_synchronize(); + *lock = 0; +#endif return 0; } int pthread_spin_destroy(pthread_spinlock_t *lock) diff --git a/configure b/configure index dc38115d8..431d93732 100755 --- a/configure +++ b/configure @@ -764,7 +764,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -879,7 +878,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' @@ -1132,15 +1130,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1278,7 +1267,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1431,7 +1420,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -5464,7 +5452,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -5510,7 +5498,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -5534,7 +5522,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -5579,7 +5567,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -5603,7 +5591,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -6008,6 +5996,9 @@ case "$target_os" in LDFLAGS="$LDFLAGS -L/usr/local/lib";; netbsd*) CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" LDFLAGS="$LDFLAGS -Wl,-R/usr/pkg/lib -L/usr/pkg/lib";; + linux-android* ) + # link against libandroid for native application APIs + LIBS="$LIBS -landroid";; esac #-------------------------------------------------------------------- @@ -12410,6 +12401,20 @@ else have_dispatch=no fi +done + + # check for private header which includes runloop integration functions in + # the Swift corelibs libdispatch release + for ac_header in dispatch/private.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "dispatch/private.h" "ac_cv_header_dispatch_private_h" "$ac_includes_default" +if test "x$ac_cv_header_dispatch_private_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DISPATCH_PRIVATE_H 1 +_ACEOF + +fi + done fi @@ -12515,10 +12520,24 @@ _ACEOF fi done - if test "$ac_cv_func_dispatch_main_queue_drain_np" = "no"; then + if test "$ac_cv_func_dispatch_main_queue_drain_np" = "yes" && test "$ac_cv_func_dispatch_get_main_queue_handle_np" = "yes"; then HAVE_LIBDISPATCH_RUNLOOP=1 fi - if test "$ac_cv_func_dispatch_get_main_queue_handle_np" = "no"; then + # Check for "_4CF" variants of runloop integration functions provided by the + # Swift corelibs libdispatch release + for ac_func in _dispatch_main_queue_callback_4CF _dispatch_get_main_queue_handle_4CF +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + if test "$ac_cv_func__dispatch_main_queue_callback_4CF" = "yes" && test "$ac_cv_func__dispatch_get_main_queue_handle_4CF" = "yes"; then HAVE_LIBDISPATCH_RUNLOOP=1 fi fi diff --git a/configure.ac b/configure.ac index 2b555fc1d..0636c0350 100644 --- a/configure.ac +++ b/configure.ac @@ -1246,6 +1246,9 @@ case "$target_os" in LDFLAGS="$LDFLAGS -L/usr/local/lib";; netbsd*) CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" LDFLAGS="$LDFLAGS -Wl,-R/usr/pkg/lib -L/usr/pkg/lib";; + linux-android* ) + # link against libandroid for native application APIs + LIBS="$LIBS -landroid";; esac #-------------------------------------------------------------------- @@ -3357,6 +3360,9 @@ if test $enable_libdispatch = yes; then AC_CHECK_HEADERS(dispatch.h, have_dispatch=yes, have_dispatch=no) if test "$have_dispatch" = "no"; then AC_CHECK_HEADERS(dispatch/dispatch.h, have_dispatch=yes, have_dispatch=no) + # check for private header which includes runloop integration functions in + # the Swift corelibs libdispatch release + AC_CHECK_HEADERS(dispatch/private.h) fi if test "$have_dispatch" = "yes"; then AC_CHECK_LIB(dispatch, dispatch_queue_create, have_dispatch=yes, have_dispatch=no) @@ -3388,10 +3394,13 @@ if test $HAVE_LIBDISPATCH = 1; then # We check whether we have a variant of libdispatch that allows runloop # integration AC_CHECK_FUNCS(dispatch_main_queue_drain_np dispatch_get_main_queue_handle_np) - if test "$ac_cv_func_dispatch_main_queue_drain_np" = "no"; then + if test "$ac_cv_func_dispatch_main_queue_drain_np" = "yes" && test "$ac_cv_func_dispatch_get_main_queue_handle_np" = "yes"; then HAVE_LIBDISPATCH_RUNLOOP=1 fi - if test "$ac_cv_func_dispatch_get_main_queue_handle_np" = "no"; then + # Check for "_4CF" variants of runloop integration functions provided by the + # Swift corelibs libdispatch release + AC_CHECK_FUNCS(_dispatch_main_queue_callback_4CF _dispatch_get_main_queue_handle_4CF) + if test "$ac_cv_func__dispatch_main_queue_callback_4CF" = "yes" && test "$ac_cv_func__dispatch_get_main_queue_handle_4CF" = "yes"; then HAVE_LIBDISPATCH_RUNLOOP=1 fi fi