From b05e8a0e132d659ee1ca231e15bfded5d63392cc Mon Sep 17 00:00:00 2001 From: woxtu Date: Sat, 10 Jun 2023 13:42:52 +0000 Subject: [PATCH 01/63] Fix sorting keys tests --- Tests/Foundation/Tests/TestJSONEncoder.swift | 66 +++++++++++++++++--- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/Tests/Foundation/Tests/TestJSONEncoder.swift b/Tests/Foundation/Tests/TestJSONEncoder.swift index 3fc3451898..e919572b9d 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 } From d62fc6d62fd4ba76e4ce9ac5b6e8b9982691ed17 Mon Sep 17 00:00:00 2001 From: woxtu Date: Sat, 10 Jun 2023 13:47:32 +0000 Subject: [PATCH 02/63] Fix sorting keys --- Sources/Foundation/JSONEncoder.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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) From 1c929e5fa58676afeaecc75c2cdeca5091bf8bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B6pfl?= Date: Thu, 2 Nov 2023 18:16:53 +0100 Subject: [PATCH 03/63] Fixes issue #4642: Encountering "Constant strings cannot be deallocated" in Linux foundation (#4653) The reported error was an CFSTR("") which is later released. While this should not be a problem, the Linux implementation of CFSTR does not ignore dealloc on constant strings. Fixed this by calling CFRetain on the constant string. Strictly speaking this is only a workaround. Issue #1351 has some hints how this could be fixed but the workaround is used a over the code so I think it is okay to use it here, too. I found the same problem in CFDateIntervalFormatter.c where it appeared in a error handling code path that should never be called. Fixed anyways. --- CoreFoundation/Locale.subproj/CFDateIntervalFormatter.c | 4 ++-- CoreFoundation/PlugIn.subproj/CFBundle_Resources.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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/PlugIn.subproj/CFBundle_Resources.c b/CoreFoundation/PlugIn.subproj/CFBundle_Resources.c index c7fb636b71..601d014a73 100644 --- a/CoreFoundation/PlugIn.subproj/CFBundle_Resources.c +++ b/CoreFoundation/PlugIn.subproj/CFBundle_Resources.c @@ -1242,7 +1242,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); From 36a411b304063de2cbd3fe06adc662e7648d5a9d Mon Sep 17 00:00:00 2001 From: Jonathan Flat <50605158+jrflat@users.noreply.github.com> Date: Thu, 16 Nov 2023 09:28:47 -0800 Subject: [PATCH 04/63] Ensure URLSession and curl agree on the host (#4836) --- .../URL.subproj/CFURLSessionInterface.c | 19 +++++++++++++++++++ .../URL.subproj/CFURLSessionInterface.h | 1 + .../URLSession/FTP/FTPURLProtocol.swift | 16 +++++++++++++++- .../URLSession/HTTP/HTTPURLProtocol.swift | 16 +++++++++++++++- .../URLSession/libcurl/EasyHandle.swift | 12 +++++++++--- 5 files changed, 59 insertions(+), 5 deletions(-) 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/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() } } From 9f011c66e038b60826e8113208d3d6dc55eb9551 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 22 Nov 2023 12:31:24 -0800 Subject: [PATCH 05/63] Foundation: avoid temporary file leaks on Windows Correct the implementation of `_NSCleanupTemporaryFile` to use `MoveFileExW` with `MOVEFILE_COPY_ALLOWED` to prefer to use file renames rather than copy and delete. This should improve performance in the general single volume case and still allow the correct behaviour in the multi-volume scenarios using `CopyFile` and `DeleteFile`. Thanks to @darinf for identifying the test case with 65535 temporary files! --- Sources/Foundation/FileManager+Win32.swift | 2 +- Sources/Foundation/NSPathUtilities.swift | 3 ++- Sources/Foundation/WinSDK+Extensions.swift | 12 ++++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) 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/NSPathUtilities.swift b/Sources/Foundation/NSPathUtilities.swift index beba8d86eb..1726b35115 100644 --- a/Sources/Foundation/NSPathUtilities.swift +++ b/Sources/Foundation/NSPathUtilities.swift @@ -813,7 +813,8 @@ internal func _NSCleanupTemporaryFile(_ auxFilePath: String, _ filePath: String) #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) 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) } From c38b49e4da3eb00d0db7565623b3e1175836bdf7 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Tue, 19 Dec 2023 10:49:20 -0800 Subject: [PATCH 06/63] [runloop] Fix the failure memory order argument to atomic_compare_exchange_strong_explicit The failure memory order cannot be release or acq_rel. Clang since https://github.com/llvm/llvm-project/commit/fed564432cef76f8b303c19ab1dfc0a14878fbc3 diagnoses an invalid argument. --- CoreFoundation/RunLoop.subproj/CFRunLoop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CoreFoundation/RunLoop.subproj/CFRunLoop.c b/CoreFoundation/RunLoop.subproj/CFRunLoop.c index 466eb6fe9d..f202dda2bf 100644 --- a/CoreFoundation/RunLoop.subproj/CFRunLoop.c +++ b/CoreFoundation/RunLoop.subproj/CFRunLoop.c @@ -1306,7 +1306,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) { From c854cfc522a783c64ec196ee0b9dd039d43f9fee Mon Sep 17 00:00:00 2001 From: fumoboy007 <2100868+fumoboy007@users.noreply.github.com> Date: Wed, 3 Jan 2024 16:16:09 -0800 Subject: [PATCH 07/63] Avoid unnecessarily allocating an array when initializing `String` from a sequence of bytes. (#4813) --- .../Foundation-swiftoverlay/NSStringAPI.swift | 19 ++++++++++++++----- Sources/Foundation/NSStringAPI.swift | 19 ++++++++++++++----- 2 files changed, 28 insertions(+), 10 deletions(-) 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/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) From aed225266e83fee20e1de706e1389813cceb683a Mon Sep 17 00:00:00 2001 From: fumoboy007 <2100868+fumoboy007@users.noreply.github.com> Date: Wed, 3 Jan 2024 16:17:09 -0800 Subject: [PATCH 08/63] Add `NSLock.withLock(_:)` method. (#4736) Fixes #4735. Xcode 14 introduced the `NSLocking.withLock(_:)` method to the Darwin implementation of Foundation. This commit adds the new method to the open-source implementation. (Note: The [documentation](https://developer.apple.com/documentation/foundation/nslocking/4059821-withlock) incorrectly specifies the availability of the method as iOS 16+, etc. but it is actually available on all OS versions because it is marked [`@_alwaysEmitIntoClient`](https://github.com/apple/swift/blob/main/docs/ReferenceGuides/UnderscoredAttributes.md#_alwaysemitintoclient). The documentation bug is tracked by [FB11968310](https://feedbackassistant.apple.com/feedback/11968310).) I copied the implementation from `Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Modules/Foundation.swiftmodule/arm64e-apple-ios.swiftinterface`. --- Sources/Foundation/NSLock.swift | 13 +++++++++++ Tests/Foundation/Tests/TestNSLock.swift | 30 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/Sources/Foundation/NSLock.swift b/Sources/Foundation/NSLock.swift index 59d334f1ad..f4384b70ac 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 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.. Date: Sun, 4 Feb 2024 13:57:13 +0000 Subject: [PATCH 09/63] [wasm][build] Guard libdispatch and Threads usage with HAS_LIBDISPATCH_API This is a follow-up to 5e7281b993ca04486ed8f2add39c8b11f132a550 --- CMakeLists.txt | 4 +++- CoreFoundation/CMakeLists.txt | 36 ++++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bb1099078..646cd3e4d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,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) diff --git a/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt index beb48d6c86..18c2e508f4 100644 --- a/CoreFoundation/CMakeLists.txt +++ b/CoreFoundation/CMakeLists.txt @@ -22,7 +22,9 @@ 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) @@ -385,10 +387,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) @@ -504,15 +511,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 From 18d6a75ef7c0d82cbdfadfd1a90e53a119a00d1c Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 7 Feb 2024 17:19:00 +0000 Subject: [PATCH 10/63] [wasm] Port BlocksRuntime for no dlfcn.h platforms BlocksRuntime uses dlsym to find objc_destructInstance, which is not available on all platforms. This change adds a check for dlfcn.h and only uses dlsym if it is available and otherwise crashes the program. The crash will not usually happen, as `_Block_use_RR` is only called from objc-auto, which is not available for such platforms. --- Sources/BlocksRuntime/runtime.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 } From 98e2d980d83d9f0a157f7fd9d8e10b3deff1b519 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 14 Feb 2024 18:12:44 +0900 Subject: [PATCH 11/63] Bump the macOS deployment target to 10.13 in the Xcode project. Xcode 15 no longer recognizes 10.12 as a valid deployment target and just falls back to 14.2, which is too new for our CI. --- Foundation.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Foundation.xcodeproj/project.pbxproj b/Foundation.xcodeproj/project.pbxproj index baaa84e7ed..2e6436d971 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; @@ -4268,7 +4268,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 +4299,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; From e54dd44b0258860298085f75e3000e6f083e9889 Mon Sep 17 00:00:00 2001 From: Hiroshi Yamauchi Date: Tue, 13 Feb 2024 10:19:37 -0800 Subject: [PATCH 12/63] Support Windows ARM64 builds. --- cmake/modules/SwiftSupport.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index ffb24527eb..67c9edd979 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -11,6 +11,8 @@ function(get_swift_host_arch result_var_name) set("${result_var_name}" "x86_64" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64") set("${result_var_name}" "aarch64" PARENT_SCOPE) + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ARM64") + set("${result_var_name}" "aarch64" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64") set("${result_var_name}" "powerpc64" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") From dc549029c2161bb6fd5cf567a5461e52328a377b Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 16 Feb 2024 02:24:18 +0900 Subject: [PATCH 13/63] Stop assuming `CFSTR` is a constant-time expression with Clang 15 (#4872) From Clang 15, nested static initializer inside statement-expression is no longer a constant-time expression (See https://reviews.llvm.org/D127201). OSS Foundation defines `CFSTR` as a macro rather than `__builtin___CFStringMakeConstantString` and it uses nested static initializer inside statement-expression, so we can't assume `CFSTR` itself is always a constant-time expression. This patch removes some `static` qualifiers associated with `CFSTR` to make them acceptable with Clang 15 and later. --- CoreFoundation/Locale.subproj/CFLocale.c | 2 +- CoreFoundation/PlugIn.subproj/CFBundle_Locale.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CoreFoundation/Locale.subproj/CFLocale.c b/CoreFoundation/Locale.subproj/CFLocale.c index c5c555c92a..738ff28a0b 100644 --- a/CoreFoundation/Locale.subproj/CFLocale.c +++ b/CoreFoundation/Locale.subproj/CFLocale.c @@ -1274,7 +1274,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/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])) { From 81e494c575338568a5825ff9ee08862e1f0f411e Mon Sep 17 00:00:00 2001 From: Freddy Kellison-Linn Date: Thu, 15 Feb 2024 16:21:36 -0500 Subject: [PATCH 14/63] NSNotification.Name is sendable --- Sources/Foundation/NSNotification.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Foundation/NSNotification.swift b/Sources/Foundation/NSNotification.swift index 15b2e78f13..82f7536170 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) { From d5c78dc7c43d973e1d4923dece91ec3f58652a73 Mon Sep 17 00:00:00 2001 From: Freddy Kellison-Linn Date: Thu, 15 Feb 2024 15:47:07 -0500 Subject: [PATCH 15/63] CG types are sendable --- Sources/Foundation/CGFloat.swift | 2 +- Sources/Foundation/NSGeometry.swift | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) 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/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 } From 004a9dd527da8614ea049bf038e82d08f37d9564 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 7 Feb 2024 16:35:42 +0000 Subject: [PATCH 16/63] [wasm][build] Exclude Tools from build when BUILD_TOOLS is OFF This is a follow up to 5e7281b993ca04486ed8f2add39c8b11f132a550, which just adds the `BUILD_TOOLS` option but doesn't actually use it. This patch renames the option to follow the CMake conventions and uses it to actually exclude the tools from the build. --- CMakeLists.txt | 2 +- Sources/CMakeLists.txt | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bb1099078..46b757e5a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift) option(BUILD_SHARED_LIBS "build shared libraries" ON) option(HAS_LIBDISPATCH_API "has libdispatch API" ON) option(BUILD_NETWORKING "build FoundationNetworking module" ON) -option(BUILD_TOOLS "build tools" 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) diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt index ab3a1bef11..93c067d261 100644 --- a/Sources/CMakeLists.txt +++ b/Sources/CMakeLists.txt @@ -2,4 +2,6 @@ add_subdirectory(UUID) add_subdirectory(Foundation) add_subdirectory(FoundationNetworking) add_subdirectory(FoundationXML) -add_subdirectory(Tools) +if(FOUNDATION_BUILD_TOOLS) + add_subdirectory(Tools) +endif() From 3744d4d2df6b43f87fbc075b91296f4d0c94ab0f Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 29 Oct 2023 00:39:31 +0000 Subject: [PATCH 17/63] [wasm] Port thread-related APIs for no thread platform This change ports the thread-related APIs for the no thread platform by adding no-op implementations. Note that WASI is going to support threads in the near future, so this does not guard by `TARGET_OS_WASI` but by `!SWIFT_CORELIBS_FOUNDATION_HAS_THREADS` to make it easier for future WASI + threads support. --- CoreFoundation/Base.subproj/CFInternal.h | 33 +++++- CoreFoundation/Base.subproj/CFPlatform.c | 3 + CoreFoundation/Base.subproj/CFRuntime.c | 6 +- CoreFoundation/Base.subproj/CFUtilities.c | 9 +- .../Base.subproj/ForSwiftFoundationOnly.h | 6 + CoreFoundation/CMakeLists.txt | 4 + Sources/Foundation/CMakeLists.txt | 7 ++ Sources/Foundation/NSLock.swift | 103 ++++++++++++------ 8 files changed, 136 insertions(+), 35 deletions(-) diff --git a/CoreFoundation/Base.subproj/CFInternal.h b/CoreFoundation/Base.subproj/CFInternal.h index b737f30ec7..6f99889099 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 diff --git a/CoreFoundation/Base.subproj/CFPlatform.c b/CoreFoundation/Base.subproj/CFPlatform.c index 040e8966f2..bbb3cdba97 100644 --- a/CoreFoundation/Base.subproj/CFPlatform.c +++ b/CoreFoundation/Base.subproj/CFPlatform.c @@ -1628,6 +1628,8 @@ CF_PRIVATE int asprintf(char **ret, const char *format, ...) { 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,6 +1808,7 @@ 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 diff --git a/CoreFoundation/Base.subproj/CFRuntime.c b/CoreFoundation/Base.subproj/CFRuntime.c index afdbf5d21e..61e6b29313 100644 --- a/CoreFoundation/Base.subproj/CFRuntime.c +++ b/CoreFoundation/Base.subproj/CFRuntime.c @@ -1194,9 +1194,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 diff --git a/CoreFoundation/Base.subproj/CFUtilities.c b/CoreFoundation/Base.subproj/CFUtilities.c index 7c3fc9f8e7..5b4a25e13d 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()); diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h index 642151ab34..80c881be58 100644 --- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h +++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h @@ -412,6 +412,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 +427,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,6 +436,7 @@ 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); diff --git a/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt index beb48d6c86..31175fda5a 100644 --- a/CoreFoundation/CMakeLists.txt +++ b/CoreFoundation/CMakeLists.txt @@ -99,6 +99,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>) diff --git a/Sources/Foundation/CMakeLists.txt b/Sources/Foundation/CMakeLists.txt index fc093ce0c8..f3cc6bf252 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" diff --git a/Sources/Foundation/NSLock.swift b/Sources/Foundation/NSLock.swift index f4384b70ac..0513bfd96e 100644 --- a/Sources/Foundation/NSLock.swift +++ b/Sources/Foundation/NSLock.swift @@ -57,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) @@ -71,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) @@ -84,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) @@ -92,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) @@ -109,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 @@ -117,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 } @@ -127,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 } @@ -152,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 @@ -256,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) @@ -284,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) @@ -297,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) @@ -305,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) @@ -322,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 @@ -330,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 } @@ -340,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 } @@ -362,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 @@ -372,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) @@ -385,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) @@ -393,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) @@ -401,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) @@ -409,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 { @@ -420,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) @@ -428,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) From 32e9e2dcb9f9aad2f35ca0f3c8ec218f39ce54d5 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 22 Feb 2024 10:17:55 +0000 Subject: [PATCH 18/63] [Build] Add `SWIFT_SYSTEM_NAME` setting. This lets us override the library subdir name when its derivation isn't straightforwardly just the lower-case version of `CMAKE_SYSTEM_NAME`. rdar://123381867 --- CMakeLists.txt | 12 ++++++++++-- Sources/BlocksRuntime/CMakeLists.txt | 4 ++-- Sources/Tools/plutil/CMakeLists.txt | 2 +- Sources/UUID/CMakeLists.txt | 4 ++-- cmake/modules/SwiftSupport.cmake | 7 +------ 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bb1099078..e67b99a845 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 @@ -99,13 +107,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) 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/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/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/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/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index ffb24527eb..ba22becab2 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -49,12 +49,7 @@ endfunction() # Sets ${result_var_name} with the converted OS name derived from # CMAKE_SYSTEM_NAME. function(get_swift_host_os result_var_name) - if(CMAKE_SYSTEM_NAME STREQUAL Darwin) - set(${result_var_name} macosx PARENT_SCOPE) - else() - string(TOLOWER ${CMAKE_SYSTEM_NAME} cmake_system_name_lc) - set(${result_var_name} ${cmake_system_name_lc} PARENT_SCOPE) - endif() + set(${result_var_name} ${SWIFT_SYSTEM_NAME} PARENT_SCOPE) endfunction() function(_install_target module) From b0b6977efc5511386b04c7858e834442faf62e01 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 22 Feb 2024 10:22:13 +0000 Subject: [PATCH 19/63] [Build] Make CMake locate librt for us. This is needed when we're statically linking, otherwise we can't pull in Dispatch because we won't have RT::rt as a CMake target. rdar://123381867 --- CMakeLists.txt | 6 ++++++ cmake/modules/FindLibRT.cmake | 39 +++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 cmake/modules/FindLibRT.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index e67b99a845..cb383c2338 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,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) diff --git a/cmake/modules/FindLibRT.cmake b/cmake/modules/FindLibRT.cmake new file mode 100644 index 0000000000..0a9f0d80e5 --- /dev/null +++ b/cmake/modules/FindLibRT.cmake @@ -0,0 +1,39 @@ +#.rst: +# FindLibRT +# --------- +# +# Find librt library and headers. +# +# The mdoule defines the following variables: +# +# :: +# +# LibRT_FOUND - true if librt was found +# LibRT_INCLUDE_DIR - include search path +# LibRT_LIBRARIES - libraries to link + +if(UNIX) + find_path(LibRT_INCLUDE_DIR + NAMES + time.h) + find_library(LibRT_LIBRARIES rt) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(LibRT + REQUIRED_VARS + LibRT_LIBRARIES + LibRT_INCLUDE_DIR) + + if(LibRT_FOUND) + if(NOT TARGET RT::rt) + add_library(RT::rt UNKNOWN IMPORTED) + set_target_properties(RT::rt + PROPERTIES + IMPORTED_LOCATION ${LibRT_LIBRARIES} + INTERFACE_INCLUDE_DIRECTORIES ${LibRT_INCLUDE_DIR}) + endif() + endif() + + mark_as_advanced(LibRT_LIBRARIES LibRT_INCLUDE_DIR) +endif() + From db0c7fce7486ef3fcf9405b363240d89ba69530a Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 22 Feb 2024 10:25:20 +0000 Subject: [PATCH 20/63] [Build] When building against musl, add -lfts. Musl doesn't have fts built-in; it's in a separate library, which we need to add if we're going to use it. rdar://123381867 --- Sources/Foundation/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/Foundation/CMakeLists.txt b/Sources/Foundation/CMakeLists.txt index fc093ce0c8..7154092e29 100644 --- a/Sources/Foundation/CMakeLists.txt +++ b/Sources/Foundation/CMakeLists.txt @@ -164,6 +164,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 "$" From a63cfbad45c0834d9608faf06f822e44a74ccafa Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 4 Feb 2024 14:42:43 +0000 Subject: [PATCH 21/63] [wasm][build] Disable networking targets from CMake build This is a follow-up to 5e7281b993ca04486ed8f2add39c8b11f132a550, which introduced `BUILD_NETWORKING` option but didn't update the CMake build to respect it. This patch renames the option to follow CMake conventions and updates the build to respect it. --- CMakeLists.txt | 4 ++-- CoreFoundation/CMakeLists.txt | 25 +++++++++++++++++-------- Sources/CMakeLists.txt | 4 +++- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fab83a0d1..10bc812561 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift) option(BUILD_SHARED_LIBS "build shared libraries" ON) option(HAS_LIBDISPATCH_API "has libdispatch API" ON) -option(BUILD_NETWORKING "build FoundationNetworking module" 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) @@ -103,7 +103,7 @@ if(NOT BUILD_SHARED_LIBS) install(TARGETS CoreFoundation CFXMLInterface DESTINATION lib/swift_static/$) - if(BUILD_NETWORKING) + if(FOUNDATION_ENABLE_FOUNDATION_NETWORKING) set_property(GLOBAL APPEND PROPERTY Foundation_EXPORTS CFURLSessionInterface) install(TARGETS CFURLSessionInterface diff --git a/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt index 18c2e508f4..34192c65d6 100644 --- a/CoreFoundation/CMakeLists.txt +++ b/CoreFoundation/CMakeLists.txt @@ -28,11 +28,14 @@ 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() @@ -438,7 +441,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() @@ -540,10 +543,16 @@ 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/Sources/CMakeLists.txt b/Sources/CMakeLists.txt index 93c067d261..14ace7ad51 100644 --- a/Sources/CMakeLists.txt +++ b/Sources/CMakeLists.txt @@ -1,6 +1,8 @@ add_subdirectory(UUID) add_subdirectory(Foundation) -add_subdirectory(FoundationNetworking) +if(FOUNDATION_ENABLE_FOUNDATION_NETWORKING) + add_subdirectory(FoundationNetworking) +endif() add_subdirectory(FoundationXML) if(FOUNDATION_BUILD_TOOLS) add_subdirectory(Tools) From fa3086811213c46cfb0256e88284bd0059001872 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 4 Feb 2024 16:20:24 +0000 Subject: [PATCH 22/63] [wasm] Fix signatures of `swift_retain` Function signature cannot be inconsistent in Wasm platforms. This patch fixes the signature of `swift_retain` to return the retained object. --- CoreFoundation/Base.subproj/CFPlatform.c | 2 +- CoreFoundation/Base.subproj/CFRuntime.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CoreFoundation/Base.subproj/CFPlatform.c b/CoreFoundation/Base.subproj/CFPlatform.c index 040e8966f2..a8e97f0c53 100644 --- a/CoreFoundation/Base.subproj/CFPlatform.c +++ b/CoreFoundation/Base.subproj/CFPlatform.c @@ -1625,7 +1625,7 @@ 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 TARGET_OS_WIN32 diff --git a/CoreFoundation/Base.subproj/CFRuntime.c b/CoreFoundation/Base.subproj/CFRuntime.c index afdbf5d21e..9f62ec3c9f 100644 --- a/CoreFoundation/Base.subproj/CFRuntime.c +++ b/CoreFoundation/Base.subproj/CFRuntime.c @@ -1407,7 +1407,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". From cd522ff746f708fb6a3751603b4a66352abd6014 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 8 Feb 2024 06:13:11 +0000 Subject: [PATCH 23/63] [wasm] Port NSError.swift for WASI --- Sources/Foundation/NSError.swift | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) 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 From 05e5023437230185906e457e4a26a3896b07a4b2 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 4 Feb 2024 16:09:44 +0000 Subject: [PATCH 24/63] [wasm] Port `CoreFoundation/Base.subproj/CFFileUtilities.c` --- CoreFoundation/Base.subproj/CFFileUtilities.c | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) 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; From f634213c1edfe50556ae4b75c9a1a4b579d38887 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 4 Feb 2024 16:23:50 +0000 Subject: [PATCH 25/63] [wasm] Unlock cwd-related APIs wasi-libc has user-land implementations of `getcwd`, so we don't need to guard cwd-related APIs. --- CoreFoundation/Base.subproj/CFPlatform.c | 2 -- CoreFoundation/URL.subproj/CFURL.c | 16 ++++------------ 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/CoreFoundation/Base.subproj/CFPlatform.c b/CoreFoundation/Base.subproj/CFPlatform.c index 040e8966f2..9d11ed71a3 100644 --- a/CoreFoundation/Base.subproj/CFPlatform.c +++ b/CoreFoundation/Base.subproj/CFPlatform.c @@ -62,11 +62,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 diff --git a/CoreFoundation/URL.subproj/CFURL.c b/CoreFoundation/URL.subproj/CFURL.c index 9b2dc82be8..93d257c5a2 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 @@ -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; From 68775d9fbcd63afbd98f407d8e387188f4b53c19 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 4 Feb 2024 16:31:06 +0000 Subject: [PATCH 26/63] [wasm] Use `__wasilibc_get_environ` to get environ The `environ` variable in wasi-libc need to be accessed through the `__wasilibc_get_environ` function to ensure that it is initialized properly. --- CoreFoundation/Base.subproj/CFPlatform.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CoreFoundation/Base.subproj/CFPlatform.c b/CoreFoundation/Base.subproj/CFPlatform.c index 040e8966f2..672a437526 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 @@ -1812,8 +1816,10 @@ CF_EXPORT char **_CFEnviron(void) { 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; From 836b94002f06d10faef64a9a4823d89a967f650d Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 4 Feb 2024 16:32:44 +0000 Subject: [PATCH 27/63] [wasm] Port CoreFoundation/Base.subproj/CFRuntime.c --- CoreFoundation/Base.subproj/CFRuntime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CoreFoundation/Base.subproj/CFRuntime.c b/CoreFoundation/Base.subproj/CFRuntime.c index afdbf5d21e..06d8ab645e 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() @@ -1162,7 +1162,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 From 80e95bb98f13601e839f3d1161d528ea5b4edaf4 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 22 Feb 2024 10:26:52 +0000 Subject: [PATCH 28/63] [Build] Add some libraries to the autolink list. For static linking, we need to list all the dependencies of libcurl or libxml2 that we're using. This differs from dynamic linking, because in the latter case that information is in the shared objects, which is not true in the statically linked case. rdar://123381867 --- CMakeLists.txt | 1 + Sources/FoundationNetworking/CMakeLists.txt | 8 ++++++++ Sources/FoundationXML/CMakeLists.txt | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index cb383c2338..11e6511c53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ 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) 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/FoundationXML/CMakeLists.txt b/Sources/FoundationXML/CMakeLists.txt index 944ea25875..5a73f70f58 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 $) From 48076cb22c151b52b52e204328d097a2474f64b6 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 22 Feb 2024 10:30:10 +0000 Subject: [PATCH 29/63] [CoreFoundation][Build] Explicitly check for a few functions. Use CMake to check for the existence of strlcpy(), strlcat() and issetugid() before using them. rdar://123381867 --- .../Base.subproj/CoreFoundation_Prefix.h | 8 ++++++-- CoreFoundation/CMakeLists.txt | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h b/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h index bf6f203b5f..928fef002f 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 @@ -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 diff --git a/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt index beb48d6c86..b4827f44c5 100644 --- a/CoreFoundation/CMakeLists.txt +++ b/CoreFoundation/CMakeLists.txt @@ -90,6 +90,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>) From fbc7e2c28e286d1f70c45b4d11bf7bf329fc8704 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 22 Feb 2024 10:38:18 +0000 Subject: [PATCH 30/63] [CoreFoundation] Don't assume we can use __GLIBC_PREREQ on Linux. We might be using musl instead, which doesn't have __GLIBC_PREREQ as it isn't Glibc. rdar://123381867 --- CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h index 642151ab34..1717c04d07 100644 --- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h +++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h @@ -69,6 +69,7 @@ #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 +79,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 From 321997f774fac1da29d5c98de4d0f027901a84d2 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 22 Feb 2024 10:39:22 +0000 Subject: [PATCH 31/63] [CoreFoundation] Musl doesn't have _D_EXACT_NAMLEN or d_namlen. This means we're in the same boat as for Android - we need to use `strlen`. rdar://123381867 --- CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h index 1717c04d07..9dc7379c9d 100644 --- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h +++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h @@ -563,7 +563,7 @@ CF_CROSS_PLATFORM_EXPORT int _CFOpenFile(const char *path, int opts); 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 return strlen(entry->d_name); #else return entry->d_namlen; From 56c4738a615ca55bb34701d6243d7b31ca645964 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 22 Feb 2024 10:42:08 +0000 Subject: [PATCH 32/63] [CoreFoundation][Foundation][Tools] Miscellanous musl support. This is mostly checking for and importing the `Musl` module and, where necessary, using it instead of the `Glibc` module. rdar://123381867 --- CoreFoundation/Base.subproj/CFUtilities.c | 2 +- Sources/Foundation/Data.swift | 9 +++++++++ Sources/Foundation/FileHandle.swift | 5 +++++ Sources/Foundation/Host.swift | 2 +- Sources/Foundation/NSData.swift | 4 +++- Sources/Foundation/NSSwiftRuntime.swift | 4 +++- Sources/Foundation/NSURL.swift | 2 ++ Sources/Foundation/Process.swift | 2 +- Sources/Foundation/Thread.swift | 8 ++++++-- Sources/Tools/plutil/main.swift | 3 +++ 10 files changed, 34 insertions(+), 7 deletions(-) diff --git a/CoreFoundation/Base.subproj/CFUtilities.c b/CoreFoundation/Base.subproj/CFUtilities.c index 7c3fc9f8e7..e3fdd98c04 100644 --- a/CoreFoundation/Base.subproj/CFUtilities.c +++ b/CoreFoundation/Base.subproj/CFUtilities.c @@ -1675,7 +1675,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/Sources/Foundation/Data.swift b/Sources/Foundation/Data.swift index 86585a3a86..23254e6b22 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 diff --git a/Sources/Foundation/FileHandle.swift b/Sources/Foundation/FileHandle.swift index a538a2975e..285bed7059 100644 --- a/Sources/Foundation/FileHandle.swift +++ b/Sources/Foundation/FileHandle.swift @@ -22,6 +22,11 @@ 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(_:) #endif #if canImport(WinSDK) diff --git a/Sources/Foundation/Host.swift b/Sources/Foundation/Host.swift index 5fe7b29c5b..5a72373c6d 100644 --- a/Sources/Foundation/Host.swift +++ b/Sources/Foundation/Host.swift @@ -281,7 +281,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/NSData.swift b/Sources/Foundation/NSData.swift index ed9e7f0529..e004c9502a 100644 --- a/Sources/Foundation/NSData.swift +++ b/Sources/Foundation/NSData.swift @@ -494,8 +494,10 @@ 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) #endif guard let fh = FileHandle(path: path, flags: flags, createMode: createMode) else { throw _NSErrorWithErrno(errno, reading: false, path: path) 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..4b6a2a5b98 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 diff --git a/Sources/Foundation/Process.swift b/Sources/Foundation/Process.swift index 542cc94cf1..8d5ac46563 100644 --- a/Sources/Foundation/Process.swift +++ b/Sources/Foundation/Process.swift @@ -776,7 +776,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) diff --git a/Sources/Foundation/Thread.swift b/Sources/Foundation/Thread.swift index 7734cf738d..7fbcbb522e 100644 --- a/Sources/Foundation/Thread.swift +++ b/Sources/Foundation/Thread.swift @@ -14,6 +14,8 @@ import WinSDK #if canImport(Glibc) import Glibc +#elseif canImport(Musl) +import Musl #endif // WORKAROUND_SR9811 @@ -356,13 +358,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 +387,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() 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 From a3c2228bf5d06e3289ecd069df86eaf73fce92ea Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 26 Feb 2024 16:43:12 +0000 Subject: [PATCH 33/63] [Build] Make sure we include CheckSymbolExists. We need to include CheckSymbolExists on Windows as well as on Linux. rdar://123381867 --- CoreFoundation/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt index b4827f44c5..2e8afc2139 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) @@ -70,8 +73,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) From 7fa782be924ccfc5e57fe1c07d3aeb3129cbc4d0 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 29 Feb 2024 07:22:27 +0900 Subject: [PATCH 34/63] Repair the macOS build by adding missing `-D` in Xcode project macOS build was broken by 3744d4d2df6b43f87fbc075b91296f4d0c94ab0f, which introduced a new constant definition but did not add it to the Xcode project. --- Foundation.xcodeproj/project.pbxproj | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Foundation.xcodeproj/project.pbxproj b/Foundation.xcodeproj/project.pbxproj index 2e6436d971..e781b7afb2 100644 --- a/Foundation.xcodeproj/project.pbxproj +++ b/Foundation.xcodeproj/project.pbxproj @@ -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; From 70088251861422e4f306fb9d667362bf46cd2db7 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 4 Feb 2024 16:09:44 +0000 Subject: [PATCH 35/63] Port `CoreFoundation/Base.subproj/CFFileUtilities.c` --- CoreFoundation/Base.subproj/CFFileUtilities.c | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) 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; From 095b12f27e1e9a3496d998f89d73d7e10d89dd6b Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 14 Feb 2024 12:07:39 +0000 Subject: [PATCH 36/63] [wasm] Port ProcessInfo for WASI platform --- CoreFoundation/Base.subproj/CFPlatform.c | 46 ++++++++++++++++++++---- CoreFoundation/Base.subproj/CFPriv.h | 6 +--- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/CoreFoundation/Base.subproj/CFPlatform.c b/CoreFoundation/Base.subproj/CFPlatform.c index bbb3cdba97..dfba457af2 100644 --- a/CoreFoundation/Base.subproj/CFPlatform.c +++ b/CoreFoundation/Base.subproj/CFPlatform.c @@ -103,7 +103,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 +185,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 +272,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 +296,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 +314,6 @@ CF_PRIVATE CFStringRef _CFProcessNameString(void) { } return __CFProcessNameString; } -#endif // !TARGET_OS_WASI #if TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD @@ -387,16 +408,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 +458,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 +489,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 +557,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 +691,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 +702,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) { diff --git a/CoreFoundation/Base.subproj/CFPriv.h b/CoreFoundation/Base.subproj/CFPriv.h index 692a106a99..73292b0986 100644 --- a/CoreFoundation/Base.subproj/CFPriv.h +++ b/CoreFoundation/Base.subproj/CFPriv.h @@ -57,19 +57,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 +164,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 +175,6 @@ CFStringRef CFCopyUserName(void); CF_EXPORT CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName); /* Pass NULL for the current user's home directory */ -#endif /* From 3048047db3e401ffdba56ef6cead6233bde3910b Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 14 Feb 2024 12:09:08 +0000 Subject: [PATCH 37/63] [wasm] Port use of `dirent` for wasi-libc wasi-libc defines `d_name` as "flexible array member" which is not supported by ClangImporter yet. This patch replaces the use of `d_name` with a helper function `_direntName` to work around the issue. --- CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h | 4 ++++ Sources/Foundation/FileManager+POSIX.swift | 6 ++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h index d545b9e21e..37d38f26d1 100644 --- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h +++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h @@ -576,6 +576,10 @@ static inline int _direntNameLength(struct dirent *entry) { #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) { return major(rdev); diff --git a/Sources/Foundation/FileManager+POSIX.swift b/Sources/Foundation/FileManager+POSIX.swift index d90ece91e6..7c2a4e9c11 100644 --- a/Sources/Foundation/FileManager+POSIX.swift +++ b/Sources/Foundation/FileManager+POSIX.swift @@ -411,10 +411,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) From a5d3c211731414df8c26133eb932679d7d7da632 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 23 Feb 2024 04:08:12 +0000 Subject: [PATCH 38/63] [wasm] Fix definition conflict of `errno` WASILibc's `errno` conflicts with Clang-imported `errno` in . --- Sources/Foundation/NSPathUtilities.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Sources/Foundation/NSPathUtilities.swift b/Sources/Foundation/NSPathUtilities.swift index 1726b35115..e39408c136 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) From ca407803ffa799ac6cb016481bb38db287765720 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 14 Feb 2024 12:45:16 +0000 Subject: [PATCH 39/63] [wasm] Provide stub for `_NSCreateTemporaryFile` on WASI --- Sources/Foundation/NSPathUtilities.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/Foundation/NSPathUtilities.swift b/Sources/Foundation/NSPathUtilities.swift index e39408c136..f7e69c46b6 100644 --- a/Sources/Foundation/NSPathUtilities.swift +++ b/Sources/Foundation/NSPathUtilities.swift @@ -779,6 +779,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) @@ -814,8 +818,8 @@ 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 { From 48f2ad0aec035e696b7cf67ab1eca62da033f3e1 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 1 Mar 2024 08:50:07 +0000 Subject: [PATCH 40/63] [wasm] Port `CoreFoundation/StringEncodings.subproj` This commit adds `TARGET_OS_WASI` as ICU supported platform in `#if` conditions under `StringEncodings.subproj` --- .../StringEncodings.subproj/CFPlatformConverters.c | 4 ++-- .../CFStringEncodingConverter.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) 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; From e80fcc5d171ef62824c4ba48292c6317e815201b Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 1 Mar 2024 09:12:57 +0000 Subject: [PATCH 41/63] [wasm] Port FileManager for WASI platform --- .../Base.subproj/ForSwiftFoundationOnly.h | 16 +++- Sources/Foundation/FileHandle.swift | 6 ++ Sources/Foundation/FileManager+POSIX.swift | 73 +++++++++++++++++++ Sources/Foundation/FileManager.swift | 11 +++ Sources/Foundation/NSData.swift | 2 + 5 files changed, 105 insertions(+), 3 deletions(-) diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h index d545b9e21e..d78eeddf68 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 @@ -565,11 +565,11 @@ CF_CROSS_PLATFORM_EXPORT int _CFOpenFileWithMode(const char *path, int opts, mod 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_LINUX || TARGET_OS_ANDROID +#elif TARGET_OS_LINUX || TARGET_OS_ANDROID || TARGET_OS_WASI return strlen(entry->d_name); #else return entry->d_namlen; @@ -578,11 +578,21 @@ static inline int _direntNameLength(struct dirent *entry) { // 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 diff --git a/Sources/Foundation/FileHandle.swift b/Sources/Foundation/FileHandle.swift index 285bed7059..5fb7258ca8 100644 --- a/Sources/Foundation/FileHandle.swift +++ b/Sources/Foundation/FileHandle.swift @@ -27,6 +27,12 @@ import Musl fileprivate let _read = Musl.read(_:_:_:) fileprivate let _write = Musl.write(_:_:_:) fileprivate let _close = Musl.close(_:) +#elseif canImport(WASILibc) +import WASILibc +@_implementationOnly import wasi_emulated_mman +fileprivate let _read = WASILibc.read(_:_:_:) +fileprivate let _write = WASILibc.write(_:_:_:) +fileprivate let _close = WASILibc.close(_:) #endif #if canImport(WinSDK) diff --git a/Sources/Foundation/FileManager+POSIX.swift b/Sources/Foundation/FileManager+POSIX.swift index d90ece91e6..a69d71e9f7 100644 --- a/Sources/Foundation/FileManager+POSIX.swift +++ b/Sources/Foundation/FileManager+POSIX.swift @@ -96,6 +96,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 @@ -446,6 +472,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 +508,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 +538,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 +556,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 +576,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 +634,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 +786,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 +832,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 +935,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 +946,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 +1117,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 +1270,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.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/NSData.swift b/Sources/Foundation/NSData.swift index e004c9502a..5f3640300d 100644 --- a/Sources/Foundation/NSData.swift +++ b/Sources/Foundation/NSData.swift @@ -498,6 +498,8 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { 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) From 5a60991eb19a41788d898f1feb0816779cc899cf Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 1 Mar 2024 08:49:57 +0000 Subject: [PATCH 42/63] [wasm] Include syslog.h only if available wasi-libc does not provide `syslog.h`, so we should only include it if it is available. syslog APIs are only used for debugging code guarded under `DEBUG_URL_MEMORY_USAGE`, so it is safe to exclude it. --- CoreFoundation/URL.subproj/CFURL.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CoreFoundation/URL.subproj/CFURL.c b/CoreFoundation/URL.subproj/CFURL.c index 93d257c5a2..85adc844da 100644 --- a/CoreFoundation/URL.subproj/CFURL.c +++ b/CoreFoundation/URL.subproj/CFURL.c @@ -31,7 +31,7 @@ #include #if __has_include() #include -#else +#elif __has_include() #include #endif #include From 660ccc83e6cea6a753004a76624133b10ec55aba Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 1 Mar 2024 08:51:05 +0000 Subject: [PATCH 43/63] [wasm] Port CoreFoundation/PlugIn.subproj --- CoreFoundation/PlugIn.subproj/CFBundle.c | 2 +- CoreFoundation/PlugIn.subproj/CFBundle_BinaryTypes.h | 1 + CoreFoundation/PlugIn.subproj/CFBundle_InfoPlist.c | 8 +++++++- CoreFoundation/PlugIn.subproj/CFBundle_Internal.h | 4 +++- CoreFoundation/PlugIn.subproj/CFBundle_Resources.c | 4 ++++ 5 files changed, 16 insertions(+), 3 deletions(-) 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_Resources.c b/CoreFoundation/PlugIn.subproj/CFBundle_Resources.c index 601d014a73..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 From 5dc4849268b5a99f6e9c90abdfdf073d694346be Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 1 Mar 2024 08:52:29 +0000 Subject: [PATCH 44/63] [wasm] Port CoreFoundation/Preferences.subproj --- CoreFoundation/Preferences.subproj/CFPreferences.c | 4 ++-- CoreFoundation/Preferences.subproj/CFXMLPreferencesDomain.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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; From e0c821fa0910dac004d5e66c8a17ef4000790f17 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 1 Mar 2024 08:50:54 +0000 Subject: [PATCH 45/63] [wasm] Port CoreFoundation/String.subproj --- .../Base.subproj/CoreFoundation_Prefix.h | 2 +- .../String.subproj/CFCharacterSetData.S | 11 +++++++++++ CoreFoundation/String.subproj/CFString.c | 7 +++++-- .../String.subproj/CFStringUtilities.c | 18 +++++++++--------- .../String.subproj/CFUniCharPropertyDatabase.S | 11 +++++++++++ CoreFoundation/String.subproj/CFUnicodeData.S | 11 +++++++++++ 6 files changed, 48 insertions(+), 12 deletions(-) diff --git a/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h b/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h index 928fef002f..77678304aa 100644 --- a/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h +++ b/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h @@ -340,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/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 From 7a70a1bcbdb87e3a3cd47d70dc4c1ab1abc61d23 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 1 Mar 2024 09:09:43 +0000 Subject: [PATCH 46/63] [wasm] Remove too conservative guards around file operations Those guards were added to prevent the build from failing on WASI, but they are too conservative and the latest wasi-libc is now providing enough support for these operations. --- Sources/Foundation/Data.swift | 5 +---- Sources/Foundation/NSData.swift | 8 -------- Sources/Foundation/NSPathUtilities.swift | 13 ++++--------- Sources/Foundation/NSURL.swift | 14 -------------- 4 files changed, 5 insertions(+), 35 deletions(-) diff --git a/Sources/Foundation/Data.swift b/Sources/Foundation/Data.swift index 23254e6b22..d20a9fba03 100644 --- a/Sources/Foundation/Data.swift +++ b/Sources/Foundation/Data.swift @@ -36,6 +36,7 @@ @usableFromInline let memcpy = Musl.memcpy @usableFromInline let memcmp = Musl.memcmp #elseif canImport(WASILibc) +import wasi_emulated_mman @usableFromInline let calloc = WASILibc.calloc @usableFromInline let malloc = WASILibc.malloc @usableFromInline let free = WASILibc.free @@ -2048,7 +2049,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. @@ -2061,7 +2061,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. /// @@ -2325,7 +2324,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. @@ -2346,7 +2344,6 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl #endif } } -#endif // MARK: - diff --git a/Sources/Foundation/NSData.swift b/Sources/Foundation/NSData.swift index e004c9502a..ae0ac58516 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) @@ -545,7 +540,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. @@ -1012,7 +1006,6 @@ open class NSMutableData : NSData { super.init(data: data) } -#if !os(WASI) public override init?(contentsOfFile path: String) { super.init(contentsOfFile: path) } @@ -1028,7 +1021,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/NSPathUtilities.swift b/Sources/Foundation/NSPathUtilities.swift index 1726b35115..3d2507fd75 100644 --- a/Sources/Foundation/NSPathUtilities.swift +++ b/Sources/Foundation/NSPathUtilities.swift @@ -195,7 +195,6 @@ extension String { return temp } -#if !os(WASI) internal func _tryToRemovePathPrefix(_ prefix: String) -> String? { guard self != prefix else { return nil @@ -208,7 +207,6 @@ extension String { return nil } -#endif } extension NSString { @@ -338,7 +336,6 @@ extension NSString { return result._stringByFixingSlashes() } -#if !os(WASI) public var expandingTildeInPath: String { guard hasPrefix("~") else { return _swiftObject @@ -359,7 +356,6 @@ extension NSString { return result } -#endif #if os(Windows) public var unixPath: String { @@ -374,7 +370,6 @@ extension NSString { } #endif -#if !os(WASI) public var standardizingPath: String { #if os(Windows) let expanded = unixPath.expandingTildeInPath @@ -422,8 +417,6 @@ extension NSString { return resolvedPath } -#endif - public func stringsByAppendingPaths(_ paths: [String]) -> [String] { if self == "" { return paths @@ -655,7 +648,6 @@ extension NSString { } -#if !os(WASI) extension FileManager { public enum SearchPathDirectory: UInt { @@ -731,6 +723,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 +733,7 @@ public func NSHomeDirectoryForUser(_ user: String?) -> String? { let url: URL = homeDir._swiftObject return url.path +#endif } public func NSUserName() -> String { @@ -831,4 +827,3 @@ internal func _NSCleanupTemporaryFile(_ auxFilePath: String, _ filePath: String) }) #endif } -#endif diff --git a/Sources/Foundation/NSURL.swift b/Sources/Foundation/NSURL.swift index 4b6a2a5b98..4d31e2ba9c 100644 --- a/Sources/Foundation/NSURL.swift +++ b/Sources/Foundation/NSURL.swift @@ -556,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, @@ -574,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. @@ -918,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) @@ -971,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 @@ -1063,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) @@ -1597,7 +1584,6 @@ fileprivate extension URLResourceValuesStorage { } } } -#endif // ----- From 92f7dd1e37bb184893b9681305ca8e1298001691 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 6 Mar 2024 20:20:41 +0900 Subject: [PATCH 47/63] Update Sources/Foundation/Data.swift Co-authored-by: Max Desiatov --- Sources/Foundation/Data.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/Foundation/Data.swift b/Sources/Foundation/Data.swift index d20a9fba03..b76fef915c 100644 --- a/Sources/Foundation/Data.swift +++ b/Sources/Foundation/Data.swift @@ -36,7 +36,11 @@ @usableFromInline let memcpy = Musl.memcpy @usableFromInline let memcmp = Musl.memcmp #elseif canImport(WASILibc) +#if swift(>=6.0) +private import wasi_emulated_mman +#else import wasi_emulated_mman +#endif @usableFromInline let calloc = WASILibc.calloc @usableFromInline let malloc = WASILibc.malloc @usableFromInline let free = WASILibc.free From ea22e02fe6dba4fda9429248f65bd7faea4add2a Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sun, 4 Feb 2024 16:17:42 +0000 Subject: [PATCH 48/63] [wasm] Guard out the use of `libdispatch` types To avoid the use of `libdispatch` types in the `CoreFoundation` module when unavailable --- CoreFoundation/Base.subproj/CFInternal.h | 3 ++- CoreFoundation/Stream.subproj/CFStream.h | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CoreFoundation/Base.subproj/CFInternal.h b/CoreFoundation/Base.subproj/CFInternal.h index 6f99889099..e5cc3840ad 100644 --- a/CoreFoundation/Base.subproj/CFInternal.h +++ b/CoreFoundation/Base.subproj/CFInternal.h @@ -1203,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/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 */ From 8a134e8325b57444e3b97e82278582caf6c9a363 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 14 Feb 2024 12:43:15 +0000 Subject: [PATCH 49/63] [wasm] Grab wasi-libc constants manually Unfortunately they are defined in the way ClangImporter can't handle them, so we need to grab them manually through function calls. Those calls are usually inlined, so the performance impact should be minimal. --- CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h | 11 +++++++++++ Sources/Foundation/FileManager+POSIX.swift | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h index d78eeddf68..c6e63fac8e 100644 --- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h +++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h @@ -64,6 +64,8 @@ #include #include #include +#elif TARGET_OS_WASI +#include #elif TARGET_OS_LINUX #include #include @@ -712,6 +714,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/Sources/Foundation/FileManager+POSIX.swift b/Sources/Foundation/FileManager+POSIX.swift index a69d71e9f7..f2f723fa78 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 { From 7e66e34d799c38497ed07f3176db7542bacc25da Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 7 Mar 2024 18:26:02 +0000 Subject: [PATCH 50/63] [wasm] Port CoreFoundation/NumberDate.subproj This commit adds `TARGET_OS_WASI` as ICU supported platform in `#if` conditions under `NumberDate.subproj`. --- CoreFoundation/NumberDate.subproj/CFDate.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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()); } From 7891776c9d1aa7c1499b91efffe145183f12625a Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 7 Mar 2024 18:27:46 +0000 Subject: [PATCH 51/63] [wasm] Port CoreFoundation/Locale.subproj * Remove no longer needed `#if !TARGET_OS_WASI` * Add WASI to the list of ICU supported platforms --- CoreFoundation/Locale.subproj/CFLocale.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CoreFoundation/Locale.subproj/CFLocale.c b/CoreFoundation/Locale.subproj/CFLocale.c index 738ff28a0b..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 From efc01825039b5d0c59310fc8b59ce483a4b57dd1 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 7 Mar 2024 17:42:11 +0000 Subject: [PATCH 52/63] [wasm] Port CFStream for no-dispatch platforms This patch guards the use of RunLoop, which is not available on no-dispatch platforms. --- CoreFoundation/Stream.subproj/CFStream.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CoreFoundation/Stream.subproj/CFStream.c b/CoreFoundation/Stream.subproj/CFStream.c index 010f69bc13..d264608383 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) { @@ -1469,6 +1479,7 @@ CF_PRIVATE void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, CFRunLoop count--; } +#if __HAS_DISPATCH__ if (count == 0) { CFRunLoopSourceRef source = _CFStreamCopySource(stream); if (source) { @@ -1477,6 +1488,7 @@ CF_PRIVATE void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, CFRunLoop } CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey); } +#endif CFDictionaryRemoveValue(sSharedSources, stream); @@ -1518,6 +1530,7 @@ CF_PRIVATE void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, CFRunLoop __CFBitClear(stream->flags, CALLING_CLIENT); } +#if __HAS_DISPATCH__ /* * If we've got events pending, we need to wake up and signal */ @@ -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) { From 5d81a9ecde97ab35c51422175f37afecd7252c34 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 7 Mar 2024 17:41:12 +0000 Subject: [PATCH 53/63] [wasm] Port CoreFoundation/Parsing.subproj * Remove no longer needed `#if !TARGET_OS_WASI` * Add WASI to the list of ICU supported platforms --- CoreFoundation/Parsing.subproj/CFBinaryPList.c | 4 ---- CoreFoundation/Parsing.subproj/CFPropertyList.c | 6 +----- CoreFoundation/Parsing.subproj/CFPropertyList.h | 4 ---- 3 files changed, 1 insertion(+), 13 deletions(-) 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. */ From 48c5fd496d295e64edd0d4f4941939c65261df8b Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 7 Mar 2024 16:24:23 +0000 Subject: [PATCH 54/63] [wasm] Guard RunLoop.subproj sources with `__HAS_DISPATCH__` --- CoreFoundation/RunLoop.subproj/CFRunLoop.c | 3 +++ CoreFoundation/RunLoop.subproj/CFSocket.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/CoreFoundation/RunLoop.subproj/CFRunLoop.c b/CoreFoundation/RunLoop.subproj/CFRunLoop.c index f202dda2bf..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 @@ -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__ */ From dc551c7fe646e296704fa9013f0b01ca94821d52 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 1 Mar 2024 08:52:39 +0000 Subject: [PATCH 55/63] [wasm] Port CoreFoundation/CMakeLists.txt * CFXMLInterface usually depends on BlocksRuntime through dispatch indirectly, so we need to link it explicitly for no-dispatch builds to include BlocksRuntime headers. * Enable some wasi-libc emulations for building CF. --- CoreFoundation/CMakeLists.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt index 4b3370a90b..11fd5d76e7 100644 --- a/CoreFoundation/CMakeLists.txt +++ b/CoreFoundation/CMakeLists.txt @@ -479,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) @@ -561,6 +566,13 @@ 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 CFXMLInterface From ee05d2d974f337f718ca0e933f6c3711d072a079 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 8 Mar 2024 09:28:17 +0000 Subject: [PATCH 56/63] [wasm] Enable wasi-libc emulations for Foundation This change enables wasi-libc emulations for Foundation and FoundationXML to properly import CoreFoundation, which includes those emulation libraries as a part of public interface. --- Sources/Foundation/CMakeLists.txt | 12 ++++++++++++ Sources/FoundationXML/CMakeLists.txt | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/Sources/Foundation/CMakeLists.txt b/Sources/Foundation/CMakeLists.txt index fbb0b62be6..d7a999f9b8 100644 --- a/Sources/Foundation/CMakeLists.txt +++ b/Sources/Foundation/CMakeLists.txt @@ -225,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/FoundationXML/CMakeLists.txt b/Sources/FoundationXML/CMakeLists.txt index 5a73f70f58..a09d059417 100644 --- a/Sources/FoundationXML/CMakeLists.txt +++ b/Sources/FoundationXML/CMakeLists.txt @@ -43,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) From ddb58bd3ca359b30a7e360e1017c76dbdff0e794 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 8 Mar 2024 09:29:25 +0000 Subject: [PATCH 57/63] [wasm] Exclude some completely unavailable APIs from build --- .../DispatchData+DataProtocol.swift | 3 ++- Sources/Foundation/NSNotification.swift | 4 ++++ Sources/Foundation/NotificationQueue.swift | 3 +++ Sources/Foundation/Operation.swift | 2 ++ Sources/Foundation/Port.swift | 9 +++++++++ Sources/Foundation/Process.swift | 3 +++ Sources/Foundation/Progress.swift | 2 ++ Sources/Foundation/RunLoop.swift | 20 +++++++++++++++++++ Sources/Foundation/Thread.swift | 2 ++ Sources/Foundation/UserDefaults.swift | 4 ++++ 10 files changed, 51 insertions(+), 1 deletion(-) 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/NSNotification.swift b/Sources/Foundation/NSNotification.swift index 82f7536170..ff25a3b136 100644 --- a/Sources/Foundation/NSNotification.swift +++ b/Sources/Foundation/NSNotification.swift @@ -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/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 8d5ac46563..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 @@ -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/Thread.swift b/Sources/Foundation/Thread.swift index 7fbcbb522e..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 @@ -448,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 } } From 7e25bb8f1f6c1971331372246219538e30b510fb Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 8 Mar 2024 09:30:02 +0000 Subject: [PATCH 58/63] [wasm] Port Sources/Foundation/FileHandle.swift * Unsupport background read/write operations * Unsupport Pipe --- Sources/Foundation/FileHandle.swift | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/Sources/Foundation/FileHandle.swift b/Sources/Foundation/FileHandle.swift index 5fb7258ca8..10e6dc9c92 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(). @@ -90,6 +92,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 @@ -213,6 +216,7 @@ open class FileHandle : NSObject { } } } +#endif // canImport(Dispatch) open var availableData: Data { _checkFileHandle() @@ -626,6 +630,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 { @@ -637,6 +642,9 @@ open class FileHandle : NSObject { } else { try block() } +#else + try block() +#endif } @available(swift 5.0) @@ -651,6 +659,7 @@ open class FileHandle : NSObject { guard self != FileHandle._nulldeviceFileHandle else { return } guard _isPlatformHandleValid else { return } + #if canImport(Dispatch) privateAsyncVariablesLock.lock() writabilitySource?.cancel() readabilitySource?.cancel() @@ -659,6 +668,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 @@ -861,6 +871,9 @@ extension FileHandle { } open func readInBackgroundAndNotify(forModes modes: [RunLoop.Mode]?) { +#if !canImport(Dispatch) + NSUnsupported() +#else _checkFileHandle() privateAsyncVariablesLock.lock() @@ -915,6 +928,7 @@ extension FileHandle { operation(data, error) } #endif +#endif // canImport(Dispatch) } open func readToEndOfFileInBackgroundAndNotify() { @@ -922,6 +936,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") } @@ -963,11 +980,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]) @@ -976,7 +994,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 @@ -1014,6 +1032,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 { @@ -1031,6 +1052,7 @@ extension FileHandle { privateAsyncVariablesLock.unlock() owner.resume() +#endif } } @@ -1052,6 +1074,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) @@ -1078,4 +1102,3 @@ open class Pipe: NSObject { super.init() } } - From de93e26574ad05e09487835e2f4faac03bd14701 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 8 Mar 2024 09:30:19 +0000 Subject: [PATCH 59/63] [wasm] Miscellaneous Foundation fixes * Removed too conservative guards * Port `Host` class * Add `arch(wasm32)` to 32-bit arch conditions --- Sources/Foundation/Host.swift | 10 ++++++++++ Sources/Foundation/NSCharacterSet.swift | 2 -- Sources/Foundation/NSKeyedArchiver.swift | 10 ---------- Sources/Foundation/NSPathUtilities.swift | 6 ------ Sources/Foundation/NSString.swift | 4 ---- Sources/Foundation/ScannerAPI.swift | 2 +- 6 files changed, 11 insertions(+), 23 deletions(-) diff --git a/Sources/Foundation/Host.swift b/Sources/Foundation/Host.swift index 5a72373c6d..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 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/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/NSPathUtilities.swift b/Sources/Foundation/NSPathUtilities.swift index 3253845696..91e7ccba44 100644 --- a/Sources/Foundation/NSPathUtilities.swift +++ b/Sources/Foundation/NSPathUtilities.swift @@ -75,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. @@ -433,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 { @@ -536,7 +533,6 @@ extension NSString { return { $0.lowercased().hasPrefix(prefix) } } } -#endif internal func _longestCommonPrefix(_ strings: [String], caseSensitive: Bool) -> String? { guard !strings.isEmpty else { @@ -584,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) 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/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) } From 7226a6e215f6404b3da9e82c40624b47913d551f Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 8 Mar 2024 09:31:12 +0000 Subject: [PATCH 60/63] [wasm] Port Sources/Foundation/NSObjCRuntime.swift --- Sources/Foundation/NSObjCRuntime.swift | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) 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 }() From 90c183256e2f579027dcb873e48c06c9e74d794b Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 8 Mar 2024 09:43:48 +0000 Subject: [PATCH 61/63] [wasm] Import `sys/mman.h` through CoreFoundation Importing `wasi_emulated_mman` in Swift code requires the client to define `_WASI_EMULATED_MMAN`. `@_implementationOnly import` was the only way to work around this, but it's now declared as unsafe if it's used in non-resilient moules (even though it's actually safe as long as the module does not use type layout of the imported module). The new scoped import feature always requires the transitive clients to load privately imported modules, so it's not a good fit for this tricky case where a special macro must be defined before importing the module. This patch imports `sys/mman.h` through CoreFoundation while defining `_WASI_EMULATED_MMAN` in the header exposed by modulemap. This way, the clients don't need to define it. --- CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h | 5 +++++ Sources/Foundation/Data.swift | 5 ----- Sources/Foundation/FileHandle.swift | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h index c6e63fac8e..1a7eb3e073 100644 --- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h +++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h @@ -66,6 +66,11 @@ #include #elif TARGET_OS_WASI #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 diff --git a/Sources/Foundation/Data.swift b/Sources/Foundation/Data.swift index b76fef915c..9e5c9faf38 100644 --- a/Sources/Foundation/Data.swift +++ b/Sources/Foundation/Data.swift @@ -36,11 +36,6 @@ @usableFromInline let memcpy = Musl.memcpy @usableFromInline let memcmp = Musl.memcmp #elseif canImport(WASILibc) -#if swift(>=6.0) -private import wasi_emulated_mman -#else -import wasi_emulated_mman -#endif @usableFromInline let calloc = WASILibc.calloc @usableFromInline let malloc = WASILibc.malloc @usableFromInline let free = WASILibc.free diff --git a/Sources/Foundation/FileHandle.swift b/Sources/Foundation/FileHandle.swift index 5fb7258ca8..6307b300d7 100644 --- a/Sources/Foundation/FileHandle.swift +++ b/Sources/Foundation/FileHandle.swift @@ -29,7 +29,6 @@ fileprivate let _write = Musl.write(_:_:_:) fileprivate let _close = Musl.close(_:) #elseif canImport(WASILibc) import WASILibc -@_implementationOnly import wasi_emulated_mman fileprivate let _read = WASILibc.read(_:_:_:) fileprivate let _write = WASILibc.write(_:_:_:) fileprivate let _close = WASILibc.close(_:) From 44031b5a0e96ad91eada2261db2d3890818fe1d0 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 1 Mar 2024 08:52:21 +0000 Subject: [PATCH 62/63] [wasm] Miscellanous Base.subproj fixes * Remove too conservative include guards * Update class table to exclude unavailable classes * Port mach_absolute_time to WASI platform --- CoreFoundation/Base.subproj/CFPriv.h | 2 -- CoreFoundation/Base.subproj/CFRuntime.c | 2 ++ CoreFoundation/Base.subproj/CoreFoundation_Prefix.h | 2 +- CoreFoundation/Base.subproj/ForFoundationOnly.h | 6 ------ CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h | 9 ++------- .../Base.subproj/SwiftRuntime/CoreFoundation.h | 4 +++- 6 files changed, 8 insertions(+), 17 deletions(-) diff --git a/CoreFoundation/Base.subproj/CFPriv.h b/CoreFoundation/Base.subproj/CFPriv.h index 73292b0986..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 diff --git a/CoreFoundation/Base.subproj/CFRuntime.c b/CoreFoundation/Base.subproj/CFRuntime.c index 68b62a2b26..bdd43eaab8 100644 --- a/CoreFoundation/Base.subproj/CFRuntime.c +++ b/CoreFoundation/Base.subproj/CFRuntime.c @@ -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, diff --git a/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h b/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h index 77678304aa..c1176c765c 100644 --- a/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h +++ b/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h @@ -260,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; 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 1a7eb3e073..73c2898db9 100644 --- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h +++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h @@ -66,6 +66,7 @@ #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 @@ -387,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; @@ -401,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); @@ -451,7 +448,6 @@ CF_EXPORT CFCharacterSetRef _CFCharacterSetCreateCopy(CFAllocatorRef alloc, CFCh 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); @@ -460,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); @@ -566,7 +561,7 @@ 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); 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 From 6a70d034a7cc48ab6d600de2a569c9f5f777ffb4 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Sat, 9 Mar 2024 08:36:38 +0000 Subject: [PATCH 63/63] [wasm] Follow-up dispatch fix for CFStream.c This patch is a follow-up fix for efc01825039b5d0c59310fc8b59ce483a4b57dd1 to fix undefined symbol reference against excluded CFRunLoop APIs. --- CoreFoundation/Stream.subproj/CFStream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CoreFoundation/Stream.subproj/CFStream.c b/CoreFoundation/Stream.subproj/CFStream.c index d264608383..1cfeeb657d 100644 --- a/CoreFoundation/Stream.subproj/CFStream.c +++ b/CoreFoundation/Stream.subproj/CFStream.c @@ -1385,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. @@ -1530,7 +1531,6 @@ CF_PRIVATE void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, CFRunLoop __CFBitClear(stream->flags, CALLING_CLIENT); } -#if __HAS_DISPATCH__ /* * If we've got events pending, we need to wake up and signal */