diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bb1099078..4dac9a46f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,14 @@ project(Foundation LANGUAGES C Swift) enable_testing() +if(NOT SWIFT_SYSTEM_NAME) + if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + set(SWIFT_SYSTEM_NAME macosx) + else() + set(SWIFT_SYSTEM_NAME "$") + endif() +endif() + # NOTE(compnerd) default to /MD or /MDd by default based on the configuration. # Cache the variable to allow the user to alter the configuration. set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL" CACHE @@ -38,9 +46,10 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift) option(BUILD_SHARED_LIBS "build shared libraries" ON) +option(BUILD_FULLY_STATIC "build fully static" NO) option(HAS_LIBDISPATCH_API "has libdispatch API" ON) -option(BUILD_NETWORKING "build FoundationNetworking module" ON) -option(BUILD_TOOLS "build tools" ON) +option(FOUNDATION_ENABLE_FOUNDATION_NETWORKING "build FoundationNetworking module" ON) +option(FOUNDATION_BUILD_TOOLS "build tools" ON) option(NS_CURL_ASSUME_FEATURES_MISSING "Assume that optional libcurl features are missing rather than test the library's version, for build debugging" NO) if(HAS_LIBDISPATCH_API) @@ -49,6 +58,12 @@ endif() find_package(ICU COMPONENTS uc i18n REQUIRED OPTIONAL_COMPONENTS data) +# This is needed if we're statically linking, otherwise we can't pull in Dispatch +# because we won't have RT::rt as a CMake target. +if(NOT CMAKE_SYSTEM_NAME STREQUAL Android) + find_package(LibRT) +endif() + include(SwiftSupport) include(GNUInstallDirs) include(XCTest) @@ -57,7 +72,9 @@ set(CF_DEPLOYMENT_SWIFT YES CACHE BOOL "Build for Swift" FORCE) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG OFF) -find_package(Threads REQUIRED) +if(HAS_LIBDISPATCH_API) + find_package(Threads REQUIRED) +endif() set(SAVED_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) set(BUILD_SHARED_LIBS NO) @@ -99,13 +116,13 @@ if(NOT BUILD_SHARED_LIBS) endif() install(TARGETS CoreFoundation CFXMLInterface - DESTINATION lib/swift_static/$) + DESTINATION lib/swift_static/${SWIFT_SYSTEM_NAME}) - if(BUILD_NETWORKING) + if(FOUNDATION_ENABLE_FOUNDATION_NETWORKING) set_property(GLOBAL APPEND PROPERTY Foundation_EXPORTS CFURLSessionInterface) install(TARGETS CFURLSessionInterface - DESTINATION lib/swift_static/$) + DESTINATION lib/swift_static/${SWIFT_SYSTEM_NAME}) endif() endif() diff --git a/CoreFoundation/Base.subproj/CFFileUtilities.c b/CoreFoundation/Base.subproj/CFFileUtilities.c index 53596fb964..875526af2c 100644 --- a/CoreFoundation/Base.subproj/CFFileUtilities.c +++ b/CoreFoundation/Base.subproj/CFFileUtilities.c @@ -38,7 +38,11 @@ #include #include #include -#include + +#if !TARGET_OS_WASI +# include +#endif + #include #define statinfo stat @@ -341,7 +345,7 @@ CF_PRIVATE CFMutableArrayRef _CFCreateContentsOfDirectory(CFAllocatorRef alloc, FindClose(handle); pathBuf[pathLength] = '\0'; -#elif TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD +#elif TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI uint8_t extBuff[CFMaxPathSize]; int extBuffInteriorDotCount = 0; //people insist on using extensions like ".trace.plist", so we need to know how many dots back to look :( @@ -444,7 +448,7 @@ CF_PRIVATE CFMutableArrayRef _CFCreateContentsOfDirectory(CFAllocatorRef alloc, dirURL = CFURLCreateFromFileSystemRepresentation(alloc, (uint8_t *)dirPath, pathLength, true); releaseBase = true; } -#if !defined(__OpenBSD__) +#if !defined(__OpenBSD__) && !TARGET_OS_WASI if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN || dp->d_type == DT_LNK || dp->d_type == DT_WHT) { #else if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN || dp->d_type == DT_LNK) { @@ -461,13 +465,13 @@ CF_PRIVATE CFMutableArrayRef _CFCreateContentsOfDirectory(CFAllocatorRef alloc, isDir = ((statBuf.st_mode & S_IFMT) == S_IFDIR); } } -#if TARGET_OS_LINUX +#if TARGET_OS_LINUX || TARGET_OS_WASI fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, (uint8_t *)dp->d_name, namelen, isDir, dirURL); #else fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, (uint8_t *)dp->d_name, dp->d_namlen, isDir, dirURL); #endif } else { -#if TARGET_OS_LINUX +#if TARGET_OS_LINUX || TARGET_OS_WASI fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc, (uint8_t *)dp->d_name, namelen, false, dirURL); #else fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc, (uint8_t *)dp->d_name, dp->d_namlen, false, dirURL); @@ -554,7 +558,7 @@ CF_PRIVATE SInt32 _CFGetPathProperties(CFAllocatorRef alloc, char *path, Boolean if (modTime != NULL) { if (fileExists) { -#if TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI struct timespec ts = {statBuf.st_mtime, 0}; #else struct timespec ts = statBuf.st_mtimespec; @@ -1118,6 +1122,8 @@ CF_PRIVATE void _CFIterateDirectory(CFStringRef directoryPath, Boolean appendSla } } } +#elif TARGET_OS_WASI + CFIndex nameLen = strlen(dent->d_name); #else CFIndex nameLen = dent->d_namlen; #endif @@ -1130,7 +1136,25 @@ CF_PRIVATE void _CFIterateDirectory(CFStringRef directoryPath, Boolean appendSla // This buffer has to be 1 bigger than the size of the one in the dirent so we can hold the extra '/' if it's required // Be sure to initialize the first character to null, so that strlcat below works correctly - char fullPathToFile[sizeof(dent->d_name) + 1]; + #if TARGET_OS_WASI + // wasi-libc's dirent.d_name is not a fixed-size array but a pointer, so we need to calculate + // the size of buffer at first. + size_t d_name_size = nameLen; + if (stuffToPrefix) { + for (CFIndex i = 0; i < CFArrayGetCount(stuffToPrefix); i++) { + CFStringRef onePrefix = CFArrayGetValueAtIndex(stuffToPrefix, i); + size_t prefixLen = CFStringGetLength(onePrefix); + // Add 1 for concatenating '/' + if (d_name_size > nameLen) { + d_name_size += 1; + } + d_name_size += prefixLen; + } + } + #else + size_t d_name_size = sizeof(dent->d_name); + #endif + char fullPathToFile[d_name_size + 1]; fullPathToFile[0] = 0; CFIndex startAt = 0; diff --git a/CoreFoundation/Base.subproj/CFInternal.h b/CoreFoundation/Base.subproj/CFInternal.h index b737f30ec7..e5cc3840ad 100644 --- a/CoreFoundation/Base.subproj/CFInternal.h +++ b/CoreFoundation/Base.subproj/CFInternal.h @@ -654,6 +654,37 @@ CF_INLINE int _CFRecursiveMutexUnlock(_CFRecursiveMutex *mutex) { LeaveCriticalSection(mutex); return 0; } +#elif TARGET_OS_WASI +// For wasi-libc without pthread support (_POSIX_THREADS), just assume that it's single-threaded. +// wasi-libc with pthread support is handled by the _POSIX_THREADS case above. +typedef void *_CFMutex; +#define _CF_MUTEX_STATIC_INITIALIZER {} +CF_INLINE int _CFMutexCreate(_CFMutex *lock) { + return 0; +} +CF_INLINE int _CFMutexDestroy(_CFMutex *lock) { + return 0; +} +CF_INLINE int _CFMutexLock(_CFMutex *lock) { + return 0; +} +CF_INLINE int _CFMutexUnlock(_CFMutex *lock) { + return 0; +} + +typedef void *_CFRecursiveMutex; +CF_INLINE int _CFRecursiveMutexCreate(_CFRecursiveMutex *mutex) { + return 0; +} +CF_INLINE int _CFRecursiveMutexDestroy(_CFRecursiveMutex *mutex) { + return 0; +} +CF_INLINE int _CFRecursiveMutexLock(_CFRecursiveMutex *mutex) { + return 0; +} +CF_INLINE int _CFRecursiveMutexUnlock(_CFRecursiveMutex *mutex) { + return 0; +} #else #error "do not know how to define mutex and recursive mutex for this OS" #endif @@ -677,7 +708,7 @@ typedef uint32_t os_unfair_lock_options_t; static void os_unfair_lock_lock(os_unfair_lock_t lock) { pthread_mutex_lock(lock); } static void os_unfair_lock_lock_with_options(os_unfair_lock_t lock, os_unfair_lock_options_t options) { pthread_mutex_lock(lock); } static void os_unfair_lock_unlock(os_unfair_lock_t lock) { pthread_mutex_unlock(lock); } -#elif defined(_WIN32) +#elif defined(_WIN32) || TARGET_OS_WASI #define OS_UNFAIR_LOCK_INIT CFLockInit #define os_unfair_lock CFLock_t #define os_unfair_lock_lock __CFLock @@ -1172,12 +1203,13 @@ CF_INLINE dispatch_queue_t __CFDispatchQueueGetGenericBackground(void) { return dispatch_get_global_queue(QOS_CLASS_UTILITY, DISPATCH_QUEUE_OVERCOMMIT); } +CF_PRIVATE dispatch_data_t _CFDataCreateDispatchData(CFDataRef data); //avoids copying in most cases + #endif CF_PRIVATE CFStringRef _CFStringCopyBundleUnloadingProtectedString(CFStringRef str); CF_PRIVATE uint8_t *_CFDataGetBytePtrNonObjC(CFDataRef data); -CF_PRIVATE dispatch_data_t _CFDataCreateDispatchData(CFDataRef data); //avoids copying in most cases // Use this for functions that are intended to be breakpoint hooks. If you do not, the compiler may optimize them away. // Based on: BREAKPOINT_FUNCTION in objc-os.h diff --git a/CoreFoundation/Base.subproj/CFPlatform.c b/CoreFoundation/Base.subproj/CFPlatform.c index 040e8966f2..d89d8192ad 100644 --- a/CoreFoundation/Base.subproj/CFPlatform.c +++ b/CoreFoundation/Base.subproj/CFPlatform.c @@ -22,6 +22,10 @@ #include #endif +#if TARGET_OS_WASI +#include +#endif + #define _CFEmitInternalDiagnostics 0 @@ -62,11 +66,9 @@ int _CFArgc(void) { return *_NSGetArgc(); } #endif -#if !TARGET_OS_WASI CF_PRIVATE Boolean _CFGetCurrentDirectory(char *path, int maxlen) { return getcwd(path, maxlen) != NULL; } -#endif #if TARGET_OS_WIN32 // Returns the path to the CF DLL, which we can then use to find resources like char sets @@ -103,7 +105,6 @@ CF_PRIVATE const wchar_t *_CFDLLPath(void) { } #endif // TARGET_OS_WIN32 -#if !TARGET_OS_WASI static const char *__CFProcessPath = NULL; static const char *__CFprogname = NULL; @@ -186,6 +187,31 @@ const char *_CFProcessPath(void) { __CFprogname = __CFProcessPath; } return __CFProcessPath; +#elif TARGET_OS_WASI + __wasi_errno_t err; + size_t argc; + size_t argv_buf_size; + err = __wasi_args_sizes_get(&argc, &argv_buf_size); + if (err != 0) { + __CFProcessPath = ""; + __CFprogname = __CFProcessPath; + return __CFProcessPath; + } + char *argv_buf = malloc(argv_buf_size); + char **argv = calloc(argc, sizeof(char *)); + err = __wasi_args_get((uint8_t **)argv, (uint8_t *)argv_buf); + if (err != 0) { + __CFProcessPath = ""; + __CFprogname = __CFProcessPath; + free(argv_buf); + free(argv); + return __CFProcessPath; + } + _CFSetProgramNameFromPath(argv[0]); + free(argv_buf); + free(argv); + return __CFProcessPath; + #else // TARGET_OS_BSD char *argv0 = NULL; @@ -248,7 +274,6 @@ const char *_CFProcessPath(void) { return __CFProcessPath; #endif } -#endif // TARGET_OS_WASI #if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_BSD CF_CROSS_PLATFORM_EXPORT Boolean _CFIsMainThread(void) { @@ -273,7 +298,6 @@ Boolean _CFIsMainThread(void) { } #endif // TARGET_OS_LINUX -#if !TARGET_OS_WASI CF_PRIVATE CFStringRef _CFProcessNameString(void) { static CFStringRef __CFProcessNameString = NULL; if (!__CFProcessNameString) { @@ -292,7 +316,6 @@ CF_PRIVATE CFStringRef _CFProcessNameString(void) { } return __CFProcessNameString; } -#endif // !TARGET_OS_WASI #if TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD @@ -387,16 +410,20 @@ static CFURLRef _CFCopyHomeDirURLForUser(const char *username, bool fallBackToHo #endif -#if !TARGET_OS_WASI #define CFMaxHostNameLength 256 #define CFMaxHostNameSize (CFMaxHostNameLength+1) CF_PRIVATE CFStringRef _CFStringCreateHostName(void) { +#if TARGET_OS_WASI + // WASI doesn't have a concept of a hostname + return CFSTR(""); +#else char myName[CFMaxHostNameSize]; // return @"" instead of nil a la CFUserName() and Ali Ozer if (0 != gethostname(myName, CFMaxHostNameSize)) return CFSTR(""); return CFStringCreateWithCString(kCFAllocatorSystemDefault, myName, kCFPlatformInterfaceStringEncoding); +#endif } /* These are sanitized versions of the above functions. We might want to eliminate the above ones someday. @@ -433,6 +460,8 @@ CF_EXPORT CFStringRef CFCopyUserName(void) { result = CFStringCreateWithCString(kCFAllocatorSystemDefault, cname, kCFPlatformInterfaceStringEncoding); } } +#elif TARGET_OS_WASI + // WASI does not have user concept #else #error "Please add an implementation for CFCopyUserName() that copies the account username" #endif @@ -462,6 +491,8 @@ CF_CROSS_PLATFORM_EXPORT CFStringRef CFCopyFullUserName(void) { GetUserNameExW(NameDisplay, (LPWSTR)wszBuffer, &ulLength); result = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)wszBuffer, ulLength); +#elif TARGET_OS_WASI + // WASI does not have user concept #else #error "Please add an implementation for CFCopyFullUserName() that copies the full (display) user name" #endif @@ -528,6 +559,9 @@ CFURLRef CFCopyHomeDirectoryURL(void) { if (testPath) CFRelease(testPath); return retVal; +#elif TARGET_OS_WASI + // WASI does not have user concept + return NULL; #else #error Dont know how to compute users home directories on this platform #endif @@ -659,6 +693,9 @@ CF_EXPORT CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName) { CFAllocatorDeallocate(kCFAllocatorSystemDefault, pwszUserName); return url; +#elif TARGET_OS_WASI + // WASI does not have user concept + return NULL; #else #error Dont know how to compute users home directories on this platform #endif @@ -667,7 +704,6 @@ CF_EXPORT CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName) { #undef CFMaxHostNameLength #undef CFMaxHostNameSize -#endif // !TARGET_OS_WASI #if TARGET_OS_WIN32 CF_INLINE CFIndex strlen_UniChar(const UniChar* p) { @@ -1625,9 +1661,11 @@ CF_PRIVATE int asprintf(char **ret, const char *format, ...) { #if DEPLOYMENT_RUNTIME_SWIFT #include -extern void swift_retain(void *); +extern void *swift_retain(void *); extern void swift_release(void *); +#if SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + #if TARGET_OS_WIN32 typedef struct _CFThreadSpecificData { CFTypeRef value; @@ -1806,14 +1844,17 @@ CF_CROSS_PLATFORM_EXPORT int _CFThreadGetName(char *buf, int length) { #endif return -1; } +#endif // SWIFT_CORELIBS_FOUNDATION_HAS_THREADS CF_EXPORT char **_CFEnviron(void) { #if TARGET_OS_MAC return *_NSGetEnviron(); #elif TARGET_OS_WIN32 return _environ; +#elif TARGET_OS_WASI + return __wasilibc_get_environ(); #else -#if TARGET_OS_BSD || TARGET_OS_WASI +#if TARGET_OS_BSD extern char **environ; #endif return environ; diff --git a/CoreFoundation/Base.subproj/CFPriv.h b/CoreFoundation/Base.subproj/CFPriv.h index 692a106a99..c877565b91 100644 --- a/CoreFoundation/Base.subproj/CFPriv.h +++ b/CoreFoundation/Base.subproj/CFPriv.h @@ -46,10 +46,8 @@ #include #endif -#if !TARGET_OS_WASI #include #include -#endif #include @@ -57,19 +55,17 @@ CF_EXTERN_C_BEGIN CF_EXPORT void _CFRuntimeSetCFMPresent(void *a); -#if !TARGET_OS_WASI CF_EXPORT const char *_CFProcessPath(void); CF_EXPORT const char **_CFGetProcessPath(void); CF_EXPORT const char **_CFGetProgname(void); -#if !TARGET_OS_WIN32 +#if !TARGET_OS_WIN32 && !TARGET_OS_WASI #include CF_EXPORT void _CFGetUGIDs(uid_t *euid, gid_t *egid); CF_EXPORT uid_t _CFGetEUID(void); CF_EXPORT uid_t _CFGetEGID(void); #endif -#endif #if (TARGET_OS_MAC && !(TARGET_OS_IPHONE || TARGET_OS_LINUX)) CF_EXPORT void _CFRunLoopSetCurrent(CFRunLoopRef rl); @@ -166,7 +162,6 @@ CF_EXPORT Boolean _CFStringGetFileSystemRepresentation(CFStringRef string, UInt8 /* If this is publicized, we might need to create a GetBytesPtr type function as well. */ CF_EXPORT CFStringRef _CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const UInt8 *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator); -#if !TARGET_OS_WASI /* These return NULL on MacOS 8 */ // This one leaks the returned string in order to be thread-safe. // CF cannot help you in this matter if you continue to use this SPI. @@ -178,7 +173,6 @@ CFStringRef CFCopyUserName(void); CF_EXPORT CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName); /* Pass NULL for the current user's home directory */ -#endif /* diff --git a/CoreFoundation/Base.subproj/CFRuntime.c b/CoreFoundation/Base.subproj/CFRuntime.c index afdbf5d21e..bdd43eaab8 100644 --- a/CoreFoundation/Base.subproj/CFRuntime.c +++ b/CoreFoundation/Base.subproj/CFRuntime.c @@ -52,7 +52,7 @@ __kCFRetainEvent = 28, __kCFReleaseEvent = 29 }; -#if TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI #include #elif TARGET_OS_BSD #include // malloc() @@ -239,12 +239,14 @@ _CFClassTables __CFRuntimeClassTables __attribute__((aligned)) = { +#if !TARGET_OS_WASI [_kCFRuntimeIDCFRunLoopMode] = &__CFRunLoopModeClass, [_kCFRuntimeIDCFRunLoop] = &__CFRunLoopClass, [_kCFRuntimeIDCFRunLoopSource] = &__CFRunLoopSourceClass, [_kCFRuntimeIDCFRunLoopObserver] = &__CFRunLoopObserverClass, [_kCFRuntimeIDCFRunLoopTimer] = &__CFRunLoopTimerClass, [_kCFRuntimeIDCFSocket] = &__CFSocketClass, +#endif [_kCFRuntimeIDCFReadStream] = &__CFReadStreamClass, [_kCFRuntimeIDCFWriteStream] = &__CFWriteStreamClass, [_kCFRuntimeIDCFAttributedString] = &__CFAttributedStringClass, @@ -1162,7 +1164,7 @@ _CFThreadRef _CF_pthread_main_thread_np(void) { -#if TARGET_OS_LINUX || TARGET_OS_BSD +#if TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI static void __CFInitialize(void) __attribute__ ((constructor)); #endif #if TARGET_OS_WIN32 @@ -1194,9 +1196,13 @@ void __CFInitialize(void) { DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &_CFMainPThread, 0, FALSE, DUPLICATE_SAME_ACCESS); -#else +#elif _POSIX_THREADS // move this next line up into the #if above after Foundation gets off this symbol. Also: Stop using _CFMainPThread _CFMainPThread = pthread_self(); +#elif TARGET_OS_WASI + _CFMainPThread = kNilPthreadT; +#else +#error Dont know how to get the main thread on this platform #endif #if TARGET_OS_WIN32 @@ -1407,7 +1413,7 @@ int DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ) { #endif #if DEPLOYMENT_RUNTIME_SWIFT -extern void swift_retain(void *); +extern void *swift_retain(void *); #endif // For "tryR==true", a return of NULL means "failed". diff --git a/CoreFoundation/Base.subproj/CFUtilities.c b/CoreFoundation/Base.subproj/CFUtilities.c index 7c3fc9f8e7..371482bcad 100644 --- a/CoreFoundation/Base.subproj/CFUtilities.c +++ b/CoreFoundation/Base.subproj/CFUtilities.c @@ -927,8 +927,13 @@ static void _populateBanner(char **banner, char **time, char **thread, int *bann bannerLen = asprintf(banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%lx] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), GetCurrentThreadId()); asprintf(thread, "%lx", GetCurrentThreadId()); #elif TARGET_OS_WASI - bannerLen = asprintf(banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d [%x] ", year, month, day, hour, minute, second, ms, (unsigned int)pthread_self()); - asprintf(thread, "%lx", pthread_self()); + _CFThreadRef tid = 0; + // When pthread API is available from wasi-libc, use it. Otherwise use the dummy value. +# if _POSIX_THREADS + tid = pthread_self(); +# endif + bannerLen = asprintf(banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d [%x] ", year, month, day, hour, minute, second, ms, (unsigned int)tid); + asprintf(thread, "%lx", tid); #else bannerLen = asprintf(banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%x] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), (unsigned int)pthread_self()); asprintf(thread, "%lx", pthread_self()); @@ -1675,7 +1680,7 @@ CFDictionaryRef __CFGetEnvironment() { extern char **environ; char **envp = environ; #elif TARGET_OS_LINUX -#if !defined(environ) && !TARGET_OS_ANDROID +#if !defined(environ) && !TARGET_OS_ANDROID && !defined(__musl__) #define environ __environ #endif char **envp = environ; diff --git a/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h b/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h index bf6f203b5f..c1176c765c 100644 --- a/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h +++ b/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h @@ -189,7 +189,8 @@ static dispatch_queue_t __ ## PREFIX ## Queue(void) { \ #define CF_RETAIN_BALANCED_ELSEWHERE(obj, identified_location) do { } while (0) #endif -#if (TARGET_OS_LINUX && !TARGET_OS_ANDROID && !TARGET_OS_CYGWIN) || TARGET_OS_WIN32 +#if !TARGET_OS_MAC +#if !HAVE_STRLCPY CF_INLINE size_t strlcpy(char * dst, const char * src, size_t maxlen) { const size_t srclen = strlen(src); @@ -201,7 +202,9 @@ strlcpy(char * dst, const char * src, size_t maxlen) { } return srclen; } +#endif +#if !HAVE_STRLCAT CF_INLINE size_t strlcat(char * dst, const char * src, size_t maxlen) { const size_t srclen = strlen(src); @@ -216,6 +219,7 @@ strlcat(char * dst, const char * src, size_t maxlen) { return dstlen + srclen; } #endif +#endif // !TARGET_OS_MAC #if TARGET_OS_WIN32 // Compatibility with boolean.h @@ -256,7 +260,7 @@ CF_INLINE uint64_t mach_absolute_time() { ULONGLONG ullTime; QueryUnbiasedInterruptTimePrecise(&ullTime); return ullTime; -#elif TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_MAC +#elif TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_MAC || TARGET_OS_WASI struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (uint64_t)ts.tv_nsec + (uint64_t)ts.tv_sec * 1000000000UL; @@ -300,7 +304,7 @@ typedef unsigned long fd_mask; #endif -#if !TARGET_OS_CYGWIN && !TARGET_OS_BSD +#if !TARGET_OS_MAC && !HAVE_ISSETUGID #define issetugid() 0 #endif @@ -336,7 +340,7 @@ CF_INLINE size_t malloc_size(void *memblock) { #endif #endif -#if TARGET_OS_LINUX || TARGET_OS_BSD +#if TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI #include #endif #if TARGET_OS_WIN32 || TARGET_OS_LINUX diff --git a/CoreFoundation/Base.subproj/ForFoundationOnly.h b/CoreFoundation/Base.subproj/ForFoundationOnly.h index 4084755960..1eb77df7eb 100644 --- a/CoreFoundation/Base.subproj/ForFoundationOnly.h +++ b/CoreFoundation/Base.subproj/ForFoundationOnly.h @@ -28,10 +28,8 @@ #include #include -#if !TARGET_OS_WASI #include #include -#endif #include #include @@ -102,7 +100,6 @@ CF_EXPORT BOOL _NSIsNSCFConstantString(NSISARGTYPE arg); CF_EXPORT BOOL _NSIsNSIndexSet(NSISARGTYPE arg); CF_EXPORT BOOL _NSIsNSAttributedString(NSISARGTYPE arg); -#if !TARGET_OS_WASI #pragma mark - CFBundle #include @@ -127,7 +124,6 @@ CF_EXPORT Boolean _CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, Bool CF_EXPORT CFErrorRef _CFBundleCreateError(CFAllocatorRef _Nullable allocator, CFBundleRef bundle, CFIndex code); _CF_EXPORT_SCOPE_END -#endif #pragma mark - CFUUID @@ -651,7 +647,6 @@ CF_CROSS_PLATFORM_EXPORT void _CFURLInitWithFileSystemPathRelativeToBase(CFURLRe CF_CROSS_PLATFORM_EXPORT Boolean _CFURLInitWithURLString(CFURLRef url, CFStringRef string, Boolean checkForLegalCharacters, _Nullable CFURLRef baseURL); CF_CROSS_PLATFORM_EXPORT Boolean _CFURLInitAbsoluteURLWithBytes(CFURLRef url, const UInt8 *relativeURLBytes, CFIndex length, CFStringEncoding encoding, _Nullable CFURLRef baseURL); -#if !TARGET_OS_WASI CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef mode); CF_EXPORT CFTypeRef _CFRunLoopGet2(CFRunLoopRef rl); CF_EXPORT Boolean _CFRunLoopIsCurrent(CFRunLoopRef rl); @@ -662,7 +657,6 @@ CF_EXPORT void _CFWriteStreamInitialize(CFWriteStreamRef writeStream); CF_EXPORT void _CFReadStreamDeallocate(CFReadStreamRef readStream); CF_EXPORT void _CFWriteStreamDeallocate(CFWriteStreamRef writeStream); CF_EXPORT CFReadStreamRef CFReadStreamCreateWithData(_Nullable CFAllocatorRef alloc, CFDataRef data); -#endif #if TARGET_OS_MAC typedef struct { diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h index 642151ab34..cc1ba84355 100644 --- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h +++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h @@ -45,7 +45,7 @@ #if _POSIX_THREADS #include #endif -#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__wasi__) #include #endif @@ -64,11 +64,20 @@ #include #include #include +#elif TARGET_OS_WASI +#include +#include +// Define _WASI_EMULATED_MMAN here to use the emulated mman functions in +// Foundation-side without requiring transitive clients to define it. +#undef _WASI_EMULATED_MMAN +#define _WASI_EMULATED_MMAN +#include #elif TARGET_OS_LINUX #include #include #include +#ifdef __GLIBC_PREREQ #if __GLIBC_PREREQ(2, 28) == 0 // required for statx() system call, glibc >=2.28 wraps the kernel function #include @@ -78,7 +87,7 @@ #include #define AT_STATX_SYNC_AS_STAT 0x0000 /* - Do whatever stat() does */ #endif //__GLIBC_PREREQ(2. 28) - +#endif // defined(__GLIBC_PREREQ) #ifndef __NR_statx #include #endif // not __NR_statx @@ -379,9 +388,7 @@ CF_PRIVATE uint64_t __CFMemorySize(void); CF_PRIVATE CFIndex __CFActiveProcessorCount(void); CF_CROSS_PLATFORM_EXPORT CFStringRef CFCopyFullUserName(void); -#if !TARGET_OS_WASI extern CFWriteStreamRef _CFWriteStreamCreateFromFileDescriptor(CFAllocatorRef alloc, int fd); -#endif #if !__COREFOUNDATION_FORFOUNDATIONONLY__ typedef const struct __CFKeyedArchiverUID * CFKeyedArchiverUIDRef; @@ -393,9 +400,7 @@ extern uint32_t _CFKeyedArchiverUIDGetValue(CFKeyedArchiverUIDRef uid); extern CFIndex __CFBinaryPlistWriteToStream(CFPropertyListRef plist, CFTypeRef stream); CF_CROSS_PLATFORM_EXPORT CFDataRef _CFPropertyListCreateXMLDataWithExtras(CFAllocatorRef allocator, CFPropertyListRef propertyList); -#if !TARGET_OS_WASI extern CFWriteStreamRef _CFWriteStreamCreateFromFileDescriptor(CFAllocatorRef alloc, int fd); -#endif CF_EXPORT char *_Nullable *_Nonnull _CFEnviron(void); @@ -412,6 +417,10 @@ typedef unsigned long _CFThreadSpecificKey; typedef pthread_t _CFThreadRef; typedef pthread_attr_t _CFThreadAttributes; typedef pthread_key_t _CFThreadSpecificKey; +#elif TARGET_OS_WASI // WASI without pthreads +typedef void *_CFThreadRef; +typedef void *_CFThreadAttributes; +typedef void *_CFThreadSpecificKey; #endif CF_CROSS_PLATFORM_EXPORT Boolean _CFIsMainThread(void); @@ -423,6 +432,7 @@ CF_EXPORT CFHashCode __CFHashDouble(double d); CF_CROSS_PLATFORM_EXPORT void CFSortIndexes(CFIndex *indexBuffer, CFIndex count, CFOptionFlags opts, CFComparisonResult (^cmp)(CFIndex, CFIndex)); #endif +#if SWIFT_CORELIBS_FOUNDATION_HAS_THREADS CF_EXPORT CFTypeRef _Nullable _CFThreadSpecificGet(_CFThreadSpecificKey key); CF_EXPORT void _CFThreadSpecificSet(_CFThreadSpecificKey key, CFTypeRef _Nullable value); CF_EXPORT _CFThreadSpecificKey _CFThreadSpecificKeyCreate(void); @@ -431,13 +441,13 @@ CF_EXPORT _CFThreadRef _CFThreadCreate(const _CFThreadAttributes attrs, void *_N CF_CROSS_PLATFORM_EXPORT int _CFThreadSetName(_CFThreadRef thread, const char *_Nonnull name); CF_CROSS_PLATFORM_EXPORT int _CFThreadGetName(char *_Nonnull buf, int length); +#endif CF_EXPORT Boolean _CFCharacterSetIsLongCharacterMember(CFCharacterSetRef theSet, UTF32Char theChar); CF_EXPORT CFCharacterSetRef _CFCharacterSetCreateCopy(CFAllocatorRef alloc, CFCharacterSetRef theSet); CF_EXPORT CFMutableCharacterSetRef _CFCharacterSetCreateMutableCopy(CFAllocatorRef alloc, CFCharacterSetRef theSet); CF_CROSS_PLATFORM_EXPORT void _CFCharacterSetInitCopyingSet(CFAllocatorRef alloc, CFMutableCharacterSetRef cset, CFCharacterSetRef theSet, bool isMutable, bool validateSubclasses); -#if !TARGET_OS_WASI CF_EXPORT _Nullable CFErrorRef CFReadStreamCopyError(CFReadStreamRef _Null_unspecified stream); CF_EXPORT _Nullable CFErrorRef CFWriteStreamCopyError(CFWriteStreamRef _Null_unspecified stream); @@ -446,7 +456,6 @@ CF_CROSS_PLATFORM_EXPORT CFStringRef _Nullable _CFBundleCopyExecutablePath(CFBun CF_CROSS_PLATFORM_EXPORT Boolean _CFBundleSupportsFHSBundles(void); CF_CROSS_PLATFORM_EXPORT Boolean _CFBundleSupportsFreestandingBundles(void); CF_CROSS_PLATFORM_EXPORT CFStringRef _Nullable _CFBundleCopyLoadedImagePathForAddress(const void *p); -#endif CF_CROSS_PLATFORM_EXPORT CFStringRef __CFTimeZoneCopyDataVersionString(void); @@ -552,30 +561,44 @@ CF_CROSS_PLATFORM_EXPORT CFIndex __CFCharDigitValue(UniChar ch); #if TARGET_OS_WIN32 CF_CROSS_PLATFORM_EXPORT int _CFOpenFileWithMode(const unsigned short *path, int opts, mode_t mode); -#elif !TARGET_OS_WASI +#else CF_CROSS_PLATFORM_EXPORT int _CFOpenFileWithMode(const char *path, int opts, mode_t mode); #endif CF_CROSS_PLATFORM_EXPORT void *_CFReallocf(void *ptr, size_t size); CF_CROSS_PLATFORM_EXPORT int _CFOpenFile(const char *path, int opts); -#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__wasi__) static inline int _direntNameLength(struct dirent *entry) { #ifdef _D_EXACT_NAMLEN // defined on Linux return _D_EXACT_NAMLEN(entry); -#elif TARGET_OS_ANDROID +#elif TARGET_OS_LINUX || TARGET_OS_ANDROID || TARGET_OS_WASI return strlen(entry->d_name); #else return entry->d_namlen; #endif } +static inline char *_direntName(struct dirent *entry) { + return entry->d_name; +} + // major() and minor() might be implemented as macros or functions. static inline unsigned int _dev_major(dev_t rdev) { +#if !TARGET_OS_WASI return major(rdev); +#else + // WASI does not have device numbers + return 0; +#endif } static inline unsigned int _dev_minor(dev_t rdev) { +#if !TARGET_OS_WASI return minor(rdev); +#else + // WASI does not have device numbers + return 0; +#endif } #endif @@ -695,6 +718,15 @@ typedef struct _REPARSE_DATA_BUFFER { } REPARSE_DATA_BUFFER; #endif +#if TARGET_OS_WASI +static inline uint8_t _getConst_DT_DIR(void) { return DT_DIR; } +static inline int32_t _getConst_O_CREAT(void) { return O_CREAT; } +static inline int32_t _getConst_O_DIRECTORY(void) { return O_DIRECTORY; } +static inline int32_t _getConst_O_EXCL(void) { return O_EXCL; } +static inline int32_t _getConst_O_TRUNC(void) { return O_TRUNC; } +static inline int32_t _getConst_O_WRONLY(void) { return O_WRONLY; } +#endif + #if !TARGET_OS_WIN32 typedef void * _CFPosixSpawnFileActionsRef; typedef void * _CFPosixSpawnAttrRef; diff --git a/CoreFoundation/Base.subproj/SwiftRuntime/CoreFoundation.h b/CoreFoundation/Base.subproj/SwiftRuntime/CoreFoundation.h index b373875ac2..245aef64df 100644 --- a/CoreFoundation/Base.subproj/SwiftRuntime/CoreFoundation.h +++ b/CoreFoundation/Base.subproj/SwiftRuntime/CoreFoundation.h @@ -86,13 +86,15 @@ #include #include -#if !TARGET_OS_WASI #include +#if !TARGET_OS_WASI #include #include +#endif #include #include #include +#if !TARGET_OS_WASI #include #include #endif diff --git a/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt index beb48d6c86..11fd5d76e7 100644 --- a/CoreFoundation/CMakeLists.txt +++ b/CoreFoundation/CMakeLists.txt @@ -6,6 +6,9 @@ project(CoreFoundation VERSION 1338 LANGUAGES ASM C) +include(CheckSymbolExists) +include(CheckIncludeFile) + set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED YES) @@ -22,15 +25,20 @@ set(CMAKE_POSITION_INDEPENDENT_CODE YES) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG OFF) -find_package(Threads REQUIRED) +if(HAS_LIBDISPATCH_API) + find_package(Threads REQUIRED) +endif() if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) find_package(LibXml2 REQUIRED) - find_package(CURL CONFIG) - if(CURL_FOUND) - set(CURL_VERSION_STRING ${CURL_VERSION}) - else() - find_package(CURL REQUIRED) + + if(FOUNDATION_ENABLE_FOUNDATION_NETWORKING) + find_package(CURL CONFIG) + if(CURL_FOUND) + set(CURL_VERSION_STRING ${CURL_VERSION}) + else() + find_package(CURL REQUIRED) + endif() endif() endif() @@ -70,8 +78,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL Android) add_compile_definitions($<$:_GNU_SOURCE>) if(CMAKE_SYSTEM_NAME STREQUAL Linux) - include(CheckSymbolExists) - include(CheckIncludeFile) list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) check_include_file("sched.h" HAVE_SCHED_H) if(HAVE_SCHED_H) @@ -90,6 +96,21 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL Windows) endif() endif() +# Look for some functions that may not be present on all platforms +check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY) +check_symbol_exists(strlcat "string.h" HAVE_STRLCAT) +check_symbol_exists(issetugid "unistd.h" HAVE_ISSETUGID) + +if(HAVE_STRLCPY) + add_compile_definitions($<$:HAVE_STRLCPY>) +endif() +if(HAVE_STRLCAT) + add_compile_definitions($<$:HAVE_STRLCAT>) +endif() +if(HAVE_ISSETUGID) + add_compile_definitions($<$:HAVE_ISSETUGID>) +endif() + add_compile_definitions($<$:U_SHOW_DRAFT_API>) add_compile_definitions($<$:CF_BUILDING_CF>) @@ -99,6 +120,10 @@ else() add_compile_definitions($<$:DEPLOYMENT_RUNTIME_C>) endif() +if(Threads_FOUND) + add_compile_definitions($<$:SWIFT_CORELIBS_FOUNDATION_HAS_THREADS>) +endif() + # TODO(compnerd) ensure that the compiler supports the warning flag add_compile_options($<$:-Wno-shorten-64-to-32>) add_compile_options($<$:-Wno-deprecated-declarations>) @@ -385,10 +410,15 @@ target_include_directories(CoreFoundation PRIVATE ${PROJECT_SOURCE_DIR}) target_link_libraries(CoreFoundation PRIVATE - Threads::Threads ${CMAKE_DL_LIBS} - BlocksRuntime - dispatch) + BlocksRuntime) + +if(HAS_LIBDISPATCH_API) + target_link_libraries(CoreFoundation PRIVATE + Threads::Threads + dispatch) +endif() + if(CMAKE_SYSTEM_NAME STREQUAL Android) target_link_libraries(CoreFoundation PRIVATE log) @@ -431,7 +461,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL Windows) PRIVATE CURL_STATICLIB) endif() -if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) +if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin AND FOUNDATION_ENABLE_FOUNDATION_NETWORKING) target_link_libraries(CFURLSessionInterface PRIVATE CURL::libcurl) endif() @@ -449,6 +479,11 @@ add_framework(CFXMLInterface SOURCES Parsing.subproj/CFXMLInterface.c) add_dependencies(CFXMLInterface CoreFoundation) +if(NOT HAS_LIBDISPATCH_API) + # Explicitly link BlocksRuntime if we are not using libdispatch, which + # indirectly brings BlocksRuntime in. + target_link_libraries(CFXMLInterface PRIVATE BlocksRuntime) +endif() if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) target_link_libraries(CFXMLInterface PRIVATE LibXml2::LibXml2) @@ -504,15 +539,18 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL Windows AND NOT CMAKE_SYSTEM_NAME STREQUAL Dar PRIVATE m) endif() -target_link_libraries(CoreFoundation - PRIVATE - dispatch) -target_link_libraries(CFURLSessionInterface - PRIVATE - dispatch) -target_link_libraries(CFXMLInterface - PRIVATE - dispatch) + +if(HAS_LIBDISPATCH_API) + target_link_libraries(CoreFoundation + PRIVATE + dispatch) + target_link_libraries(CFURLSessionInterface + PRIVATE + dispatch) + target_link_libraries(CFXMLInterface + PRIVATE + dispatch) +endif() if(CMAKE_SYSTEM_NAME STREQUAL Darwin) target_link_libraries(CoreFoundation PRIVATE @@ -528,12 +566,25 @@ if(CMAKE_SYSTEM_NAME STREQUAL Darwin) -Xlinker;-alias_list;-Xlinker;Base.subproj/DarwinSymbolAliases;-twolevel_namespace;-sectcreate;__UNICODE;__csbitmaps;CharacterSets/CFCharacterSetBitmaps.bitmap;-sectcreate;__UNICODE;__properties;CharacterSets/CFUniCharPropertyDatabase.data;-sectcreate;__UNICODE;__data;CharacterSets/CFUnicodeData-L.mapping;-segprot;__UNICODE;r;r) endif() +if(CMAKE_SYSTEM_NAME STREQUAL WASI) + # Enable emulated features + set(WASI_EMULATION_DEFS _WASI_EMULATED_MMAN _WASI_EMULATED_SIGNAL _WASI_EMULATED_PROCESS_CLOCKS) + target_compile_definitions(CoreFoundation PRIVATE ${WASI_EMULATION_DEFS}) + target_compile_definitions(CFXMLInterface PRIVATE ${WASI_EMULATION_DEFS}) +endif() + install(TARGETS CoreFoundation - CFURLSessionInterface CFXMLInterface DESTINATION - "${CMAKE_INSTALL_FULL_LIBDIR}") + "${CMAKE_INSTALL_FULL_LIBDIR}/$") + +if(FOUNDATION_ENABLE_FOUNDATION_NETWORKING) + install(TARGETS + CFURLSessionInterface + DESTINATION + "${CMAKE_INSTALL_FULL_LIBDIR}/$") +endif() # Needed to avoid double slash "//" when CMAKE_INSTALL_PREFIX set to "/" and DESTDIR used to relocate whole installation. # Double slash raise CMake error "file called with network path DESTINATION //System/Library/Frameworks". diff --git a/CoreFoundation/Locale.subproj/CFDateIntervalFormatter.c b/CoreFoundation/Locale.subproj/CFDateIntervalFormatter.c index 78c0df3c15..6fe554c85b 100644 --- a/CoreFoundation/Locale.subproj/CFDateIntervalFormatter.c +++ b/CoreFoundation/Locale.subproj/CFDateIntervalFormatter.c @@ -507,7 +507,7 @@ void _CFDateIntervalFormatterSetBoundaryStyle(CFDateIntervalFormatterRef formatt CFStringRef CFDateIntervalFormatterCreateStringFromDateToDate(CFDateIntervalFormatterRef formatter, CFDateRef fromDate, CFDateRef toDate) { LOCK(); - CFStringRef resultStr = CFSTR(""); + CFStringRef resultStr = NULL; updateFormatter(formatter); if (formatter->_formatter) { @@ -531,7 +531,7 @@ CFStringRef CFDateIntervalFormatterCreateStringFromDateToDate(CFDateIntervalForm resultStr = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, result, len); } } else { - resultStr = CFSTR(""); + resultStr = (CFStringRef)CFRetain(CFSTR("")); } UNLOCK(); diff --git a/CoreFoundation/Locale.subproj/CFLocale.c b/CoreFoundation/Locale.subproj/CFLocale.c index c5c555c92a..2c2a942dc8 100644 --- a/CoreFoundation/Locale.subproj/CFLocale.c +++ b/CoreFoundation/Locale.subproj/CFLocale.c @@ -19,15 +19,11 @@ #include #include "CFInternal.h" #include "CFRuntime_Internal.h" -#if !TARGET_OS_WASI #include #include "CFBundle_Internal.h" -#else -#include "CFBase.h" -#endif #include "CFLocaleInternal.h" #include -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_BSD +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI #include // ICU locales #include // ICU locale data #include @@ -1274,7 +1270,7 @@ static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { - static CFStringRef const kCFLocaleCodesKey = CFSTR("__kCFLocaleCodes"); + CFStringRef const kCFLocaleCodesKey = CFSTR("__kCFLocaleCodes"); bool codesWasAllocated = false; CFDictionaryRef codes = NULL; diff --git a/CoreFoundation/NumberDate.subproj/CFDate.c b/CoreFoundation/NumberDate.subproj/CFDate.c index e6abb43cb2..3be4a850ce 100644 --- a/CoreFoundation/NumberDate.subproj/CFDate.c +++ b/CoreFoundation/NumberDate.subproj/CFDate.c @@ -359,7 +359,7 @@ CFAbsoluteTime CFGregorianDateGetAbsoluteTime(CFGregorianDate gdate, CFTimeZoneR CFAbsoluteTime at; at = 86400.0 * __CFAbsoluteFromYMD(gdate.year - 2001, gdate.month, gdate.day); at += 3600.0 * gdate.hour + 60.0 * gdate.minute + gdate.second; -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } @@ -378,7 +378,7 @@ CFGregorianDate CFAbsoluteTimeGetGregorianDate(CFAbsoluteTime at, CFTimeZoneRef int64_t absolute, year; int8_t month, day; CFAbsoluteTime fixedat; -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } @@ -406,7 +406,7 @@ CFAbsoluteTime CFAbsoluteTimeAddGregorianUnits(CFAbsoluteTime at, CFTimeZoneRef CFAbsoluteTime candidate_at0, candidate_at1; uint8_t monthdays; -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } @@ -525,7 +525,7 @@ CFGregorianUnits CFAbsoluteTimeGetDifferenceAsGregorianUnits(CFAbsoluteTime at1, SInt32 CFAbsoluteTimeGetDayOfWeek(CFAbsoluteTime at, CFTimeZoneRef tz) { int64_t absolute; CFAbsoluteTime fixedat; -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } @@ -541,7 +541,7 @@ SInt32 CFAbsoluteTimeGetDayOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) { CFAbsoluteTime fixedat; int64_t absolute, year; int8_t month, day; -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } @@ -560,7 +560,7 @@ SInt32 CFAbsoluteTimeGetWeekOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) { int64_t absolute, year; int8_t month, day; CFAbsoluteTime fixedat; -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } diff --git a/CoreFoundation/Parsing.subproj/CFBinaryPList.c b/CoreFoundation/Parsing.subproj/CFBinaryPList.c index 54a4877c0b..2331035c89 100644 --- a/CoreFoundation/Parsing.subproj/CFBinaryPList.c +++ b/CoreFoundation/Parsing.subproj/CFBinaryPList.c @@ -31,9 +31,7 @@ #include "CFRuntime_Internal.h" #include "CFPropertyList_Internal.h" -#if !TARGET_OS_WASI #include -#endif enum { CF_NO_ERROR = 0, @@ -135,7 +133,6 @@ uint32_t _CFKeyedArchiverUIDGetValue(CFKeyedArchiverUIDRef uid) { CF_PRIVATE CFErrorRef __CFPropertyListCreateError(CFIndex code, CFStringRef debugString, ...); -#if !TARGET_OS_WASI typedef struct { CFTypeRef stream; void *databytes; @@ -696,7 +693,6 @@ CF_PRIVATE CFDataRef __CFBinaryPlistCreateDataUsingExternalBufferAllocator(CFPro } return result; } -#endif #pragma mark - #pragma mark Reading diff --git a/CoreFoundation/Parsing.subproj/CFPropertyList.c b/CoreFoundation/Parsing.subproj/CFPropertyList.c index 1a40299052..feec18ba81 100644 --- a/CoreFoundation/Parsing.subproj/CFPropertyList.c +++ b/CoreFoundation/Parsing.subproj/CFPropertyList.c @@ -24,9 +24,7 @@ #include "CFRuntime_Internal.h" #include #include -#if !TARGET_OS_WASI #include -#endif #include #include "CFLocaleInternal.h" #include @@ -2325,7 +2323,7 @@ static CFStringEncoding encodingForXMLData(CFDataRef data, CFErrorRef *error, CF if (len == 5 && (*base == 'u' || *base == 'U') && (base[1] == 't' || base[1] == 'T') && (base[2] == 'f' || base[2] == 'F') && (base[3] == '-') && (base[4] == '8')) return kCFStringEncodingUTF8; encodingName = CFStringCreateWithBytes(kCFAllocatorSystemDefault, base, len, kCFStringEncodingISOLatin1, false); -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI CFStringEncoding enc = CFStringConvertIANACharSetNameToEncoding(encodingName); if (enc != kCFStringEncodingInvalidId) { if (encodingName) {CFRelease(encodingName); } @@ -2898,7 +2896,6 @@ CFPropertyListRef CFPropertyListCreateFromXMLData(CFAllocatorRef allocator, CFDa return result; } -#if !TARGET_OS_WASI CFDataRef CFPropertyListCreateData(CFAllocatorRef allocator, CFPropertyListRef propertyList, CFPropertyListFormat format, CFOptionFlags options, CFErrorRef *error) { CFAssert1(format != kCFPropertyListOpenStepFormat, __kCFLogAssertion, "%s(): kCFPropertyListOpenStepFormat not supported for writing", __PRETTY_FUNCTION__); CFAssert2(format == kCFPropertyListXMLFormat_v1_0 || format == kCFPropertyListBinaryFormat_v1_0, __kCFLogAssertion, "%s(): Unrecognized option %ld", __PRETTY_FUNCTION__, format); @@ -3152,7 +3149,6 @@ bool _CFPropertyListValidateData(CFDataRef data, CFTypeID *outTopLevelTypeID) { return result; } -#endif #pragma mark - #pragma mark Property List Copies diff --git a/CoreFoundation/Parsing.subproj/CFPropertyList.h b/CoreFoundation/Parsing.subproj/CFPropertyList.h index 07b32e6b46..728f5c59fe 100644 --- a/CoreFoundation/Parsing.subproj/CFPropertyList.h +++ b/CoreFoundation/Parsing.subproj/CFPropertyList.h @@ -15,9 +15,7 @@ #include #include -#if !TARGET_OS_WASI #include -#endif CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN @@ -131,7 +129,6 @@ CF_ENUM(CFIndex) { CF_EXPORT CFPropertyListRef CFPropertyListCreateWithData(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags options, CFPropertyListFormat *format, CFErrorRef *error) API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)); -#if !TARGET_OS_WASI /* Create and return a property list with a CFReadStream input. If the format parameter is non-NULL, it will be set to the format of the data after parsing is complete. The options parameter is used to specify CFPropertyListMutabilityOptions. The streamLength parameter specifies the number of bytes to read from the stream. Set streamLength to 0 to read until the end of the stream is detected. If an error occurs while parsing the data, the return value will be NULL. Additionally, if an error occurs and the error parameter is non-NULL, the error parameter will be set to a CFError describing the problem, which the caller must release. If the parse succeeds, the returned value is a reference to the new property list. It is the responsibility of the caller to release this value. */ CF_EXPORT @@ -141,7 +138,6 @@ CFPropertyListRef CFPropertyListCreateWithStream(CFAllocatorRef allocator, CFRea */ CF_EXPORT CFIndex CFPropertyListWrite(CFPropertyListRef propertyList, CFWriteStreamRef stream, CFPropertyListFormat format, CFOptionFlags options, CFErrorRef *error) API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)); -#endif /* Create a CFData with the bytes of a serialized property list. The format of the property list can be chosen with the format parameter. The options parameter is currently unused and should be set to 0. If an error occurs while parsing the data, the return value will be NULL. Additionally, if an error occurs and the error parameter is non-NULL, the error parameter will be set to a CFError describing the problem, which the caller must release. If the conversion succeeds, the returned value is a reference to the created data. It is the responsibility of the caller to release this value. */ diff --git a/CoreFoundation/PlugIn.subproj/CFBundle.c b/CoreFoundation/PlugIn.subproj/CFBundle.c index e9e6db3de7..bdf20e0d27 100644 --- a/CoreFoundation/PlugIn.subproj/CFBundle.c +++ b/CoreFoundation/PlugIn.subproj/CFBundle.c @@ -42,7 +42,7 @@ #endif #endif /* BINARY_SUPPORT_DLFCN */ -#if TARGET_OS_MAC +#if TARGET_OS_MAC || TARGET_OS_WASI #include #elif TARGET_OS_WIN32 #include diff --git a/CoreFoundation/PlugIn.subproj/CFBundle_BinaryTypes.h b/CoreFoundation/PlugIn.subproj/CFBundle_BinaryTypes.h index 7528e80eb1..33e74b3fda 100644 --- a/CoreFoundation/PlugIn.subproj/CFBundle_BinaryTypes.h +++ b/CoreFoundation/PlugIn.subproj/CFBundle_BinaryTypes.h @@ -28,6 +28,7 @@ CF_EXTERN_C_BEGIN #define BINARY_SUPPORT_DLL 1 #elif TARGET_OS_LINUX || TARGET_OS_BSD #define BINARY_SUPPORT_DLFCN 1 +#elif TARGET_OS_WASI #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif diff --git a/CoreFoundation/PlugIn.subproj/CFBundle_InfoPlist.c b/CoreFoundation/PlugIn.subproj/CFBundle_InfoPlist.c index 3a9e0101eb..5f4c926ba1 100644 --- a/CoreFoundation/PlugIn.subproj/CFBundle_InfoPlist.c +++ b/CoreFoundation/PlugIn.subproj/CFBundle_InfoPlist.c @@ -15,7 +15,7 @@ #include #include -#if (TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD) && !TARGET_OS_CYGWIN +#if (TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI) && !TARGET_OS_CYGWIN #include #if TARGET_OS_MAC || TARGET_OS_BSD #include @@ -142,6 +142,8 @@ CF_PRIVATE CFStringRef _CFBundleGetPlatformNameSuffix(void) { return _CFBundleLinuxPlatformNameSuffix; #elif TARGET_OS_BSD return _CFBundleFreeBSDPlatformNameSuffix; +#elif TARGET_OS_WASI + return _CFBundleWASIPlatformNameSuffix; #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -174,6 +176,8 @@ CF_EXPORT CFStringRef _CFGetPlatformName(void) { #endif #elif TARGET_OS_BSD return _CFBundleFreeBSDPlatformName; +#elif TARGET_OS_WASI + return _CFBundleWASIPlatformName; #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -194,6 +198,8 @@ CF_EXPORT CFStringRef _CFGetAlternatePlatformName(void) { #endif #elif TARGET_OS_BSD return CFSTR("FreeBSD"); +#elif TARGET_OS_WASI + return CFSTR("WASI"); #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif diff --git a/CoreFoundation/PlugIn.subproj/CFBundle_Internal.h b/CoreFoundation/PlugIn.subproj/CFBundle_Internal.h index def3aafc8d..244f0494a7 100644 --- a/CoreFoundation/PlugIn.subproj/CFBundle_Internal.h +++ b/CoreFoundation/PlugIn.subproj/CFBundle_Internal.h @@ -32,7 +32,7 @@ CF_EXTERN_C_BEGIN // FHS bundles are supported on the Swift and C runtimes, except on Windows. #if !DEPLOYMENT_RUNTIME_OBJC && !TARGET_OS_WIN32 -#if TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_ANDROID +#if TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_ANDROID || TARGET_OS_WASI #define _CFBundleFHSSharedLibraryFilenamePrefix CFSTR("lib") #define _CFBundleFHSSharedLibraryFilenameSuffix CFSTR(".so") #elif TARGET_OS_MAC @@ -390,6 +390,7 @@ extern void _CFPlugInWillUnload(CFPlugInRef plugIn); #define _CFBundleSolarisPlatformName CFSTR("solaris") #define _CFBundleLinuxPlatformName CFSTR("linux") #define _CFBundleFreeBSDPlatformName CFSTR("freebsd") +#define _CFBundleWASIPlatformName CFSTR("wasi") #define _CFBundleMacOSXPlatformNameSuffix CFSTR("-macos") #define _CFBundleAlternateMacOSXPlatformNameSuffix CFSTR("-macosx") #define _CFBundleiPhoneOSPlatformNameSuffix CFSTR("-iphoneos") @@ -400,6 +401,7 @@ extern void _CFPlugInWillUnload(CFPlugInRef plugIn); #define _CFBundleSolarisPlatformNameSuffix CFSTR("-solaris") #define _CFBundleLinuxPlatformNameSuffix CFSTR("-linux") #define _CFBundleFreeBSDPlatformNameSuffix CFSTR("-freebsd") +#define _CFBundleWASIPlatformNameSuffix CFSTR("-wasi") STATIC_CONST_STRING_DECL(_CFBundleMacDeviceName, "mac"); STATIC_CONST_STRING_DECL(_CFBundleiPhoneDeviceName, "iphone"); diff --git a/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c b/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c index 567caf3129..621feed4a8 100644 --- a/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c +++ b/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c @@ -148,8 +148,8 @@ const char * const __CFBundleLanguageAbbreviationsArray = static CFStringRef _CFBundleGetAlternateNameForLanguage(CFStringRef language) { // These are not necessarily common localizations per se, but localizations for which the full language name is still in common use. // These are used to provide a fast path for it (other localizations usually use the abbreviation, which is even faster). - static CFStringRef const __CFBundleCommonLanguageNamesArray[] = {CFSTR("English"), CFSTR("French"), CFSTR("German"), CFSTR("Italian"), CFSTR("Dutch"), CFSTR("Spanish"), CFSTR("Japanese")}; - static CFStringRef const __CFBundleCommonLanguageAbbreviationsArray[] = {CFSTR("en"), CFSTR("fr"), CFSTR("de"), CFSTR("it"), CFSTR("nl"), CFSTR("es"), CFSTR("ja")}; + CFStringRef const __CFBundleCommonLanguageNamesArray[] = {CFSTR("English"), CFSTR("French"), CFSTR("German"), CFSTR("Italian"), CFSTR("Dutch"), CFSTR("Spanish"), CFSTR("Japanese")}; + CFStringRef const __CFBundleCommonLanguageAbbreviationsArray[] = {CFSTR("en"), CFSTR("fr"), CFSTR("de"), CFSTR("it"), CFSTR("nl"), CFSTR("es"), CFSTR("ja")}; for (CFIndex idx = 0; idx < sizeof(__CFBundleCommonLanguageNamesArray) / sizeof(CFStringRef); idx++) { if (CFEqual(language, __CFBundleCommonLanguageAbbreviationsArray[idx])) { diff --git a/CoreFoundation/PlugIn.subproj/CFBundle_Resources.c b/CoreFoundation/PlugIn.subproj/CFBundle_Resources.c index c7fb636b71..acccefeada 100644 --- a/CoreFoundation/PlugIn.subproj/CFBundle_Resources.c +++ b/CoreFoundation/PlugIn.subproj/CFBundle_Resources.c @@ -507,6 +507,8 @@ CF_EXPORT CFStringRef _CFBundleGetCurrentPlatform(void) { #endif #elif TARGET_OS_BSD return CFSTR("FreeBSD"); +#elif TARGET_OS_WASI + return CFSTR("WASI"); #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -529,6 +531,8 @@ CF_PRIVATE CFStringRef _CFBundleGetPlatformExecutablesSubdirectoryName(void) { #endif #elif TARGET_OS_BSD return CFSTR("FreeBSD"); +#elif TARGET_OS_WASI + return CFSTR("WASI"); #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -1242,7 +1246,7 @@ CF_EXPORT CFTypeRef _Nullable _CFBundleCopyFindResources(CFBundleRef _Nullable b if (returnValue) CFRelease(returnValue); if ((bundleVersion == _CFBundleVersionOldStyleResources && realSubdirectory && CFEqual(realSubdirectory, CFSTR("Resources"))) || (bundleVersion == _CFBundleVersionContentsResources && realSubdirectory && CFEqual(realSubdirectory, CFSTR("Contents/Resources")))) { if (realSubdirectory) CFRelease(realSubdirectory); - realSubdirectory = CFSTR(""); + realSubdirectory = (CFStringRef)CFRetain(CFSTR("")); } else if (bundleVersion == _CFBundleVersionOldStyleResources && realSubdirectory && CFStringGetLength(realSubdirectory) > 10 && CFStringHasPrefix(realSubdirectory, CFSTR("Resources/"))) { CFStringRef tmpRealSubdirectory = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, realSubdirectory, CFRangeMake(10, CFStringGetLength(realSubdirectory) - 10)); if (realSubdirectory) CFRelease(realSubdirectory); diff --git a/CoreFoundation/Preferences.subproj/CFPreferences.c b/CoreFoundation/Preferences.subproj/CFPreferences.c index e8f88bcb75..f81c879640 100644 --- a/CoreFoundation/Preferences.subproj/CFPreferences.c +++ b/CoreFoundation/Preferences.subproj/CFPreferences.c @@ -420,7 +420,7 @@ static CFStringRef _CFPreferencesStandardDomainCacheKey(CFStringRef domainName static CFURLRef _CFPreferencesURLForStandardDomainWithSafetyLevel(CFStringRef domainName, CFStringRef userName, CFStringRef hostName, unsigned long safeLevel) { CFURLRef theURL = NULL; CFAllocatorRef prefAlloc = __CFPreferencesAllocator(); -#if TARGET_OS_OSX || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_BSD +#if TARGET_OS_OSX || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI CFURLRef prefDir = _preferencesCreateDirectoryForUserHostSafetyLevel(userName, hostName, safeLevel); CFStringRef appName; CFStringRef fileName; @@ -454,7 +454,7 @@ static CFURLRef _CFPreferencesURLForStandardDomainWithSafetyLevel(CFStringRef do CFRelease(appName); } if (fileName) { -#if TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD +#if TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI theURL = CFURLCreateWithFileSystemPathRelativeToBase(prefAlloc, fileName, kCFURLPOSIXPathStyle, false, prefDir); #elif TARGET_OS_WIN32 theURL = CFURLCreateWithFileSystemPathRelativeToBase(prefAlloc, fileName, kCFURLWindowsPathStyle, false, prefDir); diff --git a/CoreFoundation/Preferences.subproj/CFXMLPreferencesDomain.c b/CoreFoundation/Preferences.subproj/CFXMLPreferencesDomain.c index 2c037657a4..c7a87de559 100644 --- a/CoreFoundation/Preferences.subproj/CFXMLPreferencesDomain.c +++ b/CoreFoundation/Preferences.subproj/CFXMLPreferencesDomain.c @@ -55,7 +55,7 @@ static void __CFMilliSleep(uint32_t msecs) { SleepEx(msecs, false); #elif defined(__svr4__) || defined(__hpux__) sleep((msecs + 900) / 1000); -#elif TARGET_OS_OSX || TARGET_OS_LINUX || TARGET_OS_BSD +#elif TARGET_OS_OSX || TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI struct timespec input; input.tv_sec = msecs / 1000; input.tv_nsec = (msecs - input.tv_sec * 1000) * 1000000; diff --git a/CoreFoundation/RunLoop.subproj/CFRunLoop.c b/CoreFoundation/RunLoop.subproj/CFRunLoop.c index 466eb6fe9d..0a1bcc72be 100644 --- a/CoreFoundation/RunLoop.subproj/CFRunLoop.c +++ b/CoreFoundation/RunLoop.subproj/CFRunLoop.c @@ -8,6 +8,8 @@ Responsibility: Michael LeHew */ +#if __HAS_DISPATCH__ + #include #include #include @@ -1306,7 +1308,7 @@ static Boolean __CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls) { } CF_INLINE void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls) { - atomic_compare_exchange_strong_explicit(&rls->_signaledTime, &(uint64_t){0}, mach_absolute_time(), memory_order_acq_rel, memory_order_acq_rel); + atomic_compare_exchange_strong_explicit(&rls->_signaledTime, &(uint64_t){0}, mach_absolute_time(), memory_order_acq_rel, memory_order_acquire); } CF_INLINE void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls) { @@ -4756,3 +4758,4 @@ void CFRunLoopTimerSetTolerance(CFRunLoopTimerRef rlt, CFTimeInterval tolerance) #endif } +#endif /* __HAS_DISPATCH__ */ diff --git a/CoreFoundation/RunLoop.subproj/CFSocket.c b/CoreFoundation/RunLoop.subproj/CFSocket.c index 31add9ef64..357dab6838 100644 --- a/CoreFoundation/RunLoop.subproj/CFSocket.c +++ b/CoreFoundation/RunLoop.subproj/CFSocket.c @@ -8,6 +8,8 @@ Responsibility: Michael LeHew */ +#if __HAS_DISPATCH__ + #include #include #include @@ -2639,3 +2641,4 @@ CF_EXPORT uint16_t CFSocketGetDefaultNameRegistryPortNumber(void) { return __CFSocketDefaultNameRegistryPortNumber; } +#endif /* __HAS_DISPATCH__ */ diff --git a/CoreFoundation/Stream.subproj/CFStream.c b/CoreFoundation/Stream.subproj/CFStream.c index 010f69bc13..1cfeeb657d 100644 --- a/CoreFoundation/Stream.subproj/CFStream.c +++ b/CoreFoundation/Stream.subproj/CFStream.c @@ -93,6 +93,7 @@ CF_INLINE CFRunLoopSourceRef _CFStreamCopySource(struct _CFStream* stream) { } CF_INLINE void _CFStreamSetSource(struct _CFStream* stream, CFRunLoopSourceRef source, Boolean invalidateOldSource) { +#if __HAS_DISPATCH__ CFRunLoopSourceRef oldSource = NULL; if (stream) { @@ -119,6 +120,7 @@ CF_INLINE void _CFStreamSetSource(struct _CFStream* stream, CFRunLoopSourceRef s // And lose the one that held it in our stream as well CFRelease(oldSource); } +#endif } CF_INLINE const struct _CFStreamCallBacks *_CFStreamGetCallBackPtr(struct _CFStream *stream) { @@ -135,6 +137,7 @@ CF_INLINE void _CFStreamSetStatusCode(struct _CFStream *stream, CFStreamStatus n } CF_INLINE void _CFStreamScheduleEvent(struct _CFStream *stream, CFStreamEventType event) { +#if __HAS_DISPATCH__ if (stream->client && (stream->client->when & event)) { CFRunLoopSourceRef source = _CFStreamCopySource(stream); if (source) { @@ -145,6 +148,7 @@ CF_INLINE void _CFStreamScheduleEvent(struct _CFStream *stream, CFStreamEventTyp _wakeUpRunLoop(stream); } } +#endif } CF_INLINE void _CFStreamSetStreamError(struct _CFStream *stream, CFStreamError *err) { @@ -203,6 +207,7 @@ static void _CFStreamDetachSource(struct _CFStream* stream) { CFAssert(CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, CFArrayGetCount(list)), stream) == kCFNotFound, __kCFLogAssertion, "CFStreamClose: stream found twice in its shared source's list"); +#if __HAS_DISPATCH__ if (count == 0) { CFRunLoopSourceRef source = _CFStreamCopySource(stream); if (source) { @@ -211,6 +216,7 @@ static void _CFStreamDetachSource(struct _CFStream* stream) { } CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey); } +#endif CFDictionaryRemoveValue(sSharedSources, stream); @@ -653,6 +659,7 @@ static void _cfstream_shared_signalEventSync(void* info) break; } } +#if __HAS_DISPATCH__ /* And then we also signal any other streams in this array so that we get them next go? */ for (; i < c; i++) { @@ -675,6 +682,7 @@ static void _cfstream_shared_signalEventSync(void* info) break; } } +#endif __CFUnlock(&sSourceLock); @@ -788,6 +796,7 @@ CF_PRIVATE void _CFStreamSignalEvent(struct _CFStream *stream, CFStreamEventType _CFStreamSetStatusCode(stream, kCFStreamStatusError); } +#if __HAS_DISPATCH__ // Now signal any pertinent event - if not already signaled if (stream->client && (stream->client->when & event) != 0 && (stream->client->whatToSignal & event) == 0) { CFRunLoopSourceRef source = _CFStreamCopySource(stream); @@ -824,6 +833,7 @@ CF_PRIVATE void _CFStreamSignalEvent(struct _CFStream *stream, CFStreamEventType CFRelease(source); } } +#endif } CF_PRIVATE CFStreamStatus _CFStreamGetStatus(struct _CFStream *stream) { @@ -1375,6 +1385,7 @@ CF_EXPORT void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream) { CF_PRIVATE void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) { const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream); +#if __HAS_DISPATCH__ if (! stream->client) { _initializeClient(stream); if (!stream->client) return; // we don't support asynch. @@ -1469,6 +1480,7 @@ CF_PRIVATE void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, CFRunLoop count--; } +#if __HAS_DISPATCH__ if (count == 0) { CFRunLoopSourceRef source = _CFStreamCopySource(stream); if (source) { @@ -1477,6 +1489,7 @@ CF_PRIVATE void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, CFRunLoop } CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey); } +#endif CFDictionaryRemoveValue(sSharedSources, stream); @@ -1529,6 +1542,7 @@ CF_PRIVATE void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, CFRunLoop _wakeUpRunLoop(stream); } } +#endif } CF_EXPORT void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) { @@ -1568,11 +1582,13 @@ CF_PRIVATE void _CFStreamUnscheduleFromRunLoop(struct _CFStream *stream, CFRunLo if (!stream->client->rlSource) return; if (!__CFBitIsSet(stream->flags, SHARED_SOURCE)) { +#if __HAS_DISPATCH__ CFRunLoopSourceRef source = _CFStreamCopySource(stream); if (source) { CFRunLoopRemoveSource(runLoop, source, runLoopMode); CFRelease(source); } +#endif } else { CFArrayRef runLoopAndSourceKey; CFMutableArrayRef list; @@ -1590,6 +1606,7 @@ CF_PRIVATE void _CFStreamUnscheduleFromRunLoop(struct _CFStream *stream, CFRunLo count--; } +#if __HAS_DISPATCH__ if (count == 0) { CFRunLoopSourceRef source = _CFStreamCopySource(stream); if (source) { @@ -1598,6 +1615,7 @@ CF_PRIVATE void _CFStreamUnscheduleFromRunLoop(struct _CFStream *stream, CFRunLo } CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey); } +#endif CFDictionaryRemoveValue(sSharedSources, stream); @@ -1850,6 +1868,7 @@ dispatch_queue_t CFWriteStreamCopyDispatchQueue(CFWriteStreamRef stream) #endif static void waitForOpen(struct _CFStream *stream) { +#if __HAS_DISPATCH__ CFRunLoopRef runLoop = CFRunLoopGetCurrent(); CFStringRef privateMode = CFSTR("_kCFStreamBlockingOpenMode"); _CFStreamScheduleWithRunLoop(stream, runLoop, privateMode); @@ -1858,6 +1877,7 @@ static void waitForOpen(struct _CFStream *stream) { CFRunLoopRunInMode(privateMode, 1e+20, TRUE); } _CFStreamUnscheduleFromRunLoop(stream, runLoop, privateMode); +#endif } CF_PRIVATE CFArrayRef _CFReadStreamCopyRunLoopsAndModes(CFReadStreamRef readStream) { diff --git a/CoreFoundation/Stream.subproj/CFStream.h b/CoreFoundation/Stream.subproj/CFStream.h index b3ed237862..feeef1f5a2 100644 --- a/CoreFoundation/Stream.subproj/CFStream.h +++ b/CoreFoundation/Stream.subproj/CFStream.h @@ -17,7 +17,10 @@ #include #include #include + +#if __HAS_DISPATCH__ #include +#endif CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN @@ -456,7 +459,7 @@ void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef _Null_unspecified stream, CF_EXPORT void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef _Null_unspecified stream, CFRunLoopRef _Null_unspecified runLoop, CFRunLoopMode _Null_unspecified runLoopMode); - +#if __HAS_DISPATCH__ /* * Specify the dispatch queue upon which the client callbacks will be invoked. * Passing NULL for the queue will prevent future callbacks from being invoked. @@ -480,6 +483,7 @@ dispatch_queue_t _Null_unspecified CFReadStreamCopyDispatchQueue(CFReadStreamRef CF_EXPORT dispatch_queue_t _Null_unspecified CFWriteStreamCopyDispatchQueue(CFWriteStreamRef _Null_unspecified stream) API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0)); +#endif /* The following API is deprecated starting in 10.5; please use CFRead/WriteStreamCopyError(), above, instead */ diff --git a/CoreFoundation/String.subproj/CFCharacterSetData.S b/CoreFoundation/String.subproj/CFCharacterSetData.S index 6cc016c3dd..488bac1c87 100644 --- a/CoreFoundation/String.subproj/CFCharacterSetData.S +++ b/CoreFoundation/String.subproj/CFCharacterSetData.S @@ -11,19 +11,30 @@ #if defined(__ELF__) .section .rodata +#elif defined(__wasm__) +.section .data.characterset_bitmap_data,"",@ #endif .global _C_LABEL(__CFCharacterSetBitmapData) _C_LABEL(__CFCharacterSetBitmapData): .incbin CF_CHARACTERSET_BITMAP +#if defined(__wasm__) + .size _C_LABEL(__CFCharacterSetBitmapData), . - _C_LABEL(__CFCharacterSetBitmapData) +#endif .global _C_LABEL(__CFCharacterSetBitmapDataEnd) _C_LABEL(__CFCharacterSetBitmapDataEnd): .byte 0 +#if defined(__wasm__) + .size _C_LABEL(__CFCharacterSetBitmapDataEnd), . - _C_LABEL(__CFCharacterSetBitmapDataEnd) +#endif .global _C_LABEL(__CFCharacterSetBitmapDataSize) _C_LABEL(__CFCharacterSetBitmapDataSize): .int _C_LABEL(__CFCharacterSetBitmapDataEnd) - _C_LABEL(__CFCharacterSetBitmapData) +#if defined(__wasm__) + .size _C_LABEL(__CFCharacterSetBitmapDataSize), . - _C_LABEL(__CFCharacterSetBitmapDataSize) +#endif NO_EXEC_STACK_DIRECTIVE SAFESEH_REGISTRATION_DIRECTIVE diff --git a/CoreFoundation/String.subproj/CFString.c b/CoreFoundation/String.subproj/CFString.c index ad23980722..8b606a025a 100644 --- a/CoreFoundation/String.subproj/CFString.c +++ b/CoreFoundation/String.subproj/CFString.c @@ -38,6 +38,9 @@ #if TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD #include #endif +#if TARGET_OS_WASI +#include // for u_char +#endif #if defined(__GNUC__) #define LONG_DOUBLE_SUPPORT 1 @@ -6276,7 +6279,7 @@ enum { CFFormatIncompleteSpecifierType = 43 /* special case for a trailing incomplete specifier */ }; -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI /* Only come in here if spec->type is CFFormatLongType or CFFormatDoubleType. Pass in 0 for width or precision if not specified. Returns false if couldn't do the format (with the assumption the caller falls back to unlocalized). */ static Boolean __CFStringFormatLocalizedNumber(CFMutableStringRef output, CFLocaleRef locale, const CFPrintValue *values, const CFFormatSpec *spec, SInt32 width, SInt32 precision, Boolean hasPrecision) { @@ -7493,7 +7496,7 @@ static Boolean __CFStringAppendFormatCore(CFMutableStringRef outputString, CFStr switch (specs[curSpec].type) { case CFFormatLongType: case CFFormatDoubleType: -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (localizedFormatting && (specs[curSpec].flags & kCFStringFormatLocalizable)) { // We have a locale, so we do localized formatting oldLength = __CFStringFormatOutputLengthIfNeeded(); if (__CFStringFormatLocalizedNumber(outputString, (CFLocaleRef)formatOptions, values, &specs[curSpec], width, precision, hasPrecision)) { diff --git a/CoreFoundation/String.subproj/CFStringUtilities.c b/CoreFoundation/String.subproj/CFStringUtilities.c index 29e5c94ccd..4a9af6aded 100644 --- a/CoreFoundation/String.subproj/CFStringUtilities.c +++ b/CoreFoundation/String.subproj/CFStringUtilities.c @@ -18,7 +18,7 @@ #include "CFString_Internal.h" #include #include -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI #include #include #endif @@ -111,7 +111,7 @@ CFStringEncoding CFStringConvertIANACharSetNameToEncoding(CFStringRef charsetNam encoding = __CFStringEncodingGetFromCanonicalName(name); -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (kCFStringEncodingInvalidId == encoding) encoding = __CFStringEncodingGetFromICUName(name); #endif @@ -262,7 +262,7 @@ CFStringEncoding CFStringGetMostCompatibleMacStringEncoding(CFStringEncoding enc #define kCFStringCompareAllocationIncrement (128) -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI // ------------------------------------------------------------------------------------------------- // CompareSpecials - ignore case & diacritic differences @@ -425,7 +425,7 @@ static UCollator *__CFStringCopyDefaultCollator(CFLocaleRef compareLocale) { return collator; } -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI static void __collatorFinalize(UCollator *collator) { CFLocaleRef locale = _CFGetTSD(__CFTSDKeyCollatorLocale); _CFSetTSD(__CFTSDKeyCollatorUCollator, NULL, NULL); @@ -578,7 +578,7 @@ CF_PRIVATE CFComparisonResult _CFCompareStringsWithLocale(CFStringInlineBuffer * CFRange range1 = str1Range; CFRange range2 = str2Range; SInt32 order; -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI Boolean isEqual; bool forcedOrdering = ((options & kCFCompareForcedOrdering) ? true : false); @@ -611,7 +611,7 @@ CF_PRIVATE CFComparisonResult _CFCompareStringsWithLocale(CFStringInlineBuffer * range2.location = __extendLocationBackward(range2.location - 1, str2, nonBaseBMP, punctBMP); } -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI // First we try to use the last one used on this thread, if the locale is the same, // otherwise we try to check out a default one, or then we create one. UCollator *threadCollator = _CFGetTSD(__CFTSDKeyCollatorUCollator); @@ -633,7 +633,7 @@ CF_PRIVATE CFComparisonResult _CFCompareStringsWithLocale(CFStringInlineBuffer * range1.length = (str1Range.location + str1Range.length) - range1.location; range2.length = (str2Range.location + str2Range.length) - range2.location; -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if ((NULL != collator) && (__CompareTextDefault(collator, options, characters1, range1.length, characters2, range2.length, &isEqual, &order) == 0 /* noErr */)) { compResult = ((isEqual && !forcedOrdering) ? kCFCompareEqualTo : ((order < 0) ? kCFCompareLessThan : kCFCompareGreaterThan)); } else @@ -709,7 +709,7 @@ CF_PRIVATE CFComparisonResult _CFCompareStringsWithLocale(CFStringInlineBuffer * } } -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if ((NULL != collator) && (__CompareTextDefault(collator, options, characters1, range1.length, characters2, range2.length, &isEqual, &order) == 0 /* noErr */)) { if (isEqual) { if (forcedOrdering && (kCFCompareEqualTo == compResult) && (0 != order)) compResult = ((order < 0) ? kCFCompareLessThan : kCFCompareGreaterThan); @@ -753,7 +753,7 @@ CF_PRIVATE CFComparisonResult _CFCompareStringsWithLocale(CFStringInlineBuffer * if (buffer2Len > 0) CFAllocatorDeallocate(kCFAllocatorSystemDefault, buffer2); } -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (collator == threadCollator) { // do nothing, already cached } else { diff --git a/CoreFoundation/String.subproj/CFUniCharPropertyDatabase.S b/CoreFoundation/String.subproj/CFUniCharPropertyDatabase.S index d05e0dfad5..e2649f8c42 100644 --- a/CoreFoundation/String.subproj/CFUniCharPropertyDatabase.S +++ b/CoreFoundation/String.subproj/CFUniCharPropertyDatabase.S @@ -11,19 +11,30 @@ #if defined(__ELF__) .section .rodata +#elif defined(__wasm__) +.section .data.unichar_property_database,"",@ #endif .global _C_LABEL(__CFUniCharPropertyDatabase) _C_LABEL(__CFUniCharPropertyDatabase): .incbin CF_CHARACTERSET_UNICHAR_DB +#if defined(__wasm__) + .size _C_LABEL(__CFUniCharPropertyDatabase), . - _C_LABEL(__CFUniCharPropertyDatabase) +#endif .global _C_LABEL(__CFUniCharPropertyDatabaseEnd) _C_LABEL(__CFUniCharPropertyDatabaseEnd): .byte 0 +#if defined(__wasm__) + .size _C_LABEL(__CFUniCharPropertyDatabaseEnd), . - _C_LABEL(__CFUniCharPropertyDatabaseEnd) +#endif .global _C_LABEL(__CFUniCharPropertyDatabaseSize) _C_LABEL(__CFUniCharPropertyDatabaseSize): .int _C_LABEL(__CFUniCharPropertyDatabaseEnd) - _C_LABEL(__CFUniCharPropertyDatabase) +#if defined(__wasm__) + .size _C_LABEL(__CFUniCharPropertyDatabaseSize), . - _C_LABEL(__CFUniCharPropertyDatabaseSize) +#endif NO_EXEC_STACK_DIRECTIVE SAFESEH_REGISTRATION_DIRECTIVE diff --git a/CoreFoundation/String.subproj/CFUnicodeData.S b/CoreFoundation/String.subproj/CFUnicodeData.S index 9272ab01c2..4dc318c8a1 100644 --- a/CoreFoundation/String.subproj/CFUnicodeData.S +++ b/CoreFoundation/String.subproj/CFUnicodeData.S @@ -11,6 +11,8 @@ #if defined(__ELF__) .section .rodata +#elif defined(__wasm__) +.section .data.unicode_data,"",@ #endif #if defined(__BIG_ENDIAN__) @@ -29,14 +31,23 @@ _C_LABEL(__CFUnicodeDataBSize): .global _C_LABEL(__CFUnicodeDataL) _C_LABEL(__CFUnicodeDataL): .incbin CF_CHARACTERSET_UNICODE_DATA_L +#if defined(__wasm__) + .size _C_LABEL(__CFUnicodeDataL), . - _C_LABEL(__CFUnicodeDataL) +#endif .global _C_LABEL(__CFUnicodeDataLEnd) _C_LABEL(__CFUnicodeDataLEnd): .byte 0 +#if defined(__wasm__) + .size _C_LABEL(__CFUnicodeDataLEnd), . - _C_LABEL(__CFUnicodeDataLEnd) +#endif .global _C_LABEL(__CFUnicodeDataLSize) _C_LABEL(__CFUnicodeDataLSize): .int _C_LABEL(__CFUnicodeDataLEnd) - _C_LABEL(__CFUnicodeDataL) +#if defined(__wasm__) + .size _C_LABEL(__CFUnicodeDataLSize), . - _C_LABEL(__CFUnicodeDataLSize) +#endif #endif NO_EXEC_STACK_DIRECTIVE diff --git a/CoreFoundation/StringEncodings.subproj/CFPlatformConverters.c b/CoreFoundation/StringEncodings.subproj/CFPlatformConverters.c index 177e03757a..b4d81b091f 100644 --- a/CoreFoundation/StringEncodings.subproj/CFPlatformConverters.c +++ b/CoreFoundation/StringEncodings.subproj/CFPlatformConverters.c @@ -27,7 +27,7 @@ CF_INLINE bool __CFIsPlatformConverterAvailable(int encoding) { #endif } -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI static const CFStringEncodingConverter __CFICUBootstrap = { .toBytes.standard = NULL, @@ -65,7 +65,7 @@ CF_PRIVATE const CFStringEncodingConverter *__CFStringEncodingGetExternalConvert if (__CFIsPlatformConverterAvailable(encoding)) { return &__CFPlatformBootstrap; } else { -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (__CFStringEncodingGetICUName(encoding)) { return &__CFICUBootstrap; } diff --git a/CoreFoundation/StringEncodings.subproj/CFStringEncodingConverter.c b/CoreFoundation/StringEncodings.subproj/CFStringEncodingConverter.c index a3aca9bb5d..cb78b9c938 100644 --- a/CoreFoundation/StringEncodings.subproj/CFStringEncodingConverter.c +++ b/CoreFoundation/StringEncodings.subproj/CFStringEncodingConverter.c @@ -533,7 +533,7 @@ CF_INLINE _CFEncodingConverter *__CFEncodingConverterFromDefinition(const CFStri converter->toCanonicalUnicode = __CFToCanonicalUnicodeCheapMultiByteWrapper; break; -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI case kCFStringEncodingConverterICU: converter->toBytes = (_CFToBytesProc)__CFStringEncodingGetICUName(encoding); break; @@ -699,7 +699,7 @@ uint32_t CFStringEncodingUnicodeToBytes(uint32_t encoding, uint32_t flags, const } } -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (kCFStringEncodingConverterICU == converter->definition->encodingClass) return __CFStringEncodingICUToBytes((const char *)converter->toBytes, flags, characters, numChars, usedCharLen, bytes, maxByteLen, usedByteLen); #endif @@ -844,7 +844,7 @@ uint32_t CFStringEncodingBytesToUnicode(uint32_t encoding, uint32_t flags, const if (!converter) return kCFStringEncodingConverterUnavailable; -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (kCFStringEncodingConverterICU == converter->definition->encodingClass) return __CFStringEncodingICUToUnicode((const char *)converter->toBytes, flags, bytes, numBytes, usedByteLen, characters, maxCharLen, usedCharLen); #endif @@ -888,7 +888,7 @@ CF_PRIVATE CFIndex CFStringEncodingCharLengthForBytes(uint32_t encoding, uint32_ const _CFEncodingConverter *converter = __CFGetConverter(encoding); if (converter) { -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (kCFStringEncodingConverterICU == converter->definition->encodingClass) return __CFStringEncodingICUCharLength((const char *)converter->toBytes, flags, bytes, numBytes); #endif @@ -932,7 +932,7 @@ CF_PRIVATE CFIndex CFStringEncodingByteLengthForCharacters(uint32_t encoding, ui const _CFEncodingConverter *converter = __CFGetConverter(encoding); if (converter) { -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI if (kCFStringEncodingConverterICU == converter->definition->encodingClass) return __CFStringEncodingICUByteLength((const char *)converter->toBytes, flags, characters, numChars); #endif @@ -1017,7 +1017,7 @@ CF_PRIVATE const CFStringEncoding *CFStringEncodingListOfAvailableEncodings(void if (NULL == encodings) { CFStringEncoding *list = (CFStringEncoding *)__CFBuiltinEncodings; CFIndex numICUConverters = 0, numPlatformConverters = 0; -#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_WASI CFStringEncoding *icuConverters = __CFStringEncodingCreateICUEncodings(NULL, &numICUConverters); #else CFStringEncoding *icuConverters = NULL; diff --git a/CoreFoundation/URL.subproj/CFURL.c b/CoreFoundation/URL.subproj/CFURL.c index 9b2dc82be8..85adc844da 100644 --- a/CoreFoundation/URL.subproj/CFURL.c +++ b/CoreFoundation/URL.subproj/CFURL.c @@ -22,7 +22,7 @@ #include #include #include -#if TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD +#if TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI #if TARGET_OS_OSX #include #endif @@ -31,7 +31,7 @@ #include #if __has_include() #include -#else +#elif __has_include() #include #endif #include @@ -53,9 +53,7 @@ static CFStringRef WindowsPathToURLPath(CFStringRef path, CFAllocatorRef alloc, static CFStringRef POSIXPathToURLPath(CFStringRef path, CFAllocatorRef alloc, Boolean isDirectory, Boolean isAbsolute, Boolean *posixAndUrlPathsMatch) CF_RETURNS_RETAINED; static CFStringRef CreateStringFromFileSystemRepresentationByAddingPercentEscapes(CFAllocatorRef alloc, const UInt8 *bytes, CFIndex numBytes, Boolean isDirectory, Boolean isAbsolute, Boolean windowsPath, Boolean *addedPercentEncoding) CF_RETURNS_RETAINED; CFStringRef CFURLCreateStringWithFileSystemPath(CFAllocatorRef allocator, CFURLRef anURL, CFURLPathStyle fsType, Boolean resolveAgainstBase) CF_RETURNS_RETAINED; -#if !TARGET_OS_WASI CF_EXPORT CFURLRef _CFURLCreateCurrentDirectoryURL(CFAllocatorRef allocator) CF_RETURNS_RETAINED; -#endif #if TARGET_OS_MAC static Boolean _CFURLHasFileURLScheme(CFURLRef url, Boolean *hasScheme); #endif @@ -2189,13 +2187,11 @@ static CFURLRef _CFURLCreateWithFileSystemPath(CFAllocatorRef allocator, CFStrin // if fileSystemPath is an absolute path, ignore baseURL (if provided) baseURL = NULL; } -#if !TARGET_OS_WASI else if ( baseURL == NULL ) { // if fileSystemPath is a relative path and no baseURL is provided, use the current working directory baseURL = _CFURLCreateCurrentDirectoryURL(allocator); releaseBaseURL = true; } -#endif // override isDirectory if the path is to root if ( !isDirectory && (len == 1) && (CFStringGetCharacterAtIndex(urlString, 0) == '/') ) { @@ -2282,7 +2278,7 @@ static CFURLRef _CFURLCreateWithFileSystemRepresentation(CFAllocatorRef allocato #endif struct __CFURL *result = NULL; if (bufLen > 0) { -#if TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD +#if TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI Boolean isAbsolute = bufLen && (*buffer == '/'); Boolean addedPercentEncoding; Boolean releaseBaseURL = false; @@ -2292,14 +2288,12 @@ static CFURLRef _CFURLCreateWithFileSystemRepresentation(CFAllocatorRef allocato // if buffer contains an absolute path, ignore baseURL (if provided) baseURL = NULL; isFileReferencePath = _fileSystemRepresentationHasFileIDPrefix(buffer, bufLen); - } -#if !TARGET_OS_WASI - else if ( baseURL == NULL ) { + } else if ( baseURL == NULL ) { // if buffer contains a relative path and no baseURL is provided, use the current working directory baseURL = _CFURLCreateCurrentDirectoryURL(allocator); releaseBaseURL = true; } -#endif + CFStringRef urlString = CreateStringFromFileSystemRepresentationByAddingPercentEscapes(allocator, buffer, bufLen, isDirectory, isAbsolute, false /*windowsPath*/, &addedPercentEncoding); if ( urlString ) { // allocate the URL object with the appropriate number of ranges @@ -4367,7 +4361,6 @@ static CFStringRef _resolveFileSystemPaths(CFStringRef relativePath, CFStringRef return _resolvedPath(buf, buf + baseLen + relLen, pathDelimiter, false, true, alloc); } -#if !TARGET_OS_WASI CFURLRef _CFURLCreateCurrentDirectoryURL(CFAllocatorRef allocator) { CFURLRef url = NULL; // CFMaxPathSize is OK here since we're getting the path from the file system @@ -4377,7 +4370,6 @@ CFURLRef _CFURLCreateCurrentDirectoryURL(CFAllocatorRef allocator) { } return url; } -#endif CFURLRef CFURLCreateWithFileSystemPath(CFAllocatorRef allocator, CFStringRef filePath, CFURLPathStyle fsType, Boolean isDirectory) { CFURLRef result; diff --git a/CoreFoundation/URL.subproj/CFURLSessionInterface.c b/CoreFoundation/URL.subproj/CFURLSessionInterface.c index 32f09c4c37..6226a3f5ce 100644 --- a/CoreFoundation/URL.subproj/CFURLSessionInterface.c +++ b/CoreFoundation/URL.subproj/CFURLSessionInterface.c @@ -657,3 +657,22 @@ CFURLSessionSList *_Nullable CFURLSessionSListAppend(CFURLSessionSList *_Nullabl void CFURLSessionSListFreeAll(CFURLSessionSList *_Nullable list) { curl_slist_free_all((struct curl_slist *) list); } + +bool CFURLSessionCurlHostIsEqual(const char *_Nonnull url, const char *_Nonnull expectedHost) { +#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 62) + bool isEqual = false; + CURLU *h = curl_url(); + if (0 == curl_url_set(h, CURLUPART_URL, url, 0)) { + char *curlHost = NULL; + if (0 == curl_url_get(h, CURLUPART_HOST, &curlHost, 0)) { + isEqual = (strlen(curlHost) == strlen(expectedHost) && + strncmp(curlHost, expectedHost, strlen(curlHost)) == 0); + curl_free(curlHost); + } + curl_free(h); + } + return isEqual; +#else + return true; +#endif +} diff --git a/CoreFoundation/URL.subproj/CFURLSessionInterface.h b/CoreFoundation/URL.subproj/CFURLSessionInterface.h index 574250a88d..d760177041 100644 --- a/CoreFoundation/URL.subproj/CFURLSessionInterface.h +++ b/CoreFoundation/URL.subproj/CFURLSessionInterface.h @@ -642,6 +642,7 @@ typedef struct CFURLSessionSList CFURLSessionSList; CF_EXPORT CFURLSessionSList *_Nullable CFURLSessionSListAppend(CFURLSessionSList *_Nullable list, const char * _Nullable string); CF_EXPORT void CFURLSessionSListFreeAll(CFURLSessionSList *_Nullable list); +CF_EXPORT bool CFURLSessionCurlHostIsEqual(const char *_Nonnull url, const char *_Nonnull expectedHost); CF_EXTERN_C_END diff --git a/Darwin/Foundation-swiftoverlay/NSStringAPI.swift b/Darwin/Foundation-swiftoverlay/NSStringAPI.swift index fda631f7a2..a5e6457f22 100644 --- a/Darwin/Foundation-swiftoverlay/NSStringAPI.swift +++ b/Darwin/Foundation-swiftoverlay/NSStringAPI.swift @@ -208,14 +208,23 @@ extension String { /// - encoding: The encoding to use to interpret `bytes`. public init?(bytes: __shared S, encoding: Encoding) where S.Iterator.Element == UInt8 { - let byteArray = Array(bytes) - if encoding == .utf8, - let str = byteArray.withUnsafeBufferPointer({ String._tryFromUTF8($0) }) - { - self = str + if encoding == .utf8 { + if let str = bytes.withContiguousStorageIfAvailable({ String._tryFromUTF8($0) }) { + guard let str else { + return nil + } + self = str + } else { + let byteArray = Array(bytes) + guard let str = byteArray.withUnsafeBufferPointer({ String._tryFromUTF8($0) }) else { + return nil + } + self = str + } return } + let byteArray = Array(bytes) if let ns = NSString( bytes: byteArray, length: byteArray.count, encoding: encoding.rawValue) { self = String._unconditionallyBridgeFromObjectiveC(ns) diff --git a/Foundation.xcodeproj/project.pbxproj b/Foundation.xcodeproj/project.pbxproj index baaa84e7ed..e781b7afb2 100644 --- a/Foundation.xcodeproj/project.pbxproj +++ b/Foundation.xcodeproj/project.pbxproj @@ -3868,7 +3868,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -3924,7 +3924,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -3966,6 +3966,7 @@ "-DCF_BUILDING_CF", "-DDEPLOYMENT_RUNTIME_SWIFT", "-DDEPLOYMENT_ENABLE_LIBDISPATCH", + "-DSWIFT_CORELIBS_FOUNDATION_HAS_THREADS", "-DHAVE_STRUCT_TIMESPEC", "-I$(SRCROOT)/bootstrap/common/usr/include", "-I$(SRCROOT)/bootstrap/x86_64-apple-darwin/usr/include", @@ -4002,7 +4003,7 @@ r, r, ); - OTHER_SWIFT_FLAGS = "-DDEPLOYMENT_ENABLE_LIBDISPATCH -DDEPLOYMENT_RUNTIME_SWIFT"; + OTHER_SWIFT_FLAGS = "-DDEPLOYMENT_ENABLE_LIBDISPATCH -DDEPLOYMENT_RUNTIME_SWIFT -DSWIFT_CORELIBS_FOUNDATION_HAS_THREADS -Xcc -DSWIFT_CORELIBS_FOUNDATION_HAS_THREADS"; PRODUCT_BUNDLE_IDENTIFIER = org.swift.Foundation; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -4043,6 +4044,7 @@ "-DCF_BUILDING_CF", "-DDEPLOYMENT_RUNTIME_SWIFT", "-DDEPLOYMENT_ENABLE_LIBDISPATCH", + "-DSWIFT_CORELIBS_FOUNDATION_HAS_THREADS", "-DHAVE_STRUCT_TIMESPEC", "-I$(SRCROOT)/bootstrap/common/usr/include", "-I$(SRCROOT)/bootstrap/x86_64-apple-darwin/usr/include", @@ -4080,7 +4082,7 @@ r, r, ); - OTHER_SWIFT_FLAGS = "-DDEPLOYMENT_ENABLE_LIBDISPATCH -DDEPLOYMENT_RUNTIME_SWIFT"; + OTHER_SWIFT_FLAGS = "-DDEPLOYMENT_ENABLE_LIBDISPATCH -DDEPLOYMENT_RUNTIME_SWIFT -DSWIFT_CORELIBS_FOUNDATION_HAS_THREADS -Xcc -DSWIFT_CORELIBS_FOUNDATION_HAS_THREADS"; PRODUCT_BUNDLE_IDENTIFIER = org.swift.Foundation; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -4129,6 +4131,7 @@ "-DCF_CHARACTERSET_UNICODE_DATA_B=\\\\\"CoreFoundation/CharacterSets/CFUnicodeData-B.mapping\\\\\"", "-DCF_CHARACTERSET_UNICHAR_DB=\\\\\"CoreFoundation/CharacterSets/CFUniCharPropertyDatabase.data\\\\\"", "-DCF_CHARACTERSET_BITMAP=\\\\\"CoreFoundation/CharacterSets/CFCharacterSetBitmaps.bitmap\\\\\"", + "-DSWIFT_CORELIBS_FOUNDATION_HAS_THREADS", "-Wno-format-security", ); PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/CoreFoundation; @@ -4178,6 +4181,7 @@ "-DCF_CHARACTERSET_UNICODE_DATA_B=\\\\\"CoreFoundation/CharacterSets/CFUnicodeData-B.mapping\\\\\"", "-DCF_CHARACTERSET_UNICHAR_DB=\\\\\"CoreFoundation/CharacterSets/CFUniCharPropertyDatabase.data\\\\\"", "-DCF_CHARACTERSET_BITMAP=\\\\\"CoreFoundation/CharacterSets/CFCharacterSetBitmaps.bitmap\\\\\"", + "-DSWIFT_CORELIBS_FOUNDATION_HAS_THREADS", "-Wno-format-security", ); PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/CoreFoundation; @@ -4268,7 +4272,7 @@ "@loader_path/../../..", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_BUNDLE_IDENTIFIER = org.swift.xdgTestHelper; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; @@ -4299,7 +4303,7 @@ "@loader_path/../../..", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_BUNDLE_IDENTIFIER = org.swift.xdgTestHelper; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; diff --git a/Sources/BlocksRuntime/CMakeLists.txt b/Sources/BlocksRuntime/CMakeLists.txt index 057302dd43..671627e4ee 100644 --- a/Sources/BlocksRuntime/CMakeLists.txt +++ b/Sources/BlocksRuntime/CMakeLists.txt @@ -11,5 +11,5 @@ set_target_properties(BlocksRuntime PROPERTIES add_library(BlocksRuntime::BlocksRuntime ALIAS BlocksRuntime) install(TARGETS BlocksRuntime - ARCHIVE DESTINATION lib/swift$<$>:_static>/$ - LIBRARY DESTINATION lib/swift$<$>:_static>/$) + ARCHIVE DESTINATION lib/swift$<$>:_static>/${SWIFT_SYSTEM_NAME} + LIBRARY DESTINATION lib/swift$<$>:_static>/${SWIFT_SYSTEM_NAME}) diff --git a/Sources/BlocksRuntime/runtime.c b/Sources/BlocksRuntime/runtime.c index 1b7945b949..547d832e50 100644 --- a/Sources/BlocksRuntime/runtime.c +++ b/Sources/BlocksRuntime/runtime.c @@ -15,7 +15,7 @@ #if TARGET_OS_WIN32 #include #include -#else +#elif __has_include() #include #endif #if __has_include() @@ -268,7 +268,11 @@ void _Block_use_RR( void (*retain)(const void *), break; } #else +# if __has_include() _Block_destructInstance = dlsym(RTLD_DEFAULT, "objc_destructInstance"); +# else + _Block_destructInstance = _Block_destructInstance_default; +# endif #endif } diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt index ab3a1bef11..14ace7ad51 100644 --- a/Sources/CMakeLists.txt +++ b/Sources/CMakeLists.txt @@ -1,5 +1,9 @@ add_subdirectory(UUID) add_subdirectory(Foundation) -add_subdirectory(FoundationNetworking) +if(FOUNDATION_ENABLE_FOUNDATION_NETWORKING) + add_subdirectory(FoundationNetworking) +endif() add_subdirectory(FoundationXML) -add_subdirectory(Tools) +if(FOUNDATION_BUILD_TOOLS) + add_subdirectory(Tools) +endif() diff --git a/Sources/Foundation/CGFloat.swift b/Sources/Foundation/CGFloat.swift index 61276c8394..ffe3a6c6ff 100644 --- a/Sources/Foundation/CGFloat.swift +++ b/Sources/Foundation/CGFloat.swift @@ -8,7 +8,7 @@ // @frozen -public struct CGFloat { +public struct CGFloat: Sendable { #if arch(i386) || arch(arm) || arch(wasm32) /// The native type used to store the CGFloat, which is Float on /// 32-bit architectures and Double on 64-bit architectures. diff --git a/Sources/Foundation/CMakeLists.txt b/Sources/Foundation/CMakeLists.txt index fc093ce0c8..d7a999f9b8 100644 --- a/Sources/Foundation/CMakeLists.txt +++ b/Sources/Foundation/CMakeLists.txt @@ -150,6 +150,13 @@ add_library(Foundation WinSDK+Extensions.swift) target_compile_definitions(Foundation PRIVATE DEPLOYMENT_RUNTIME_SWIFT) +if(Threads_FOUND) + target_compile_definitions(Foundation PRIVATE + SWIFT_CORELIBS_FOUNDATION_HAS_THREADS) + target_compile_options(Foundation PRIVATE + "SHELL:-Xcc -DSWIFT_CORELIBS_FOUNDATION_HAS_THREADS") +endif() + target_compile_options(Foundation PUBLIC $<$:-enable-testing> "SHELL:-Xfrontend -disable-autolink-framework -Xfrontend CoreFoundation" @@ -164,6 +171,11 @@ target_link_libraries(Foundation uuid PUBLIC swiftDispatch) +if("${CMAKE_C_COMPILER_TARGET}" MATCHES ".*-musl[^-*]$") + target_link_libraries(Foundation + PUBLIC + fts) +endif() set_target_properties(Foundation PROPERTIES INSTALL_RPATH "$ORIGIN" BUILD_RPATH "$" @@ -213,6 +225,18 @@ elseif(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) target_link_options(Foundation PRIVATE "SHELL:-no-toolchain-stdlib-rpath") endif() +if(CMAKE_SYSTEM_NAME STREQUAL WASI) + target_compile_options(Foundation PRIVATE + "SHELL:-Xcc -D_WASI_EMULATED_MMAN + -Xcc -D_WASI_EMULATED_SIGNAL + -Xcc -D_WASI_EMULATED_PROCESS_CLOCKS + -Xcc -D_WASI_EMULATED_GETPID") + # Link wasi-libc emulation libraries. Other emulation libs are also used in stdlib + target_compile_options(Foundation + PRIVATE + "SHELL:-Xfrontend -public-autolink-library -Xfrontend wasi-emulated-getpid") +endif() + set_property(GLOBAL APPEND PROPERTY Foundation_EXPORTS Foundation) _install_target(Foundation) diff --git a/Sources/Foundation/Data.swift b/Sources/Foundation/Data.swift index 86585a3a86..9e5c9faf38 100644 --- a/Sources/Foundation/Data.swift +++ b/Sources/Foundation/Data.swift @@ -28,6 +28,13 @@ @usableFromInline let memset = Glibc.memset @usableFromInline let memcpy = Glibc.memcpy @usableFromInline let memcmp = Glibc.memcmp +#elseif canImport(Musl) +@usableFromInline let calloc = Musl.calloc +@usableFromInline let malloc = Musl.malloc +@usableFromInline let free = Musl.free +@usableFromInline let memset = Musl.memset +@usableFromInline let memcpy = Musl.memcpy +@usableFromInline let memcmp = Musl.memcmp #elseif canImport(WASILibc) @usableFromInline let calloc = WASILibc.calloc @usableFromInline let malloc = WASILibc.malloc @@ -48,6 +55,8 @@ internal func malloc_good_size(_ size: Int) -> Int { #if canImport(Glibc) import Glibc +#elseif canImport(Musl) +import Musl #elseif canImport(WASILibc) import WASILibc #endif @@ -2039,7 +2048,6 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl } } -#if !os(WASI) /// Initialize a `Data` with the contents of a `URL`. /// /// - parameter url: The `URL` to read. @@ -2052,7 +2060,6 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl return Data(bytes: d.bytes, count: d.length) } } -#endif /// Initialize a `Data` from a Base-64 encoded String using the given options. /// @@ -2316,7 +2323,6 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl } #endif -#if !os(WASI) /// Write the contents of the `Data` to a location. /// /// - parameter url: The location to write the data into. @@ -2337,7 +2343,6 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl #endif } } -#endif // MARK: - diff --git a/Sources/Foundation/DispatchData+DataProtocol.swift b/Sources/Foundation/DispatchData+DataProtocol.swift index 520e2351c4..f95353eb5f 100644 --- a/Sources/Foundation/DispatchData+DataProtocol.swift +++ b/Sources/Foundation/DispatchData+DataProtocol.swift @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// - +#if canImport(Dispatch) import Dispatch extension DispatchData : DataProtocol { @@ -54,3 +54,4 @@ extension DispatchData : DataProtocol { return regions } } +#endif diff --git a/Sources/Foundation/FileHandle.swift b/Sources/Foundation/FileHandle.swift index a538a2975e..72ab09a3f6 100644 --- a/Sources/Foundation/FileHandle.swift +++ b/Sources/Foundation/FileHandle.swift @@ -8,7 +8,9 @@ // @_implementationOnly import CoreFoundation +#if canImport(Dispatch) import Dispatch +#endif // FileHandle has a .read(upToCount:) method. Just invoking read() will cause an ambiguity warning. Use _read instead. // Same with close()/.close(). @@ -22,6 +24,16 @@ import Glibc fileprivate let _read = Glibc.read(_:_:_:) fileprivate let _write = Glibc.write(_:_:_:) fileprivate let _close = Glibc.close(_:) +#elseif canImport(Musl) +import Musl +fileprivate let _read = Musl.read(_:_:_:) +fileprivate let _write = Musl.write(_:_:_:) +fileprivate let _close = Musl.close(_:) +#elseif canImport(WASILibc) +import WASILibc +fileprivate let _read = WASILibc.read(_:_:_:) +fileprivate let _write = WASILibc.write(_:_:_:) +fileprivate let _close = WASILibc.close(_:) #endif #if canImport(WinSDK) @@ -79,6 +91,7 @@ open class FileHandle : NSObject { private var _closeOnDealloc: Bool +#if canImport(Dispatch) private var currentBackgroundActivityOwner: AnyObject? // Guarded by privateAsyncVariablesLock private var readabilitySource: DispatchSourceProtocol? // Guarded by privateAsyncVariablesLock @@ -202,6 +215,7 @@ open class FileHandle : NSObject { } } } +#endif // canImport(Dispatch) open var availableData: Data { _checkFileHandle() @@ -615,6 +629,7 @@ open class FileHandle : NSObject { } private func performOnQueueIfExists(_ block: () throws -> Void) throws { +#if canImport(Dispatch) if let queue = queueIfExists { var theError: Swift.Error? queue.sync { @@ -626,6 +641,9 @@ open class FileHandle : NSObject { } else { try block() } +#else + try block() +#endif } @available(swift 5.0) @@ -640,6 +658,7 @@ open class FileHandle : NSObject { guard self != FileHandle._nulldeviceFileHandle else { return } guard _isPlatformHandleValid else { return } + #if canImport(Dispatch) privateAsyncVariablesLock.lock() writabilitySource?.cancel() readabilitySource?.cancel() @@ -648,6 +667,7 @@ open class FileHandle : NSObject { writabilitySource = nil readabilitySource = nil privateAsyncVariablesLock.unlock() + #endif #if os(Windows) // SR-13822 - Not Closing the file descriptor on Windows causes a Stack Overflow @@ -850,6 +870,9 @@ extension FileHandle { } open func readInBackgroundAndNotify(forModes modes: [RunLoop.Mode]?) { +#if !canImport(Dispatch) + NSUnsupported() +#else _checkFileHandle() privateAsyncVariablesLock.lock() @@ -904,6 +927,7 @@ extension FileHandle { operation(data, error) } #endif +#endif // canImport(Dispatch) } open func readToEndOfFileInBackgroundAndNotify() { @@ -911,6 +935,9 @@ extension FileHandle { } open func readToEndOfFileInBackgroundAndNotify(forModes modes: [RunLoop.Mode]?) { +#if !canImport(Dispatch) || !canImport(Dispatch) + NSUnsupported() +#else privateAsyncVariablesLock.lock() guard currentBackgroundActivityOwner == nil else { fatalError("No two activities can occur at the same time") } @@ -952,11 +979,12 @@ extension FileHandle { NotificationQueue.default.enqueue(Notification(name: .NSFileHandleReadToEndOfFileCompletion, object: self, userInfo: userInfo), postingStyle: .asap, coalesceMask: .none, forModes: modes) } } +#endif } @available(Windows, unavailable, message: "A SOCKET cannot be treated as a fd") open func acceptConnectionInBackgroundAndNotify() { -#if os(Windows) +#if os(Windows) || !canImport(Dispatch) NSUnsupported() #else acceptConnectionInBackgroundAndNotify(forModes: [.default]) @@ -965,7 +993,7 @@ extension FileHandle { @available(Windows, unavailable, message: "A SOCKET cannot be treated as a fd") open func acceptConnectionInBackgroundAndNotify(forModes modes: [RunLoop.Mode]?) { -#if os(Windows) +#if os(Windows) || !canImport(Dispatch) NSUnsupported() #else let owner = monitor(forReading: true, resumed: false) { (handle, source) in @@ -1003,6 +1031,9 @@ extension FileHandle { } open func waitForDataInBackgroundAndNotify(forModes modes: [RunLoop.Mode]?) { +#if !canImport(Dispatch) + NSUnsupported() +#else let owner = monitor(forReading: true, resumed: false) { (handle, source) in source.cancel() DispatchQueue.main.async { @@ -1020,6 +1051,7 @@ extension FileHandle { privateAsyncVariablesLock.unlock() owner.resume() +#endif } } @@ -1041,6 +1073,8 @@ open class Pipe: NSObject { closeOnDealloc: true) self.fileHandleForWriting = FileHandle(handle: hWritePipe!, closeOnDealloc: true) +#elseif os(WASI) + NSUnsupported() #else /// the `pipe` system call creates two `fd` in a malloc'ed area let fds = UnsafeMutablePointer.allocate(capacity: 2) @@ -1067,4 +1101,3 @@ open class Pipe: NSObject { super.init() } } - diff --git a/Sources/Foundation/FileManager+POSIX.swift b/Sources/Foundation/FileManager+POSIX.swift index d90ece91e6..73d8171832 100644 --- a/Sources/Foundation/FileManager+POSIX.swift +++ b/Sources/Foundation/FileManager+POSIX.swift @@ -13,6 +13,18 @@ internal func &(left: UInt32, right: mode_t) -> mode_t { } #endif +#if os(WASI) +import WASILibc +// wasi-libc defines the following constants in a way that Clang Importer can't +// understand, so we need to grab them manually through ForSwiftFoundationOnly.h +internal var DT_DIR: UInt8 { _getConst_DT_DIR() } +internal var O_CREAT: Int32 { _getConst_O_CREAT() } +internal var O_DIRECTORY: Int32 { _getConst_O_DIRECTORY() } +internal var O_EXCL: Int32 { _getConst_O_EXCL() } +internal var O_TRUNC: Int32 { _getConst_O_TRUNC() } +internal var O_WRONLY: Int32 { _getConst_O_WRONLY() } +#endif + @_implementationOnly import CoreFoundation extension FileManager { @@ -96,6 +108,32 @@ extension FileManager { return nil } urls = mountPoints(statBuf, Int(fsCount)) +#elseif os(WASI) + // Skip the first three file descriptors, which are reserved for stdin, stdout, and stderr. + var fd: __wasi_fd_t = 3 + let __WASI_PREOPENTYPE_DIR: UInt8 = 0 + while true { + var prestat = __wasi_prestat_t() + guard __wasi_fd_prestat_get(fd, &prestat) == 0 else { + break + } + + if prestat.tag == __WASI_PREOPENTYPE_DIR { + var buf = [UInt8](repeating: 0, count: Int(prestat.u.dir.pr_name_len)) + guard __wasi_fd_prestat_dir_name(fd, &buf, prestat.u.dir.pr_name_len) == 0 else { + break + } + let path = buf.withUnsafeBufferPointer { buf in + guard let baseAddress = buf.baseAddress else { + return "" + } + let base = UnsafeRawPointer(baseAddress).assumingMemoryBound(to: Int8.self) + return string(withFileSystemRepresentation: base, length: buf.count) + } + urls.append(URL(fileURLWithPath: path, isDirectory: true)) + } + fd += 1 + } #else #error("Requires a platform-specific implementation") #endif @@ -411,10 +449,8 @@ extension FileManager { errno = 0 while let entry = readdir(dir) { let length = Int(_direntNameLength(entry)) - let entryName = withUnsafePointer(to: entry.pointee.d_name) { (ptr) -> String in - let namePtr = UnsafeRawPointer(ptr).assumingMemoryBound(to: CChar.self) - return string(withFileSystemRepresentation: namePtr, length: length) - } + let namePtr = UnsafeRawPointer(_direntName(entry)).assumingMemoryBound(to: CChar.self) + let entryName = string(withFileSystemRepresentation: namePtr, length: length) if entryName != "." && entryName != ".." { let entryType = Int32(entry.pointee.d_type) try closure(entryName, entryType) @@ -446,6 +482,10 @@ extension FileManager { } internal func _attributesOfFileSystemIncludingBlockSize(forPath path: String) throws -> (attributes: [FileAttributeKey : Any], blockSize: UInt64?) { + #if os(WASI) + // WASI doesn't have statvfs + throw _NSErrorWithErrno(ENOTSUP, reading: true, path: path) + #else var result: [FileAttributeKey:Any] = [:] var finalBlockSize: UInt64? @@ -478,6 +518,7 @@ extension FileManager { finalBlockSize = blockSize } return (attributes: result, blockSize: finalBlockSize) + #endif // os(WASI) } internal func _createSymbolicLink(atPath path: String, withDestinationPath destPath: String) throws { @@ -507,6 +548,11 @@ extension FileManager { } internal func _recursiveDestinationOfSymbolicLink(atPath path: String) throws -> String { + #if os(WASI) + // TODO: Remove this guard when realpath implementation will be released + // See https://github.com/WebAssembly/wasi-libc/pull/473 + throw _NSErrorWithErrno(ENOTSUP, reading: true, path: path) + #else // Throw error if path is not a symbolic link: let path = try _destinationOfSymbolicLink(atPath: path) @@ -520,10 +566,16 @@ extension FileManager { } return String(cString: resolvedPath) + #endif } /* Returns a String with a canonicalized path for the element at the specified path. */ internal func _canonicalizedPath(toFileAtPath path: String) throws -> String { + #if os(WASI) + // TODO: Remove this guard when realpath implementation will be released + // See https://github.com/WebAssembly/wasi-libc/pull/473 + throw _NSErrorWithErrno(ENOTSUP, reading: true, path: path) + #else let bufSize = Int(PATH_MAX + 1) var buf = [Int8](repeating: 0, count: bufSize) let done = try _fileSystemRepresentation(withPath: path) { @@ -534,6 +586,7 @@ extension FileManager { } return self.string(withFileSystemRepresentation: buf, length: strlen(buf)) + #endif } internal func _readFrom(fd: Int32, toBuffer buffer: UnsafeMutablePointer, length bytesToRead: Int, filename: String) throws -> Int { @@ -591,12 +644,14 @@ extension FileManager { } defer { close(dstfd) } + #if !os(WASI) // WASI doesn't have ownership concept // Set the file permissions using fchmod() instead of when open()ing to avoid umask() issues let permissions = fileInfo.st_mode & ~S_IFMT guard fchmod(dstfd, permissions) == 0 else { throw _NSErrorWithErrno(errno, reading: false, path: dstPath, extraUserInfo: extraErrorInfo(srcPath: srcPath, dstPath: dstPath, userVariant: variant)) } + #endif if fileInfo.st_size == 0 { // no copying required @@ -741,6 +796,10 @@ extension FileManager { if rmdir(fsRep) == 0 { return } else if errno == ENOTEMPTY { + #if os(WASI) + // wasi-libc, which is based on musl, does not provide fts(3) + throw _NSErrorWithErrno(ENOTSUP, reading: false, path: path) + #else let ps = UnsafeMutablePointer?>.allocate(capacity: 2) ps.initialize(to: UnsafeMutablePointer(mutating: fsRep)) ps.advanced(by: 1).initialize(to: nil) @@ -783,6 +842,7 @@ extension FileManager { } else { let _ = _NSErrorWithErrno(ENOTEMPTY, reading: false, path: path) } + #endif } else if errno != ENOTDIR { throw _NSErrorWithErrno(errno, reading: false, path: path) } else if unlink(fsRep) != 0 { @@ -885,6 +945,7 @@ extension FileManager { return false } + #if !os(WASI) // WASI doesn't have ownership concept // Stat the parent directory, if that fails, return false. let parentS = try _lstatFile(atPath: path, withFileSystemRepresentation: parentFsRep) @@ -895,6 +956,7 @@ extension FileManager { // If the current user owns the file, return true. return s.st_uid == getuid() } + #endif // Return true as the best guess. return true @@ -1065,6 +1127,26 @@ extension FileManager { return temp._bridgeToObjectiveC().appendingPathComponent(dest) } + #if os(WASI) + // For platforms that don't support FTS, we just throw an error for now. + // TODO: Provide readdir(2) based implementation here or FTS in wasi-libc? + internal class NSURLDirectoryEnumerator : DirectoryEnumerator { + var _url : URL + var _errorHandler : ((URL, Error) -> Bool)? + + init(url: URL, options: FileManager.DirectoryEnumerationOptions, errorHandler: ((URL, Error) -> Bool)?) { + _url = url + _errorHandler = errorHandler + } + + override func nextObject() -> Any? { + if let handler = _errorHandler { + _ = handler(_url, _NSErrorWithErrno(ENOTSUP, reading: true, url: _url)) + } + return nil + } + } + #else internal class NSURLDirectoryEnumerator : DirectoryEnumerator { var _url : URL var _options : FileManager.DirectoryEnumerationOptions @@ -1198,6 +1280,7 @@ extension FileManager { return nil } } + #endif internal func _updateTimes(atPath path: String, withFileSystemRepresentation fsr: UnsafePointer, creationTime: Date? = nil, accessTime: Date? = nil, modificationTime: Date? = nil) throws { let stat = try _lstatFile(atPath: path, withFileSystemRepresentation: fsr) diff --git a/Sources/Foundation/FileManager+Win32.swift b/Sources/Foundation/FileManager+Win32.swift index ac0e96257e..35103f378b 100644 --- a/Sources/Foundation/FileManager+Win32.swift +++ b/Sources/Foundation/FileManager+Win32.swift @@ -620,7 +620,7 @@ extension FileManager { // case, we need to do a recursive copy & remove. if PathIsSameRootW(wszSource, wszDestination) || faSourceAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == 0 { - if !MoveFileExW(wszSource, wszDestination, DWORD(MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH)) { + if !MoveFileExW(wszSource, wszDestination, MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH) { throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [srcPath, dstPath]) } } else { diff --git a/Sources/Foundation/FileManager.swift b/Sources/Foundation/FileManager.swift index 1aa3038a01..fdd8411511 100644 --- a/Sources/Foundation/FileManager.swift +++ b/Sources/Foundation/FileManager.swift @@ -21,6 +21,10 @@ import CRT import WinSDK #endif +#if os(WASI) +import WASILibc +#endif + #if os(Windows) internal typealias NativeFSRCharType = WCHAR internal let NativeFSREncoding = String.Encoding.utf16LittleEndian.rawValue @@ -384,6 +388,10 @@ open class FileManager : NSObject { switch attribute { case .posixPermissions: +#if os(WASI) + // WASI does not have permission concept + throw _NSErrorWithErrno(ENOTSUP, reading: false, path: path) +#else guard let number = attributeValues[attribute] as? NSNumber else { fatalError("Can't set file permissions to \(attributeValues[attribute] as Any?)") } @@ -400,6 +408,7 @@ open class FileManager : NSObject { guard result == 0 else { throw _NSErrorWithErrno(errno, reading: false, path: path) } +#endif // os(WASI) case .modificationDate: fallthrough case ._accessDate: @@ -567,6 +576,8 @@ open class FileManager : NSObject { result[.deviceIdentifier] = NSNumber(value: UInt64(s.st_rdev)) let attributes = try windowsFileAttributes(atPath: path) let type = FileAttributeType(attributes: attributes, atPath: path) +#elseif os(WASI) + let type = FileAttributeType(statMode: mode_t(s.st_mode)) #else if let pwd = getpwuid(s.st_uid), pwd.pointee.pw_name != nil { let name = String(cString: pwd.pointee.pw_name) diff --git a/Sources/Foundation/Host.swift b/Sources/Foundation/Host.swift index 5fe7b29c5b..b5205ebb76 100644 --- a/Sources/Foundation/Host.swift +++ b/Sources/Foundation/Host.swift @@ -91,6 +91,8 @@ open class Host: NSObject { return "localhost" } return String(cString: hostname) +#elseif os(WASI) // WASI does not have uname + return "localhost" #else let hname = UnsafeMutablePointer.allocate(capacity: Int(NI_MAXHOST)) defer { @@ -170,6 +172,9 @@ open class Host: NSObject { } _names = [info] _resolved = true +#elseif os(WASI) // WASI does not have getifaddrs + _names = [info] + _resolved = true #else var ifaddr: UnsafeMutablePointer? = nil if getifaddrs(&ifaddr) != 0 { @@ -267,6 +272,11 @@ open class Host: NSObject { _resolved = true } +#elseif os(WASI) // WASI does not have getaddrinfo + if let info = _info { + _names = [info] + _resolved = true + } #else if let info = _info { var flags: Int32 = 0 @@ -281,7 +291,7 @@ open class Host: NSObject { } var hints = addrinfo() hints.ai_family = PF_UNSPEC -#if os(macOS) || os(iOS) || os(Android) || os(OpenBSD) +#if os(macOS) || os(iOS) || os(Android) || os(OpenBSD) || canImport(Musl) hints.ai_socktype = SOCK_STREAM #else hints.ai_socktype = Int32(SOCK_STREAM.rawValue) diff --git a/Sources/Foundation/JSONEncoder.swift b/Sources/Foundation/JSONEncoder.swift index 4e38456503..df26ca3dca 100644 --- a/Sources/Foundation/JSONEncoder.swift +++ b/Sources/Foundation/JSONEncoder.swift @@ -1011,7 +1011,7 @@ extension JSONValue { bytes.append(._closebracket) case .object(let dict): if #available(macOS 10.13, *), options.contains(.sortedKeys) { - let sorted = dict.sorted { $0.key < $1.key } + let sorted = dict.sorted { $0.key.compare($1.key, options: [.caseInsensitive, .diacriticInsensitive, .forcedOrdering, .numeric, .widthInsensitive]) == .orderedAscending } self.writeObject(sorted, into: &bytes) } else { self.writeObject(dict, into: &bytes) @@ -1073,7 +1073,7 @@ extension JSONValue { bytes.append(._closebracket) case .object(let dict): if #available(macOS 10.13, *), options.contains(.sortedKeys) { - let sorted = dict.sorted { $0.key < $1.key } + let sorted = dict.sorted { $0.key.compare($1.key, options: [.caseInsensitive, .diacriticInsensitive, .forcedOrdering, .numeric, .widthInsensitive]) == .orderedAscending } self.writePrettyObject(sorted, into: &bytes, depth: depth) } else { self.writePrettyObject(dict, into: &bytes, depth: depth) diff --git a/Sources/Foundation/NSCharacterSet.swift b/Sources/Foundation/NSCharacterSet.swift index 0148771bbe..b1491b340f 100644 --- a/Sources/Foundation/NSCharacterSet.swift +++ b/Sources/Foundation/NSCharacterSet.swift @@ -184,7 +184,6 @@ open class NSCharacterSet : NSObject, NSCopying, NSMutableCopying, NSSecureCodin _CFCharacterSetInitWithBitmapRepresentation(_cfMutableObject, data._cfObject) } -#if !os(WASI) public convenience init?(contentsOfFile fName: String) { do { let data = try Data(contentsOf: URL(fileURLWithPath: fName)) @@ -330,7 +329,6 @@ open class NSCharacterSet : NSObject, NSCopying, NSMutableCopying, NSSecureCodin aCoder.encode(true, forKey: .characterSetIsInvertedKey) } } -#endif open func characterIsMember(_ aCharacter: unichar) -> Bool { return longCharacterIsMember(UInt32(aCharacter)) diff --git a/Sources/Foundation/NSData.swift b/Sources/Foundation/NSData.swift index ed9e7f0529..aaeeb9aeca 100644 --- a/Sources/Foundation/NSData.swift +++ b/Sources/Foundation/NSData.swift @@ -151,7 +151,6 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { _init(bytes: bytes, length: length, copy: false, deallocator: deallocator) } -#if !os(WASI) /// Initializes a data object with the contents of the file at a given path. public init(contentsOfFile path: String, options readOptionsMask: ReadingOptions = []) throws { super.init() @@ -174,7 +173,6 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { return nil } } -#endif /// Initializes a data object with the contents of another data object. public init(data: Data) { @@ -184,7 +182,6 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { } } -#if !os(WASI) /// Initializes a data object with the data from the location specified by a given URL. public init(contentsOf url: URL, options readOptionsMask: ReadingOptions = []) throws { super.init() @@ -223,7 +220,6 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { return try _NSNonfileURLContentLoader.current.contentsOf(url: url) } } -#endif /// Initializes a data object with the given Base64 encoded string. public init?(base64Encoded base64String: String, options: Base64DecodingOptions = []) { @@ -439,7 +435,6 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { } } -#if !os(WASI) internal static func readBytesFromFileWithExtendedAttributes(_ path: String, options: ReadingOptions) throws -> NSDataReadResult { guard let handle = FileHandle(path: path, flags: O_RDONLY, createMode: 0) else { throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: nil) @@ -494,8 +489,12 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { let createMode = Int(ucrt.S_IREAD) | Int(ucrt.S_IWRITE) #elseif canImport(Darwin) let createMode = Int(S_IRUSR) | Int(S_IWUSR) | Int(S_IRGRP) | Int(S_IWGRP) | Int(S_IROTH) | Int(S_IWOTH) -#else +#elseif canImport(Glibc) let createMode = Int(Glibc.S_IRUSR) | Int(Glibc.S_IWUSR) | Int(Glibc.S_IRGRP) | Int(Glibc.S_IWGRP) | Int(Glibc.S_IROTH) | Int(Glibc.S_IWOTH) +#elseif canImport(Musl) + 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) #endif guard let fh = FileHandle(path: path, flags: flags, createMode: createMode) else { throw _NSErrorWithErrno(errno, reading: false, path: path) @@ -543,7 +542,6 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { } try write(toFile: url.path, options: writeOptionsMask) } -#endif // MARK: - Bytes /// Copies a number of bytes from the start of the data object into a given buffer. @@ -1010,7 +1008,6 @@ open class NSMutableData : NSData { super.init(data: data) } -#if !os(WASI) public override init?(contentsOfFile path: String) { super.init(contentsOfFile: path) } @@ -1026,7 +1023,6 @@ open class NSMutableData : NSData { public override init(contentsOf url: URL, options: NSData.ReadingOptions = []) throws { try super.init(contentsOf: url, options: options) } -#endif public override init?(base64Encoded base64Data: Data, options: NSData.Base64DecodingOptions = []) { super.init(base64Encoded: base64Data, options: options) diff --git a/Sources/Foundation/NSError.swift b/Sources/Foundation/NSError.swift index 3ec150e63b..fc87a4d648 100644 --- a/Sources/Foundation/NSError.swift +++ b/Sources/Foundation/NSError.swift @@ -1038,7 +1038,7 @@ extension POSIXError { /// Bad address. public static var EFAULT: POSIXError.Code { return .EFAULT } - #if !os(Windows) + #if !os(Windows) && !os(WASI) /// Block device required. public static var ENOTBLK: POSIXError.Code { return .ENOTBLK } #endif @@ -1141,9 +1141,11 @@ extension POSIXError { /// Protocol not supported. public static var EPROTONOSUPPORT: POSIXError.Code { return .EPROTONOSUPPORT } + #if !os(WASI) /// Socket type not supported. public static var ESOCKTNOSUPPORT: POSIXError.Code { return .ESOCKTNOSUPPORT } #endif + #endif #if canImport(Darwin) /// Operation not supported. @@ -1151,8 +1153,10 @@ extension POSIXError { #endif #if !os(Windows) + #if !os(WASI) /// Protocol family not supported. public static var EPFNOSUPPORT: POSIXError.Code { return .EPFNOSUPPORT } + #endif /// Address family not supported by protocol family. public static var EAFNOSUPPORT: POSIXError.Code { return .EAFNOSUPPORT } @@ -1191,11 +1195,13 @@ extension POSIXError { /// Socket is not connected. public static var ENOTCONN: POSIXError.Code { return .ENOTCONN } + #if !os(WASI) /// Can't send after socket shutdown. public static var ESHUTDOWN: POSIXError.Code { return .ESHUTDOWN } /// Too many references: can't splice. public static var ETOOMANYREFS: POSIXError.Code { return .ETOOMANYREFS } + #endif /// Operation timed out. public static var ETIMEDOUT: POSIXError.Code { return .ETIMEDOUT } @@ -1211,8 +1217,10 @@ extension POSIXError { public static var ENAMETOOLONG: POSIXError.Code { return .ENAMETOOLONG } #if !os(Windows) + #if !os(WASI) /// Host is down. public static var EHOSTDOWN: POSIXError.Code { return .EHOSTDOWN } + #endif /// No route to host. public static var EHOSTUNREACH: POSIXError.Code { return .EHOSTUNREACH } @@ -1229,8 +1237,10 @@ extension POSIXError { #endif #if !os(Windows) + #if !os(WASI) /// Too many users. public static var EUSERS: POSIXError.Code { return .EUSERS } + #endif /// Disk quota exceeded. public static var EDQUOT: POSIXError.Code { return .EDQUOT } @@ -1238,7 +1248,7 @@ extension POSIXError { /// Network File System - #if !os(Windows) + #if !os(Windows) && !os(WASI) /// Stale NFS file handle. public static var ESTALE: POSIXError.Code { return .ESTALE } @@ -1346,23 +1356,27 @@ extension POSIXError { /// Reserved. public static var EMULTIHOP: POSIXError.Code { return .EMULTIHOP } + #if !os(WASI) /// No message available on STREAM. public static var ENODATA: POSIXError.Code { return .ENODATA } + #endif /// Reserved. public static var ENOLINK: POSIXError.Code { return .ENOLINK } + #if !os(WASI) /// No STREAM resources. public static var ENOSR: POSIXError.Code { return .ENOSR } /// Not a STREAM. public static var ENOSTR: POSIXError.Code { return .ENOSTR } #endif + #endif /// Protocol error. public static var EPROTO: POSIXError.Code { return .EPROTO } - #if !os(OpenBSD) + #if !os(OpenBSD) && !os(WASI) /// STREAM ioctl timeout. public static var ETIME: POSIXError.Code { return .ETIME } #endif diff --git a/Sources/Foundation/NSGeometry.swift b/Sources/Foundation/NSGeometry.swift index 88fc9797d7..be58ff0330 100644 --- a/Sources/Foundation/NSGeometry.swift +++ b/Sources/Foundation/NSGeometry.swift @@ -7,7 +7,7 @@ // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // -public struct CGPoint { +public struct CGPoint: Sendable { public var x: CGFloat public var y: CGFloat public init() { @@ -100,7 +100,7 @@ extension CGPoint : Codable { } } -public struct CGSize { +public struct CGSize: Sendable { public var width: CGFloat public var height: CGFloat public init() { @@ -193,7 +193,7 @@ extension CGSize : Codable { } } -public struct CGRect { +public struct CGRect: Sendable { public var origin: CGPoint public var size: CGSize public init() { @@ -501,7 +501,7 @@ extension CGRect: NSSpecialValueCoding { } } -public enum NSRectEdge : UInt { +public enum NSRectEdge : UInt, Sendable { case minX case minY @@ -509,7 +509,7 @@ public enum NSRectEdge : UInt { case maxY } -public enum CGRectEdge : UInt32 { +public enum CGRectEdge : UInt32, Sendable { case minXEdge case minYEdge @@ -529,7 +529,7 @@ extension NSRectEdge { } -public struct NSEdgeInsets { +public struct NSEdgeInsets: Sendable { public var top: CGFloat public var left: CGFloat public var bottom: CGFloat @@ -604,7 +604,7 @@ extension NSEdgeInsets: NSSpecialValueCoding { } } -public struct AlignmentOptions : OptionSet { +public struct AlignmentOptions : OptionSet, Sendable { public var rawValue : UInt64 public init(rawValue: UInt64) { self.rawValue = rawValue } diff --git a/Sources/Foundation/NSKeyedArchiver.swift b/Sources/Foundation/NSKeyedArchiver.swift index 8433b13869..c09c682222 100644 --- a/Sources/Foundation/NSKeyedArchiver.swift +++ b/Sources/Foundation/NSKeyedArchiver.swift @@ -150,10 +150,6 @@ open class NSKeyedArchiver : NSCoder { /// - Returns: `true` if the operation was successful, otherwise `false`. @available(swift, deprecated: 9999, renamed: "archivedData(withRootObject:requiringSecureCoding:)") open class func archiveRootObject(_ rootObject: Any, toFile path: String) -> Bool { -#if os(WASI) - assertionFailure("\(#function) does not support file access on WASI") - return false -#else var fd : Int32 = -1 var auxFilePath : String var finishedEncoding : Bool = false @@ -187,7 +183,6 @@ open class NSKeyedArchiver : NSCoder { finishedEncoding = keyedArchiver._flags.contains(.finishedEncoding) return finishedEncoding -#endif } public convenience init(requiringSecureCoding: Bool) { @@ -228,13 +223,8 @@ open class NSKeyedArchiver : NSCoder { success = true } } else { -#if !os(WASI) let stream = unsafeBitCast(self._stream, to: CFWriteStream.self) success = CFPropertyListWrite(plist, stream, kCFPropertyListXMLFormat_v1_0, 0, nil) > 0 -#else - assertionFailure("\(#function) only supports data streams on WASI") - return false -#endif } return success diff --git a/Sources/Foundation/NSLock.swift b/Sources/Foundation/NSLock.swift index 59d334f1ad..0513bfd96e 100644 --- a/Sources/Foundation/NSLock.swift +++ b/Sources/Foundation/NSLock.swift @@ -22,6 +22,19 @@ public protocol NSLocking { func unlock() } +extension NSLocking { + @_alwaysEmitIntoClient + @_disfavoredOverload + public func withLock(_ body: () throws -> R) rethrows -> R { + self.lock() + defer { + self.unlock() + } + + return try body() + } +} + #if os(Windows) private typealias _MutexPointer = UnsafeMutablePointer private typealias _RecursiveMutexPointer = UnsafeMutablePointer @@ -44,7 +57,9 @@ open class NSLock: NSObject, NSLocking { #endif public override init() { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) InitializeSRWLock(mutex) InitializeConditionVariable(timeoutCond) InitializeSRWLock(timeoutMutex) @@ -58,7 +73,9 @@ open class NSLock: NSObject, NSLocking { } deinit { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) // SRWLocks do not need to be explicitly destroyed #else pthread_mutex_destroy(mutex) @@ -71,7 +88,9 @@ open class NSLock: NSObject, NSLocking { } open func lock() { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) AcquireSRWLockExclusive(mutex) #else pthread_mutex_lock(mutex) @@ -79,7 +98,9 @@ open class NSLock: NSObject, NSLocking { } open func unlock() { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) ReleaseSRWLockExclusive(mutex) AcquireSRWLockExclusive(timeoutMutex) WakeAllConditionVariable(timeoutCond) @@ -96,7 +117,10 @@ open class NSLock: NSObject, NSLocking { } open func `try`() -> Bool { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms + return true +#elseif os(Windows) return TryAcquireSRWLockExclusive(mutex) != 0 #else return pthread_mutex_trylock(mutex) == 0 @@ -104,7 +128,9 @@ open class NSLock: NSObject, NSLocking { } open func lock(before limit: Date) -> Bool { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) if TryAcquireSRWLockExclusive(mutex) != 0 { return true } @@ -114,17 +140,16 @@ open class NSLock: NSObject, NSLocking { } #endif -#if os(macOS) || os(iOS) || os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms + return true +#elseif os(macOS) || os(iOS) || os(Windows) return timedLock(mutex: mutex, endTime: limit, using: timeoutCond, with: timeoutMutex) #else guard var endTime = timeSpecFrom(date: limit) else { return false } -#if os(WASI) - return true -#else return pthread_mutex_timedlock(mutex, &endTime) == 0 -#endif #endif } @@ -139,7 +164,7 @@ extension NSLock { } } -#if !os(WASI) +#if SWIFT_CORELIBS_FOUNDATION_HAS_THREADS open class NSConditionLock : NSObject, NSLocking { internal var _cond = NSCondition() internal var _value: Int @@ -243,7 +268,9 @@ open class NSRecursiveLock: NSObject, NSLocking { public override init() { super.init() -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) InitializeCriticalSection(mutex) InitializeConditionVariable(timeoutCond) InitializeSRWLock(timeoutMutex) @@ -271,7 +298,9 @@ open class NSRecursiveLock: NSObject, NSLocking { } deinit { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) DeleteCriticalSection(mutex) #else pthread_mutex_destroy(mutex) @@ -284,7 +313,9 @@ open class NSRecursiveLock: NSObject, NSLocking { } open func lock() { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) EnterCriticalSection(mutex) #else pthread_mutex_lock(mutex) @@ -292,7 +323,9 @@ open class NSRecursiveLock: NSObject, NSLocking { } open func unlock() { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) LeaveCriticalSection(mutex) AcquireSRWLockExclusive(timeoutMutex) WakeAllConditionVariable(timeoutCond) @@ -309,7 +342,10 @@ open class NSRecursiveLock: NSObject, NSLocking { } open func `try`() -> Bool { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms + return true +#elseif os(Windows) return TryEnterCriticalSection(mutex) #else return pthread_mutex_trylock(mutex) == 0 @@ -317,7 +353,9 @@ open class NSRecursiveLock: NSObject, NSLocking { } open func lock(before limit: Date) -> Bool { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) if TryEnterCriticalSection(mutex) { return true } @@ -327,17 +365,16 @@ open class NSRecursiveLock: NSObject, NSLocking { } #endif -#if os(macOS) || os(iOS) || os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms + return true +#elseif os(macOS) || os(iOS) || os(Windows) return timedLock(mutex: mutex, endTime: limit, using: timeoutCond, with: timeoutMutex) #else guard var endTime = timeSpecFrom(date: limit) else { return false } -#if os(WASI) - return true -#else return pthread_mutex_timedlock(mutex, &endTime) == 0 -#endif #endif } @@ -349,7 +386,9 @@ open class NSCondition: NSObject, NSLocking { internal var cond = _ConditionVariablePointer.allocate(capacity: 1) public override init() { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) InitializeSRWLock(mutex) InitializeConditionVariable(cond) #else @@ -359,7 +398,9 @@ open class NSCondition: NSObject, NSLocking { } deinit { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) // SRWLock do not need to be explicitly destroyed #else pthread_mutex_destroy(mutex) @@ -372,7 +413,9 @@ open class NSCondition: NSObject, NSLocking { } open func lock() { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) AcquireSRWLockExclusive(mutex) #else pthread_mutex_lock(mutex) @@ -380,7 +423,9 @@ open class NSCondition: NSObject, NSLocking { } open func unlock() { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) ReleaseSRWLockExclusive(mutex) #else pthread_mutex_unlock(mutex) @@ -388,7 +433,9 @@ open class NSCondition: NSObject, NSLocking { } open func wait() { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) SleepConditionVariableSRW(cond, mutex, WinSDK.INFINITE, 0) #else pthread_cond_wait(cond, mutex) @@ -396,7 +443,10 @@ open class NSCondition: NSObject, NSLocking { } open func wait(until limit: Date) -> Bool { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms + return true +#elseif os(Windows) return SleepConditionVariableSRW(cond, mutex, timeoutFrom(date: limit), 0) #else guard var timeout = timeSpecFrom(date: limit) else { @@ -407,7 +457,9 @@ open class NSCondition: NSObject, NSLocking { } open func signal() { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) WakeConditionVariable(cond) #else pthread_cond_signal(cond) @@ -415,7 +467,9 @@ open class NSCondition: NSObject, NSLocking { } open func broadcast() { -#if os(Windows) +#if !SWIFT_CORELIBS_FOUNDATION_HAS_THREADS + // noop on no thread platforms +#elseif os(Windows) WakeAllConditionVariable(cond) #else pthread_cond_broadcast(cond) diff --git a/Sources/Foundation/NSNotification.swift b/Sources/Foundation/NSNotification.swift index 15b2e78f13..ff25a3b136 100644 --- a/Sources/Foundation/NSNotification.swift +++ b/Sources/Foundation/NSNotification.swift @@ -8,7 +8,7 @@ // open class NSNotification: NSObject, NSCopying, NSCoding { - public struct Name : RawRepresentable, Equatable, Hashable { + public struct Name : RawRepresentable, Equatable, Hashable, Sendable { public private(set) var rawValue: String public init(_ rawValue: String) { @@ -82,6 +82,8 @@ open class NSNotification: NSObject, NSCopying, NSCoding { } } +#if canImport(Dispatch) + private class NSNotificationReceiver : NSObject { fileprivate var name: Notification.Name? fileprivate var block: ((Notification) -> Void)? @@ -191,3 +193,5 @@ open class NotificationCenter: NSObject { } } + +#endif // canImport(Dispatch) diff --git a/Sources/Foundation/NSObjCRuntime.swift b/Sources/Foundation/NSObjCRuntime.swift index bc388d4031..c82adfda9f 100644 --- a/Sources/Foundation/NSObjCRuntime.swift +++ b/Sources/Foundation/NSObjCRuntime.swift @@ -264,7 +264,6 @@ internal let _NSClassesRenamedByObjCAPINotes: [(class: AnyClass, objCName: Strin (ProcessInfo.self, "NSProcessInfo"), (Port.self, "NSPort"), (PortMessage.self, "NSPortMessage"), - (SocketPort.self, "NSSocketPort"), (Bundle.self, "NSBundle"), (ByteCountFormatter.self, "NSByteCountFormatter"), (Host.self, "NSHost"), @@ -279,20 +278,13 @@ internal let _NSClassesRenamedByObjCAPINotes: [(class: AnyClass, objCName: Strin (JSONSerialization.self, "NSJSONSerialization"), (LengthFormatter.self, "NSLengthFormatter"), (MassFormatter.self, "NSMassFormatter"), - (NotificationQueue.self, "NSNotificationQueue"), (NumberFormatter.self, "NSNumberFormatter"), - (Operation.self, "NSOperation"), - (OperationQueue.self, "NSOperationQueue"), (OutputStream.self, "NSOutputStream"), (PersonNameComponentsFormatter.self, "NSPersonNameComponentsFormatter"), (Pipe.self, "NSPipe"), - (Progress.self, "NSProgress"), (PropertyListSerialization.self, "NSPropertyListSerialization"), - (RunLoop.self, "NSRunLoop"), (Scanner.self, "NSScanner"), (Stream.self, "NSStream"), - (Thread.self, "NSThread"), - (Timer.self, "NSTimer"), (UserDefaults.self, "NSUserDefaults"), (FileManager.DirectoryEnumerator.self, "NSDirectoryEnumerator"), (Dimension.self, "NSDimension"), @@ -322,8 +314,20 @@ internal let _NSClassesRenamedByObjCAPINotes: [(class: AnyClass, objCName: Strin (UnitVolume.self, "NSUnitVolume"), (UnitTemperature.self, "NSUnitTemperature"), ] -#if !(os(iOS) || os(Android)) +#if !(os(iOS) || os(Android) || os(WASI)) map.append((Process.self, "NSTask")) +#endif +#if !os(WASI) + map += [ + (NotificationQueue.self, "NSNotificationQueue"), + (Operation.self, "NSOperation"), + (OperationQueue.self, "NSOperationQueue"), + (SocketPort.self, "NSSocketPort"), + (Progress.self, "NSProgress"), + (RunLoop.self, "NSRunLoop"), + (Thread.self, "NSThread"), + (Timer.self, "NSTimer"), + ] #endif return map }() diff --git a/Sources/Foundation/NSPathUtilities.swift b/Sources/Foundation/NSPathUtilities.swift index beba8d86eb..91e7ccba44 100644 --- a/Sources/Foundation/NSPathUtilities.swift +++ b/Sources/Foundation/NSPathUtilities.swift @@ -10,6 +10,15 @@ @_implementationOnly import CoreFoundation #if os(Windows) import WinSDK +#elseif os(WASI) +import WASILibc +// CoreFoundation brings but it conflicts with WASILibc.errno +// definition, so we need to explicitly select the one from WASILibc. +// This is defined as "internal" since this workaround also used in other files. +internal var errno: Int32 { + get { WASILibc.errno } + set { WASILibc.errno = newValue } +} #endif #if os(Windows) @@ -66,11 +75,9 @@ public func NSTemporaryDirectory() -> String { } } #endif -#if !os(WASI) if let tmpdir = ProcessInfo.processInfo.environment["TMPDIR"] { return normalizedPath(with: tmpdir) } -#endif #if os(Android) // Bionic uses /data/local/tmp/ as temporary directory. TMPDIR is rarely // defined. @@ -195,7 +202,6 @@ extension String { return temp } -#if !os(WASI) internal func _tryToRemovePathPrefix(_ prefix: String) -> String? { guard self != prefix else { return nil @@ -208,7 +214,6 @@ extension String { return nil } -#endif } extension NSString { @@ -338,7 +343,6 @@ extension NSString { return result._stringByFixingSlashes() } -#if !os(WASI) public var expandingTildeInPath: String { guard hasPrefix("~") else { return _swiftObject @@ -359,7 +363,6 @@ extension NSString { return result } -#endif #if os(Windows) public var unixPath: String { @@ -374,7 +377,6 @@ extension NSString { } #endif -#if !os(WASI) public var standardizingPath: String { #if os(Windows) let expanded = unixPath.expandingTildeInPath @@ -422,8 +424,6 @@ extension NSString { return resolvedPath } -#endif - public func stringsByAppendingPaths(_ paths: [String]) -> [String] { if self == "" { return paths @@ -431,7 +431,6 @@ extension NSString { return paths.map(appendingPathComponent) } -#if !os(WASI) /// - Experiment: This is a draft API currently under consideration for official import into Foundation /// - Note: Since this API is under consideration it may be either removed or revised in the near future public func completePath(into outputName: inout String?, caseSensitive flag: Bool, matchesInto outputArray: inout [String], filterTypes: [String]?) -> Int { @@ -534,7 +533,6 @@ extension NSString { return { $0.lowercased().hasPrefix(prefix) } } } -#endif internal func _longestCommonPrefix(_ strings: [String], caseSensitive: Bool) -> String? { guard !strings.isEmpty else { @@ -582,11 +580,9 @@ extension NSString { return path + "/" } -#if !os(WASI) public var fileSystemRepresentation: UnsafePointer { return FileManager.default.fileSystemRepresentation(withPath: self._swiftObject) } -#endif public func getFileSystemRepresentation(_ cname: UnsafeMutablePointer, maxLength max: Int) -> Bool { #if os(Windows) @@ -655,7 +651,6 @@ extension NSString { } -#if !os(WASI) extension FileManager { public enum SearchPathDirectory: UInt { @@ -731,6 +726,9 @@ public func NSHomeDirectory() -> String { } public func NSHomeDirectoryForUser(_ user: String?) -> String? { +#if os(WASI) // WASI does not have user concept + return nil +#else let userName = user?._cfObject guard let homeDir = CFCopyHomeDirectoryURLForUser(userName)?.takeRetainedValue() else { return nil @@ -738,6 +736,7 @@ public func NSHomeDirectoryForUser(_ user: String?) -> String? { let url: URL = homeDir._swiftObject return url.path +#endif } public func NSUserName() -> String { @@ -770,6 +769,10 @@ internal func _NSCreateTemporaryFile(_ filePath: String) throws -> (Int32, Strin } // Don't close h, fd is transferred ownership let fd = _open_osfhandle(intptr_t(bitPattern: h), 0) + return (fd, pathResult) +#elseif os(WASI) + // WASI does not have temp directories + throw NSError(domain: NSPOSIXErrorDomain, code: Int(ENOTSUP)) #else var template = URL(fileURLWithPath: filePath) @@ -805,15 +808,16 @@ internal func _NSCreateTemporaryFile(_ filePath: String) throws -> (Int32, Strin close(fd) throw _NSErrorWithErrno(_errno, reading: false, path: pathResult) } -#endif return (fd, pathResult) +#endif } internal func _NSCleanupTemporaryFile(_ auxFilePath: String, _ filePath: String) throws { #if os(Windows) try withNTPathRepresentation(of: auxFilePath) { pwszSource in try withNTPathRepresentation(of: filePath) { pwszDestination in - guard CopyFileW(pwszSource, pwszDestination, false) else { + guard MoveFileExW(pwszSource, pwszDestination, + MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) else { let dwErrorCode = GetLastError() try? FileManager.default.removeItem(atPath: auxFilePath) throw _NSErrorWithWindowsError(dwErrorCode, reading: false) @@ -830,4 +834,3 @@ internal func _NSCleanupTemporaryFile(_ auxFilePath: String, _ filePath: String) }) #endif } -#endif diff --git a/Sources/Foundation/NSString.swift b/Sources/Foundation/NSString.swift index d81b20b571..d35c0b02ae 100644 --- a/Sources/Foundation/NSString.swift +++ b/Sources/Foundation/NSString.swift @@ -25,11 +25,7 @@ func NSLocalizedString(_ key: String, bundle: Bundle = Bundle.main, value: String = "", comment: String) -> String { -#if os(WASI) - return key -#else return bundle.localizedString(forKey: key, value: value, table: tableName) -#endif } internal let kCFStringEncodingMacRoman = CFStringBuiltInEncodings.macRoman.rawValue diff --git a/Sources/Foundation/NSStringAPI.swift b/Sources/Foundation/NSStringAPI.swift index 0a7c475eed..efd7b38c39 100644 --- a/Sources/Foundation/NSStringAPI.swift +++ b/Sources/Foundation/NSStringAPI.swift @@ -256,14 +256,23 @@ extension String { /// - encoding: The encoding to use to interpret `bytes`. public init?(bytes: __shared S, encoding: Encoding) where S.Iterator.Element == UInt8 { - let byteArray = Array(bytes) - if encoding == .utf8, - let str = byteArray.withUnsafeBufferPointer({ String._tryFromUTF8($0) }) - { - self = str + if encoding == .utf8 { + if let str = bytes.withContiguousStorageIfAvailable({ String._tryFromUTF8($0) }) { + guard let str else { + return nil + } + self = str + } else { + let byteArray = Array(bytes) + guard let str = byteArray.withUnsafeBufferPointer({ String._tryFromUTF8($0) }) else { + return nil + } + self = str + } return } + let byteArray = Array(bytes) if let ns = NSString( bytes: byteArray, length: byteArray.count, encoding: encoding.rawValue) { self = String._unconditionallyBridgeFromObjectiveC(ns) diff --git a/Sources/Foundation/NSSwiftRuntime.swift b/Sources/Foundation/NSSwiftRuntime.swift index 04958446d7..c079ed6259 100644 --- a/Sources/Foundation/NSSwiftRuntime.swift +++ b/Sources/Foundation/NSSwiftRuntime.swift @@ -14,8 +14,10 @@ // This mimics the behavior of the swift sdk overlay on Darwin #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) @_exported import Darwin -#elseif os(Linux) || os(Android) || CYGWIN || os(OpenBSD) +#elseif canImport(Glibc) @_exported import Glibc +#elseif canImport(Musl) +@_exported import Musl #elseif os(WASI) @_exported import WASILibc #elseif os(Windows) diff --git a/Sources/Foundation/NSURL.swift b/Sources/Foundation/NSURL.swift index 9b121d6681..4d31e2ba9c 100644 --- a/Sources/Foundation/NSURL.swift +++ b/Sources/Foundation/NSURL.swift @@ -20,6 +20,8 @@ internal let kCFURLWindowsPathStyle = CFURLPathStyle.cfurlWindowsPathStyle import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Musl) +import Musl #endif // NOTE: this represents PLATFORM_PATH_STYLE @@ -554,9 +556,6 @@ open class NSURL : NSObject, NSSecureCoding, NSCopying { // TODO: should be `checkResourceIsReachableAndReturnError` with autoreleased error parameter. // Currently Autoreleased pointers is not supported on Linux. open func checkResourceIsReachable() throws -> Bool { -#if os(WASI) - return false -#else guard isFileURL, let path = path else { throw NSError(domain: NSCocoaErrorDomain, @@ -572,7 +571,6 @@ open class NSURL : NSObject, NSSecureCoding, NSCopying { } return true -#endif } /* Returns a file path URL that refers to the same resource as a specified URL. File path URLs use a file system style path. An error will occur if the url parameter is not a file URL. A file reference URL's resource must exist and be reachable to be converted to a file path URL. Symbol is present in iOS 4, but performs no operation. @@ -916,12 +914,8 @@ extension NSURL { if selfPath.isAbsolutePath { absolutePath = selfPath } else { -#if os(WASI) - return nil -#else let workingDir = FileManager.default.currentDirectoryPath absolutePath = workingDir._bridgeToObjectiveC().appendingPathComponent(selfPath) -#endif } #if os(Windows) @@ -969,20 +963,16 @@ extension NSURL { default: resolvedPath = resolvedPath._bridgeToObjectiveC().appendingPathComponent(component) -#if !os(WASI) if let destination = FileManager.default._tryToResolveTrailingSymlinkInPath(resolvedPath) { resolvedPath = destination } -#endif } } // It might be a responsibility of NSURL(fileURLWithPath:). Check it. var isExistingDirectory: ObjCBool = false -#if !os(WASI) let _ = FileManager.default.fileExists(atPath: resolvedPath, isDirectory: &isExistingDirectory) -#endif if excludeSystemDirs { resolvedPath = resolvedPath._tryToRemovePathPrefix("/private") ?? resolvedPath @@ -1061,7 +1051,6 @@ extension NSURL : _StructTypeBridgeable { // ----- -#if !os(WASI) internal func _CFSwiftURLCopyResourcePropertyForKey(_ url: CFTypeRef, _ key: CFString, _ valuePointer: UnsafeMutablePointer?>?, _ errorPointer: UnsafeMutablePointer?>?) -> _DarwinCompatibleBoolean { do { let key = URLResourceKey(rawValue: key._swiftObject) @@ -1595,7 +1584,6 @@ fileprivate extension URLResourceValuesStorage { } } } -#endif // ----- diff --git a/Sources/Foundation/NotificationQueue.swift b/Sources/Foundation/NotificationQueue.swift index a6cc935eec..bf3e5d8e39 100644 --- a/Sources/Foundation/NotificationQueue.swift +++ b/Sources/Foundation/NotificationQueue.swift @@ -7,6 +7,7 @@ // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // +#if canImport(Dispatch) @_implementationOnly import CoreFoundation extension NotificationQueue { @@ -176,3 +177,5 @@ open class NotificationQueue: NSObject { } } + +#endif diff --git a/Sources/Foundation/Operation.swift b/Sources/Foundation/Operation.swift index 0945253be1..2f8fc54d4e 100644 --- a/Sources/Foundation/Operation.swift +++ b/Sources/Foundation/Operation.swift @@ -7,6 +7,7 @@ // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // +#if canImport(Dispatch) import Dispatch internal let _NSOperationIsFinished = "isFinished" @@ -1438,3 +1439,4 @@ extension OperationQueue { } } } +#endif diff --git a/Sources/Foundation/Port.swift b/Sources/Foundation/Port.swift index c481f96613..c53263f0ef 100644 --- a/Sources/Foundation/Port.swift +++ b/Sources/Foundation/Port.swift @@ -83,6 +83,13 @@ public protocol PortDelegate: AnyObject { func handle(_ message: PortMessage) } +#if os(WASI) + +@available(*, unavailable, message: "SocketPort is not available on this platform.") +open class SocketPort: Port {} + +#else + #if canImport(Glibc) && !os(Android) && !os(OpenBSD) import Glibc fileprivate let SOCK_STREAM = Int32(Glibc.SOCK_STREAM.rawValue) @@ -1106,3 +1113,5 @@ fileprivate extension Data { return self[...self.index(self.startIndex, offsetBy: range.upperBound)] } } + +#endif diff --git a/Sources/Foundation/Process.swift b/Sources/Foundation/Process.swift index 542cc94cf1..0f32045e49 100644 --- a/Sources/Foundation/Process.swift +++ b/Sources/Foundation/Process.swift @@ -7,6 +7,7 @@ // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // +#if canImport(Dispatch) @_implementationOnly import CoreFoundation #if os(Windows) import WinSDK @@ -776,7 +777,7 @@ open class Process: NSObject { } var taskSocketPair : [Int32] = [0, 0] -#if os(macOS) || os(iOS) || os(Android) || os(OpenBSD) +#if os(macOS) || os(iOS) || os(Android) || os(OpenBSD) || canImport(Musl) socketpair(AF_UNIX, SOCK_STREAM, 0, &taskSocketPair) #else socketpair(AF_UNIX, Int32(SOCK_STREAM.rawValue), 0, &taskSocketPair) @@ -1174,3 +1175,5 @@ extension Process { public static let didTerminateNotification = NSNotification.Name(rawValue: "NSTaskDidTerminateNotification") } + +#endif diff --git a/Sources/Foundation/Progress.swift b/Sources/Foundation/Progress.swift index 11b96ca7a5..efa278899f 100644 --- a/Sources/Foundation/Progress.swift +++ b/Sources/Foundation/Progress.swift @@ -7,6 +7,7 @@ // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // +#if canImport(Dispatch) import Dispatch /** @@ -545,3 +546,4 @@ fileprivate class _ProgressTSD : NSObject { childAttached = false } } +#endif diff --git a/Sources/Foundation/RunLoop.swift b/Sources/Foundation/RunLoop.swift index 5ad595e6ef..9323346f4b 100644 --- a/Sources/Foundation/RunLoop.swift +++ b/Sources/Foundation/RunLoop.swift @@ -51,6 +51,24 @@ extension RunLoop.Mode { } } +#if !canImport(Dispatch) + +open class RunLoop: NSObject { + @available(*, unavailable, message: "RunLoop is not available on WASI") + open class var current: RunLoop { + fatalError("RunLoop is not available on WASI") + } + + @available(*, unavailable, message: "RunLoop is not available on WASI") + open class var main: RunLoop { + fatalError("RunLoop is not available on WASI") + } + + internal final var currentCFRunLoop: CFRunLoop { NSUnsupported() } +} + +#else + internal func _NSRunLoopNew(_ cf: CFRunLoop) -> Unmanaged { let rl = Unmanaged.passRetained(RunLoop(cfObject: cf)) return unsafeBitCast(rl, to: Unmanaged.self) // this retain is balanced on the other side of the CF fence @@ -421,3 +439,5 @@ extension RunLoop._Source { unsafeBitCast(_cfSourceStorage, to: CFRunLoopSource.self) } } + +#endif // canImport(Dispatch) diff --git a/Sources/Foundation/ScannerAPI.swift b/Sources/Foundation/ScannerAPI.swift index d3fe75edfa..500b2f1d92 100644 --- a/Sources/Foundation/ScannerAPI.swift +++ b/Sources/Foundation/ScannerAPI.swift @@ -43,7 +43,7 @@ extension Scanner { if let value = scanInt64(representation: representation) { return Int(value) } - #elseif arch(i386) || arch(arm) + #elseif arch(i386) || arch(arm) || arch(wasm32) if let value = scanInt32(representation: representation) { return Int(value) } diff --git a/Sources/Foundation/Thread.swift b/Sources/Foundation/Thread.swift index 7734cf738d..166a5d3fe5 100644 --- a/Sources/Foundation/Thread.swift +++ b/Sources/Foundation/Thread.swift @@ -7,6 +7,7 @@ // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // +#if canImport(Dispatch) @_implementationOnly import CoreFoundation #if os(Windows) import WinSDK @@ -14,6 +15,8 @@ import WinSDK #if canImport(Glibc) import Glibc +#elseif canImport(Musl) +import Musl #endif // WORKAROUND_SR9811 @@ -356,13 +359,15 @@ open class Thread : NSObject { _cancelled = true } + // ###TODO: Switch these over to using the Swift runtime's backtracer + // once we have Windows support there. private class func backtraceAddresses(_ body: (UnsafeMutablePointer, Int) -> [T]) -> [T] { // Same as swift/stdlib/public/runtime/Errors.cpp backtrace let maxSupportedStackDepth = 128; let addrs = UnsafeMutablePointer.allocate(capacity: maxSupportedStackDepth) defer { addrs.deallocate() } -#if os(Android) || os(OpenBSD) +#if os(Android) || os(OpenBSD) || canImport(Musl) let count = 0 #elseif os(Windows) let count = RtlCaptureStackBackTrace(0, DWORD(maxSupportedStackDepth), @@ -383,7 +388,7 @@ open class Thread : NSObject { } open class var callStackSymbols: [String] { -#if os(Android) || os(OpenBSD) +#if os(Android) || os(OpenBSD) || canImport(Musl) return [] #elseif os(Windows) let hProcess: HANDLE = GetCurrentProcess() @@ -444,3 +449,4 @@ extension NSNotification.Name { public static let NSDidBecomeSingleThreaded = NSNotification.Name(rawValue: "NSDidBecomeSingleThreadedNotification") public static let NSThreadWillExit = NSNotification.Name(rawValue: "NSThreadWillExitNotification") } +#endif diff --git a/Sources/Foundation/UserDefaults.swift b/Sources/Foundation/UserDefaults.swift index fda2a9a912..23f035b6d6 100644 --- a/Sources/Foundation/UserDefaults.swift +++ b/Sources/Foundation/UserDefaults.swift @@ -406,7 +406,9 @@ open class UserDefaults: NSObject { _ = defaults.synchronize() +#if canImport(Dispatch) NotificationCenter.default.post(name: UserDefaults.didChangeNotification, object: self) +#endif } } @@ -418,7 +420,9 @@ open class UserDefaults: NSObject { _ = defaults.synchronize() +#if canImport(Dispatch) NotificationCenter.default.post(name: UserDefaults.didChangeNotification, object: self) +#endif } } diff --git a/Sources/Foundation/WinSDK+Extensions.swift b/Sources/Foundation/WinSDK+Extensions.swift index 65c904f181..1a4ab4136d 100644 --- a/Sources/Foundation/WinSDK+Extensions.swift +++ b/Sources/Foundation/WinSDK+Extensions.swift @@ -57,6 +57,18 @@ internal var GENERIC_WRITE: DWORD { DWORD(WinSDK.GENERIC_WRITE) } +internal var MOVEFILE_COPY_ALLOWED: DWORD { + DWORD(WinSDK.MOVEFILE_COPY_ALLOWED) +} + +internal var MOVEFILE_REPLACE_EXISTING: DWORD { + DWORD(WinSDK.MOVEFILE_REPLACE_EXISTING) +} + +internal var MOVEFILE_WRITE_THROUGH: DWORD { + DWORD(WinSDK.MOVEFILE_WRITE_THROUGH) +} + internal var OPEN_EXISTING: DWORD { DWORD(WinSDK.OPEN_EXISTING) } diff --git a/Sources/FoundationNetworking/CMakeLists.txt b/Sources/FoundationNetworking/CMakeLists.txt index 1a8f516e98..183013cc82 100644 --- a/Sources/FoundationNetworking/CMakeLists.txt +++ b/Sources/FoundationNetworking/CMakeLists.txt @@ -72,6 +72,14 @@ if(NOT BUILD_SHARED_LIBS) PRIVATE "SHELL:-Xfrontend -public-autolink-library -Xfrontend curl") + if(BUILD_FULLY_STATIC) + target_compile_options(FoundationNetworking + PRIVATE + "SHELL:-Xfrontend -public-autolink-library -Xfrontend crypto" + "SHELL:-Xfrontend -public-autolink-library -Xfrontend ssl" + "SHELL:-Xfrontend -public-autolink-library -Xfrontend z") + endif() + # Merge private dependencies into single static objects archive set_property(TARGET FoundationNetworking PROPERTY STATIC_LIBRARY_OPTIONS $) diff --git a/Sources/FoundationNetworking/URLSession/FTP/FTPURLProtocol.swift b/Sources/FoundationNetworking/URLSession/FTP/FTPURLProtocol.swift index 8f87e884cf..55583fd2b8 100644 --- a/Sources/FoundationNetworking/URLSession/FTP/FTPURLProtocol.swift +++ b/Sources/FoundationNetworking/URLSession/FTP/FTPURLProtocol.swift @@ -56,7 +56,21 @@ internal class _FTPURLProtocol: _NativeProtocol { easyHandle.set(debugOutputOn: enableLibcurlDebugOutput, task: task!) easyHandle.set(skipAllSignalHandling: true) guard let url = request.url else { fatalError("No URL in request.") } - easyHandle.set(url: url) + guard url.host != nil else { + self.internalState = .transferFailed + let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL, + userInfo: [NSLocalizedDescriptionKey: "FTP URL must have a host"]) + failWith(error: error, request: request) + return + } + do { + try easyHandle.set(url: url) + } catch { + self.internalState = .transferFailed + let nsError = error as? NSError ?? NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL) + failWith(error: nsError, request: request) + return + } easyHandle.set(preferredReceiveBufferSize: Int.max) do { switch (body, try body.getBodyLength()) { diff --git a/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift b/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift index 9695be004e..abf6623435 100644 --- a/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift +++ b/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift @@ -311,7 +311,21 @@ internal class _HTTPURLProtocol: _NativeProtocol { guard let url = request.url else { fatalError("No URL in request.") } - easyHandle.set(url: url) + guard url.host != nil else { + self.internalState = .transferFailed + let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL, + userInfo: [NSLocalizedDescriptionKey: "HTTP URL must have a host"]) + failWith(error: error, request: request) + return + } + do { + try easyHandle.set(url: url) + } catch { + self.internalState = .transferFailed + let nsError = error as? NSError ?? NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL) + failWith(error: nsError, request: request) + return + } let session = task?.session as! URLSession let _config = session._configuration easyHandle.set(sessionConfig: _config) diff --git a/Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift b/Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift index d6e50554ac..4513cdb701 100644 --- a/Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift +++ b/Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift @@ -165,10 +165,16 @@ extension _EasyHandle { } /// URL to use in the request /// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_URL.html - func set(url: URL) { + func set(url: URL) throws { _url = url - url.absoluteString.withCString { - try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionURL, UnsafeMutablePointer(mutating: $0)).asError() + try url.absoluteString.withCString { urlPtr in + try url.host?.withCString { hostPtr in + guard CFURLSessionCurlHostIsEqual(urlPtr, hostPtr) else { + throw NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL, + userInfo: [NSLocalizedDescriptionKey: "URLSession and curl did not agree on URL host"]) + } + } + try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionURL, UnsafeMutablePointer(mutating: urlPtr)).asError() } } diff --git a/Sources/FoundationXML/CMakeLists.txt b/Sources/FoundationXML/CMakeLists.txt index 944ea25875..a09d059417 100644 --- a/Sources/FoundationXML/CMakeLists.txt +++ b/Sources/FoundationXML/CMakeLists.txt @@ -23,6 +23,12 @@ if(NOT BUILD_SHARED_LIBS) PRIVATE "SHELL:-Xfrontend -public-autolink-library -Xfrontend xml2") + if(BUILD_FULLY_STATIC) + target_compile_options(FoundationXML + PRIVATE + "SHELL:-Xfrontend -public-autolink-library -Xfrontend z") + endif() + # Merge private dependencies into single static objects archive set_property(TARGET FoundationXML PROPERTY STATIC_LIBRARY_OPTIONS $) @@ -37,6 +43,12 @@ if(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin|Windows") target_link_options(FoundationXML PRIVATE "SHELL:-no-toolchain-stdlib-rpath") endif() +if(CMAKE_SYSTEM_NAME STREQUAL WASI) + target_compile_options(FoundationXML PRIVATE + "SHELL:-Xcc -D_WASI_EMULATED_SIGNAL + -Xcc -D_WASI_EMULATED_PROCESS_CLOCKS + -Xcc -D_WASI_EMULATED_MMAN") +endif() set_property(GLOBAL APPEND PROPERTY Foundation_EXPORTS FoundationXML) _install_target(FoundationXML) diff --git a/Sources/Tools/plutil/CMakeLists.txt b/Sources/Tools/plutil/CMakeLists.txt index b1c843506a..30ff29bb0c 100644 --- a/Sources/Tools/plutil/CMakeLists.txt +++ b/Sources/Tools/plutil/CMakeLists.txt @@ -28,7 +28,7 @@ if(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin|Windows") endif() set_target_properties(plutil PROPERTIES - INSTALL_RPATH "$ORIGIN/../lib/swift/$") + INSTALL_RPATH "$ORIGIN/../lib/swift/${SWIFT_SYSTEM_NAME}") set_property(GLOBAL APPEND PROPERTY Foundation_EXPORTS plutil) diff --git a/Sources/Tools/plutil/main.swift b/Sources/Tools/plutil/main.swift index c9ee783f84..d71d9ba9a2 100644 --- a/Sources/Tools/plutil/main.swift +++ b/Sources/Tools/plutil/main.swift @@ -12,6 +12,9 @@ import SwiftFoundation #elseif canImport(Glibc) import Foundation import Glibc +#elseif canImport(Musl) +import Foundation +import Musl #elseif canImport(CRT) import Foundation import CRT diff --git a/Sources/UUID/CMakeLists.txt b/Sources/UUID/CMakeLists.txt index fea52c7396..bab43b0f01 100644 --- a/Sources/UUID/CMakeLists.txt +++ b/Sources/UUID/CMakeLists.txt @@ -28,7 +28,7 @@ if(NOT BUILD_SHARED_LIBS) # TODO(drexin): should be installed in architecture specific folder, once # the layout is fixed for non-Darwin platforms install(TARGETS uuid - ARCHIVE DESTINATION lib/swift_static/$ - LIBRARY DESTINATION lib/swift_static/$ + ARCHIVE DESTINATION lib/swift_static/${SWIFT_SYSTEM_NAME} + LIBRARY DESTINATION lib/swift_static/${SWIFT_SYSTEM_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() diff --git a/Tests/Foundation/Tests/TestJSONEncoder.swift b/Tests/Foundation/Tests/TestJSONEncoder.swift index ab74ac4a7f..b208e4f188 100644 --- a/Tests/Foundation/Tests/TestJSONEncoder.swift +++ b/Tests/Foundation/Tests/TestJSONEncoder.swift @@ -235,27 +235,73 @@ class TestJSONEncoder : XCTestCase { """) } - func test_encodingOutputFormattingSortedKeys() { - let expectedJSON = "{\"email\":\"appleseed@apple.com\",\"name\":\"Johnny Appleseed\"}".data(using: .utf8)! - let person = Person.testValue + func test_encodingOutputFormattingSortedKeys() throws { + let expectedJSON = try XCTUnwrap(""" + {"2":"2","7":"7","25":"25","alice":"alice","bob":"bob","Charlie":"Charlie","中国":"中国","日本":"日本","韓国":"韓国"} + """.data(using: .utf8)) + let testValue = [ + "2": "2", + "25": "25", + "7": "7", + "alice": "alice", + "bob": "bob", + "Charlie": "Charlie", + "日本": "日本", + "中国": "中国", + "韓国": "韓国", + ] #if os(macOS) || DARWIN_COMPATIBILITY_TESTS if #available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) { - _testRoundTrip(of: person, expectedJSON: expectedJSON, outputFormatting: [.sortedKeys]) + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + let payload = try encoder.encode(testValue) + XCTAssertEqual(expectedJSON, payload) } #else - _testRoundTrip(of: person, expectedJSON: expectedJSON, outputFormatting: [.sortedKeys]) + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + let payload = try encoder.encode(testValue) + XCTAssertEqual(expectedJSON, payload) #endif } - func test_encodingOutputFormattingPrettyPrintedSortedKeys() { - let expectedJSON = "{\n \"email\" : \"appleseed@apple.com\",\n \"name\" : \"Johnny Appleseed\"\n}".data(using: .utf8)! - let person = Person.testValue + func test_encodingOutputFormattingPrettyPrintedSortedKeys() throws { + let expectedJSON = try XCTUnwrap(""" + { + "2" : "2", + "7" : "7", + "25" : "25", + "alice" : "alice", + "bob" : "bob", + "Charlie" : "Charlie", + "中国" : "中国", + "日本" : "日本", + "韓国" : "韓国" + } + """.data(using: .utf8)) + let testValue = [ + "2": "2", + "25": "25", + "7": "7", + "alice": "alice", + "bob": "bob", + "Charlie": "Charlie", + "日本": "日本", + "中国": "中国", + "韓国": "韓国", + ] #if os(macOS) || DARWIN_COMPATIBILITY_TESTS if #available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) { - _testRoundTrip(of: person, expectedJSON: expectedJSON, outputFormatting: [.prettyPrinted, .sortedKeys]) + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + let payload = try encoder.encode(testValue) + XCTAssertEqual(expectedJSON, payload) } #else - _testRoundTrip(of: person, expectedJSON: expectedJSON, outputFormatting: [.prettyPrinted, .sortedKeys]) + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + let payload = try encoder.encode(testValue) + XCTAssertEqual(expectedJSON, payload) #endif } diff --git a/Tests/Foundation/Tests/TestNSLock.swift b/Tests/Foundation/Tests/TestNSLock.swift index 3e40a8a38b..58a1b00060 100644 --- a/Tests/Foundation/Tests/TestNSLock.swift +++ b/Tests/Foundation/Tests/TestNSLock.swift @@ -14,6 +14,7 @@ class TestNSLock: XCTestCase { ("test_lockWait", test_lockWait), ("test_threadsAndLocks", test_threadsAndLocks), ("test_recursiveLock", test_recursiveLock), + ("test_withLock", test_withLock), ] } @@ -187,4 +188,33 @@ class TestNSLock: XCTestCase { threadCompletedCondition.unlock() } + + func test_withLock() { + let lock = NSLock() + + var counter = 0 + let counterIncrementPerThread = 10_000 + + let threadCount = 10 + + let threadCompletedExpectation = expectation(description: "Expected threads to complete.") + threadCompletedExpectation.expectedFulfillmentCount = threadCount + + for _ in 0..