diff --git a/CMakeLists.txt b/CMakeLists.txt index 504499d340..4675a80b4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,8 +75,8 @@ if(BUILD_SHARED_LIBS) endif() set(FOUNDATION_BUILD_NETWORKING_default ON) -if(CMAKE_SYSTEM_NAME STREQUAL "WASI") - # Networking is not supported on WASI +if(CMAKE_SYSTEM_NAME STREQUAL "WASI" OR CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + # Networking is not supported on WASI/Emscripten set(FOUNDATION_BUILD_NETWORKING_default OFF) endif() option(FOUNDATION_BUILD_NETWORKING "build FoundationNetworking" @@ -149,8 +149,8 @@ endif() # System dependencies -# We know libdispatch is always unavailable on WASI -if(NOT CMAKE_SYSTEM_NAME STREQUAL "WASI") +# We know libdispatch is always unavailable on WASI and Emscripten +if(NOT CMAKE_SYSTEM_NAME STREQUAL "WASI" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") find_package(LibRT) find_package(dispatch CONFIG) if(NOT dispatch_FOUND) diff --git a/Sources/CoreFoundation/CFPlatform.c b/Sources/CoreFoundation/CFPlatform.c index 2cdac6985e..ab444cc88c 100644 --- a/Sources/CoreFoundation/CFPlatform.c +++ b/Sources/CoreFoundation/CFPlatform.c @@ -22,7 +22,7 @@ #include #endif -#if TARGET_OS_WASI +#if TARGET_OS_WASI && !defined(__EMSCRIPTEN__) #include #include #endif @@ -191,7 +191,7 @@ const char *_CFProcessPath(void) { __CFprogname = __CFProcessPath; } return __CFProcessPath; -#elif TARGET_OS_WASI +#elif TARGET_OS_WASI && !defined(__EMSCRIPTEN__) __wasi_errno_t err; size_t argc; size_t argv_buf_size; @@ -216,6 +216,11 @@ const char *_CFProcessPath(void) { free(argv); return __CFProcessPath; +#elif defined(__EMSCRIPTEN__) + __CFProcessPath = ""; + __CFprogname = __CFProcessPath; + return __CFProcessPath; + #else // TARGET_OS_BSD char *argv0 = NULL; @@ -1883,10 +1888,10 @@ CF_EXPORT char **_CFEnviron(void) { return *_NSGetEnviron(); #elif TARGET_OS_WIN32 return _environ; -#elif TARGET_OS_WASI +#elif TARGET_OS_WASI && !defined(__EMSCRIPTEN__) return __wasilibc_get_environ(); #else -#if TARGET_OS_BSD +#if TARGET_OS_BSD || defined(__EMSCRIPTEN__) extern char **environ; #endif return environ; diff --git a/Sources/CoreFoundation/CMakeLists.txt b/Sources/CoreFoundation/CMakeLists.txt index bb01502580..55d0393d55 100644 --- a/Sources/CoreFoundation/CMakeLists.txt +++ b/Sources/CoreFoundation/CMakeLists.txt @@ -117,13 +117,16 @@ target_precompile_headers(CoreFoundation PRIVATE internalInclude/CoreFoundation_ target_link_libraries(CoreFoundation PRIVATE - _FoundationICU - dispatch) + _FoundationICU) -if(CMAKE_SYSTEM_NAME STREQUAL "WASI") - # On WASI, we use vendored BlocksRuntime instead of the one from libdispatch +if(NOT CMAKE_SYSTEM_NAME STREQUAL "WASI" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + target_link_libraries(CoreFoundation PRIVATE dispatch) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "WASI" OR CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + # On WASI/Emscripten, we use vendored BlocksRuntime instead of the one + # from libdispatch. add_subdirectory(BlockRuntime) - # Add BlocksRuntime object library to CoreFoundation static archive target_link_libraries(CoreFoundation PRIVATE BlocksRuntime) endif() diff --git a/Sources/CoreFoundation/include/CFTargetConditionals.h b/Sources/CoreFoundation/include/CFTargetConditionals.h index ed36cd6479..3047d47a6b 100644 --- a/Sources/CoreFoundation/include/CFTargetConditionals.h +++ b/Sources/CoreFoundation/include/CFTargetConditionals.h @@ -18,7 +18,10 @@ */ -#if __has_include() +// When cross-compiling for Emscripten or WASI on a macOS host, the system +// TargetConditionals.h may be found via __has_include even with --sysroot set. +// Exclude these targets so our custom definitions below are used instead. +#if __has_include() && !defined(__EMSCRIPTEN__) && !defined(__wasi__) #include #else @@ -118,6 +121,16 @@ #define TARGET_OS_ANDROID 0 #define TARGET_OS_CYGWIN 0 #define TARGET_OS_WASI 0 +#elif __EMSCRIPTEN__ +#define TARGET_OS_DARWIN 0 +#define TARGET_OS_LINUX 0 +#define TARGET_OS_WINDOWS 0 +#define TARGET_OS_BSD 0 +#define TARGET_OS_ANDROID 0 +#define TARGET_OS_CYGWIN 0 +// Emscripten shares the same CoreFoundation constraints as WASI +// (no dispatch, no pthread, single-threaded, wasm32). +#define TARGET_OS_WASI 1 #elif __unix__ #define TARGET_OS_DARWIN 0 #define TARGET_OS_LINUX 0 diff --git a/Sources/CoreFoundation/include/ForSwiftFoundationOnly.h b/Sources/CoreFoundation/include/ForSwiftFoundationOnly.h index e2f4ab0586..cbf5e94263 100644 --- a/Sources/CoreFoundation/include/ForSwiftFoundationOnly.h +++ b/Sources/CoreFoundation/include/ForSwiftFoundationOnly.h @@ -38,15 +38,17 @@ #define _CRT_NONSTDC_NO_DEPRECATE #include #else +#if __has_include() #include #endif +#endif #if __has_include() #include #endif #if _POSIX_THREADS #include #endif -#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__wasi__) +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__wasi__) || defined(__EMSCRIPTEN__) #include #endif diff --git a/Sources/CoreFoundation/internalInclude/CoreFoundation_Prefix.h b/Sources/CoreFoundation/internalInclude/CoreFoundation_Prefix.h index 40a0d02adb..c6749a5fbd 100644 --- a/Sources/CoreFoundation/internalInclude/CoreFoundation_Prefix.h +++ b/Sources/CoreFoundation/internalInclude/CoreFoundation_Prefix.h @@ -17,7 +17,7 @@ #include "CFTargetConditionals.h" #include "CFAvailability.h" -#if TARGET_OS_WASI +#if TARGET_OS_WASI || defined(__EMSCRIPTEN__) #define __HAS_DISPATCH__ 0 #else #define __HAS_DISPATCH__ 1 diff --git a/Sources/Foundation/FileHandle.swift b/Sources/Foundation/FileHandle.swift index 588734dc19..e7873a8fe3 100644 --- a/Sources/Foundation/FileHandle.swift +++ b/Sources/Foundation/FileHandle.swift @@ -34,6 +34,11 @@ import WASILibc fileprivate let _read = WASILibc.read(_:_:_:) fileprivate let _write = WASILibc.write(_:_:_:) fileprivate let _close = WASILibc.close(_:) +#elseif canImport(EmscriptenLibc) +@preconcurrency import EmscriptenLibc +fileprivate let _read = EmscriptenLibc.read(_:_:_:) +fileprivate let _write = EmscriptenLibc.write(_:_:_:) +fileprivate let _close = EmscriptenLibc.close(_:) #elseif canImport(Android) @preconcurrency import Android fileprivate let _read = Android.read(_:_:_:) @@ -1074,7 +1079,7 @@ open class Pipe: NSObject, @unchecked Sendable { closeOnDealloc: true) self.fileHandleForWriting = FileHandle(handle: hWritePipe!, closeOnDealloc: true) -#elseif os(WASI) +#elseif os(WASI) || os(Emscripten) NSUnsupported() #else /// the `pipe` system call creates two `fd` in a malloc'ed area diff --git a/Sources/Foundation/FileManager+POSIX.swift b/Sources/Foundation/FileManager+POSIX.swift index 44eb0ae344..e9e7f41fe7 100644 --- a/Sources/Foundation/FileManager+POSIX.swift +++ b/Sources/Foundation/FileManager+POSIX.swift @@ -145,6 +145,9 @@ extension FileManager { } fd += 1 } +#elseif os(Emscripten) + // Emscripten doesn't have WASI preopens or getfsstat + return nil #else #error("Requires a platform-specific implementation") #endif @@ -153,8 +156,11 @@ extension FileManager { internal func _attributesOfFileSystemIncludingBlockSize(forPath path: String) throws -> (attributes: [FileAttributeKey : Any], blockSize: UInt64?) { #if os(WASI) - // WASI doesn't have statvfs + // WASI does not have statvfs throw _NSErrorWithErrno(ENOTSUP, reading: true, path: path) + #elseif os(Emscripten) + // Emscripten does not have statvfs + throw _NSErrorWithErrno(EmscriptenLibc.ENOTSUP, reading: true, path: path) #else var result: [FileAttributeKey:Any] = [:] var finalBlockSize: UInt64? @@ -315,8 +321,10 @@ extension FileManager { var _url : URL var _options : FileManager.DirectoryEnumerationOptions var _errorHandler : ((URL, Error) -> Bool)? +#if !os(Emscripten) // Emscripten doesn't have fts.h var _stream : UnsafeMutablePointer? = nil var _current : UnsafeMutablePointer? = nil +#endif var _rootError : Error? = nil var _gotRoot : Bool = false @@ -327,6 +335,9 @@ extension FileManager { _options = options _errorHandler = errorHandler +#if os(Emscripten) + _rootError = _NSErrorWithErrno(ENOSYS, reading: true, url: url) +#else let fm = FileManager.default do { guard fm.fileExists(atPath: _url.path) else { throw _NSErrorWithErrno(ENOENT, reading: true, url: url) } @@ -343,15 +354,26 @@ extension FileManager { } catch { _rootError = error } +#endif } deinit { +#if !os(Emscripten) if let stream = _stream { fts_close(stream) } +#endif } override func nextObject() -> Any? { +#if os(Emscripten) + if let error = _rootError { + if let handler = _errorHandler { + let _ = handler(_url, error) + } + } + return nil +#else func match(filename: String, to options: DirectoryEnumerationOptions, isDir: Bool) -> (Bool, Bool) { var showFile = true var skipDescendants = false @@ -424,16 +446,23 @@ extension FileManager { } } return nil +#endif // !os(Emscripten) } override var level: Int { +#if os(Emscripten) + return 0 +#else return Int(_current?.pointee.fts_level ?? 0) +#endif } override func skipDescendants() { +#if !os(Emscripten) if let stream = _stream, let current = _current { fts_set(stream, current, FTS_SKIP) } +#endif } override var directoryAttributes : [FileAttributeKey : Any]? { diff --git a/Sources/Foundation/FileManager.swift b/Sources/Foundation/FileManager.swift index fff9fd906e..d0025d54a5 100644 --- a/Sources/Foundation/FileManager.swift +++ b/Sources/Foundation/FileManager.swift @@ -21,6 +21,8 @@ import WinSDK #if os(WASI) import WASILibc +#elseif os(Emscripten) +@preconcurrency import EmscriptenLibc #elseif canImport(Bionic) @preconcurrency import Bionic #endif diff --git a/Sources/Foundation/Host.swift b/Sources/Foundation/Host.swift index 1a4aeb415e..4b84cb1d0b 100644 --- a/Sources/Foundation/Host.swift +++ b/Sources/Foundation/Host.swift @@ -95,7 +95,7 @@ open class Host: NSObject { return "localhost" } return String(cString: hostname) -#elseif os(WASI) // WASI does not have uname +#elseif os(WASI) || os(Emscripten) // WASI/Emscripten do not have uname return "localhost" #else let hname = UnsafeMutablePointer.allocate(capacity: Int(NI_MAXHOST)) @@ -176,7 +176,7 @@ open class Host: NSObject { } _names = [info] _resolved = true -#elseif os(WASI) // WASI does not have getifaddrs +#elseif os(WASI) || os(Emscripten) // WASI/Emscripten do not have getifaddrs _names = [info] _resolved = true #else @@ -276,7 +276,7 @@ open class Host: NSObject { _resolved = true } -#elseif os(WASI) // WASI does not have getaddrinfo +#elseif os(WASI) || os(Emscripten) // WASI/Emscripten do not have getaddrinfo if let info = _info { _names = [info] _resolved = true diff --git a/Sources/Foundation/JSONSerialization.swift b/Sources/Foundation/JSONSerialization.swift index 7e2674cc1e..50591d8c07 100644 --- a/Sources/Foundation/JSONSerialization.swift +++ b/Sources/Foundation/JSONSerialization.swift @@ -274,7 +274,7 @@ open class JSONSerialization : NSObject { } -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) /* Write JSON data into a stream. The stream should be opened and configured. The return value is the number of bytes written to the stream, or 0 on error. All other behavior of this method is the same as the dataWithJSONObject:options:error: method. */ open class func writeJSONObject(_ obj: Any, toStream stream: OutputStream, options opt: WritingOptions) throws -> Int { diff --git a/Sources/Foundation/NSArray.swift b/Sources/Foundation/NSArray.swift index 5d4699e3c2..666f196e56 100644 --- a/Sources/Foundation/NSArray.swift +++ b/Sources/Foundation/NSArray.swift @@ -446,7 +446,7 @@ open class NSArray : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NSCo return objects } -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) open func write(to url: URL) throws { let pListData = try PropertyListSerialization.data(fromPropertyList: self, format: .xml, options: 0) try pListData.write(to: url, options: .atomic) diff --git a/Sources/Foundation/NSCalendar.swift b/Sources/Foundation/NSCalendar.swift index 465912e6a5..7afad823d5 100644 --- a/Sources/Foundation/NSCalendar.swift +++ b/Sources/Foundation/NSCalendar.swift @@ -866,7 +866,7 @@ open class NSCalendar : NSObject, NSCopying, NSSecureCoding { } -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) // This notification is posted through [NSNotificationCenter defaultCenter] // when the system day changes. Register with "nil" as the object of this // notification. If the computer/device is asleep when the day changed, diff --git a/Sources/Foundation/NSData.swift b/Sources/Foundation/NSData.swift index 27e1f9c61c..daad6d4901 100644 --- a/Sources/Foundation/NSData.swift +++ b/Sources/Foundation/NSData.swift @@ -8,7 +8,7 @@ // @_implementationOnly import CoreFoundation -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) import Dispatch #endif #if canImport(Android) @@ -272,7 +272,7 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { return isEqual(to: data._swiftObject) } -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) if let data = value as? DispatchData { if data.count != length { return false @@ -430,10 +430,10 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { } let fm = FileManager.default -#if os(WASI) - // WASI does not have permission concept +#if os(WASI) || os(Emscripten) + // WASI/Emscripten do not have permission concept let permissions: Int? = nil - // ReadingOptions.atomic won't be specified on WASI as it's marked unavailable + // ReadingOptions.atomic won't be specified as it's marked unavailable var atomicWrite: Bool { false } #else let permissions = try? fm.attributesOfItem(atPath: path)[.posixPermissions] as? Int @@ -475,6 +475,8 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { let createMode = Int(Musl.S_IRUSR) | Int(Musl.S_IWUSR) | Int(Musl.S_IRGRP) | Int(Musl.S_IWGRP) | Int(Musl.S_IROTH) | Int(Musl.S_IWOTH) #elseif canImport(WASILibc) let createMode = Int(WASILibc.S_IRUSR) | Int(WASILibc.S_IWUSR) | Int(WASILibc.S_IRGRP) | Int(WASILibc.S_IWGRP) | Int(WASILibc.S_IROTH) | Int(WASILibc.S_IWOTH) +#elseif canImport(EmscriptenLibc) + let createMode = Int(EmscriptenLibc.S_IRUSR) | Int(EmscriptenLibc.S_IWUSR) | Int(EmscriptenLibc.S_IRGRP) | Int(EmscriptenLibc.S_IWGRP) | Int(EmscriptenLibc.S_IROTH) | Int(EmscriptenLibc.S_IWOTH) #elseif canImport(Android) let createMode = Int(Android.S_IRUSR) | Int(Android.S_IWUSR) | Int(Android.S_IRGRP) | Int(Android.S_IWGRP) | Int(Android.S_IROTH) | Int(Android.S_IWOTH) #endif @@ -490,11 +492,11 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { /// Writes the data object's bytes to the file specified by a given path. /// NOTE: the 'atomically' flag is ignored if the url is not of a type the supports atomic writes - #if os(WASI) - @available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories") + #if os(WASI) || os(Emscripten) + @available(*, unavailable, message: "Atomic file-writing is not available on this platform") #endif open func write(toFile path: String, atomically useAuxiliaryFile: Bool) -> Bool { - #if os(WASI) + #if os(WASI) || os(Emscripten) // WASI does not support atomic file-writing as it does not have temporary directories return false #else @@ -509,11 +511,11 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { /// Writes the data object's bytes to the location specified by a given URL. /// NOTE: the 'atomically' flag is ignored if the url is not of a type the supports atomic writes - #if os(WASI) - @available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories") + #if os(WASI) || os(Emscripten) + @available(*, unavailable, message: "Atomic file-writing is not available on this platform") #endif open func write(to url: URL, atomically: Bool) -> Bool { - #if os(WASI) + #if os(WASI) || os(Emscripten) // WASI does not support atomic file-writing as it does not have temporary directories return false #else diff --git a/Sources/Foundation/NSDictionary.swift b/Sources/Foundation/NSDictionary.swift index 5cf7a45fef..bb2ec9262e 100644 --- a/Sources/Foundation/NSDictionary.swift +++ b/Sources/Foundation/NSDictionary.swift @@ -10,7 +10,7 @@ @_implementationOnly import CoreFoundation -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) import Dispatch #endif @@ -505,7 +505,7 @@ open class NSDictionary : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, return objects } -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) open func write(toFile path: String, atomically useAuxiliaryFile: Bool) -> Bool { return write(to: URL(fileURLWithPath: path), atomically: useAuxiliaryFile) } diff --git a/Sources/Foundation/NSIndexSet.swift b/Sources/Foundation/NSIndexSet.swift index 80458c9361..f660da72b3 100644 --- a/Sources/Foundation/NSIndexSet.swift +++ b/Sources/Foundation/NSIndexSet.swift @@ -7,7 +7,7 @@ // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) import Dispatch #endif diff --git a/Sources/Foundation/NSKeyedUnarchiver.swift b/Sources/Foundation/NSKeyedUnarchiver.swift index cf7f0fe345..53ed7c546c 100644 --- a/Sources/Foundation/NSKeyedUnarchiver.swift +++ b/Sources/Foundation/NSKeyedUnarchiver.swift @@ -54,7 +54,7 @@ open class NSKeyedUnarchiver : NSCoder { private enum Stream { case data(Data) -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) case stream(CFReadStream) #endif } @@ -96,7 +96,7 @@ open class NSKeyedUnarchiver : NSCoder { return try? unarchiveTopLevelObjectWithData(data) } -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) @available(swift, deprecated: 9999, renamed: "unarchivedObject(ofClass:from:)") open class func unarchiveObject(withFile path: String) -> Any? { let url = URL(fileURLWithPath: path) @@ -150,7 +150,7 @@ open class NSKeyedUnarchiver : NSCoder { switch self._stream { case .data(let data): try plist = PropertyListSerialization.propertyList(from: data, options: [], format: &format) -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) case .stream(let readStream): try plist = PropertyListSerialization.propertyList(with: readStream, options: [], format: &format) #endif diff --git a/Sources/Foundation/NSLocale.swift b/Sources/Foundation/NSLocale.swift index 10db78977f..ac159b10d9 100644 --- a/Sources/Foundation/NSLocale.swift +++ b/Sources/Foundation/NSLocale.swift @@ -375,7 +375,7 @@ extension NSLocale { } -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) extension NSLocale { public static let currentLocaleDidChangeNotification = NSNotification.Name(rawValue: "kCFLocaleCurrentLocaleDidChangeNotification") } diff --git a/Sources/Foundation/NSObjCRuntime.swift b/Sources/Foundation/NSObjCRuntime.swift index 4966547880..7dae0c335c 100644 --- a/Sources/Foundation/NSObjCRuntime.swift +++ b/Sources/Foundation/NSObjCRuntime.swift @@ -310,10 +310,10 @@ internal let _NSClassesRenamedByObjCAPINotes: [(class: AnyClass, objCName: Strin (UnitVolume.self, "NSUnitVolume"), (UnitTemperature.self, "NSUnitTemperature"), ] -#if !(os(iOS) || os(Android) || os(WASI)) +#if !(os(iOS) || os(Android) || os(WASI) || os(Emscripten)) map.append((Process.self, "NSTask")) #endif -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) map += [ (NotificationQueue.self, "NSNotificationQueue"), (Operation.self, "NSOperation"), diff --git a/Sources/Foundation/NSObject.swift b/Sources/Foundation/NSObject.swift index 33ca6e0620..a41d332088 100644 --- a/Sources/Foundation/NSObject.swift +++ b/Sources/Foundation/NSObject.swift @@ -10,7 +10,7 @@ // @_exported import of Dispatch here makes it available to all // classes in Foundation and all sources that import Foundation. // This brings it into line with Darwin usage for compatibility. -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) @_exported import Dispatch #endif diff --git a/Sources/Foundation/NSPathUtilities.swift b/Sources/Foundation/NSPathUtilities.swift index 0c1c163adc..147587e202 100644 --- a/Sources/Foundation/NSPathUtilities.swift +++ b/Sources/Foundation/NSPathUtilities.swift @@ -14,6 +14,8 @@ import WinSDK @preconcurrency import Android #elseif os(WASI) import WASILibc +#elseif os(Emscripten) +@preconcurrency import EmscriptenLibc #endif #if os(Windows) @@ -664,6 +666,9 @@ internal func _NSCreateTemporaryFile(_ filePath: String) throws -> (Int32, Strin #elseif os(WASI) // WASI does not have temp directories throw NSError(domain: NSPOSIXErrorDomain, code: Int(ENOTSUP)) +#elseif os(Emscripten) + // Emscripten does not have temp directories + throw NSError(domain: NSPOSIXErrorDomain, code: Int(EmscriptenLibc.ENOTSUP)) #else var template = URL(fileURLWithPath: filePath) diff --git a/Sources/Foundation/NSPlatform.swift b/Sources/Foundation/NSPlatform.swift index 522375bef9..25a274eec0 100644 --- a/Sources/Foundation/NSPlatform.swift +++ b/Sources/Foundation/NSPlatform.swift @@ -22,7 +22,7 @@ fileprivate var _NSPageSize: Int { GetSystemInfo(&siInfo) return Int(siInfo.dwPageSize) } -#elseif os(WASI) +#elseif os(WASI) || os(Emscripten) // WebAssembly defines a fixed page size fileprivate let _NSPageSize: Int = 65_536 #endif diff --git a/Sources/Foundation/NSString.swift b/Sources/Foundation/NSString.swift index a9dfdb62ed..71dc2fa5be 100644 --- a/Sources/Foundation/NSString.swift +++ b/Sources/Foundation/NSString.swift @@ -1266,11 +1266,11 @@ extension NSString { data = mData } - #if os(WASI) - @available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories") + #if os(WASI) || os(Emscripten) + @available(*, unavailable, message: "Atomic file-writing is not available on this platform") #endif internal func _writeTo(_ url: URL, _ useAuxiliaryFile: Bool, _ enc: UInt) throws { - #if os(WASI) + #if os(WASI) || os(Emscripten) throw CocoaError(.featureUnsupported) #else var data = Data() @@ -1279,8 +1279,8 @@ extension NSString { #endif } - #if os(WASI) - @available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories") + #if os(WASI) || os(Emscripten) + @available(*, unavailable, message: "Atomic file-writing is not available on this platform") #endif public func write(to url: URL, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws { #if os(WASI) @@ -1290,8 +1290,8 @@ extension NSString { #endif } - #if os(WASI) - @available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories") + #if os(WASI) || os(Emscripten) + @available(*, unavailable, message: "Atomic file-writing is not available on this platform") #endif public func write(toFile path: String, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws { #if os(WASI) diff --git a/Sources/Foundation/NSSwiftRuntime.swift b/Sources/Foundation/NSSwiftRuntime.swift index 1276a03b80..b91909d2aa 100644 --- a/Sources/Foundation/NSSwiftRuntime.swift +++ b/Sources/Foundation/NSSwiftRuntime.swift @@ -23,11 +23,13 @@ internal import Synchronization @_exported @preconcurrency import Bionic #elseif os(WASI) @_exported import WASILibc +#elseif os(Emscripten) +@_exported @preconcurrency import EmscriptenLibc #elseif os(Windows) @_exported import CRT #endif -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) @_exported import Dispatch #endif @@ -267,7 +269,7 @@ internal func __CFInitializeSwift() { __CFSwiftBridge.NSMutableString.appendCharacters = _CFSwiftStringAppendCharacters __CFSwiftBridge.NSMutableString._cfAppendCString = _CFSwiftStringAppendCString -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) __CFSwiftBridge.NSRunLoop._new = _NSRunLoopNew #endif @@ -303,7 +305,7 @@ internal func __CFInitializeSwift() { // __CFDefaultEightBitStringEncoding = UInt32(kCFStringEncodingUTF8) -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) __CFSwiftBridge.NSURL.copyResourcePropertyForKey = _CFSwiftURLCopyResourcePropertyForKey __CFSwiftBridge.NSURL.copyResourcePropertiesForKeys = _CFSwiftURLCopyResourcePropertiesForKeys __CFSwiftBridge.NSURL.setResourcePropertyForKey = _CFSwiftURLSetResourcePropertyForKey diff --git a/Sources/Foundation/Port.swift b/Sources/Foundation/Port.swift index 9e7bcfb31b..b4f5bf0ec4 100644 --- a/Sources/Foundation/Port.swift +++ b/Sources/Foundation/Port.swift @@ -90,7 +90,7 @@ public protocol PortDelegate: AnyObject { func handle(_ message: PortMessage) } -#if os(WASI) +#if os(WASI) || os(Emscripten) @available(*, unavailable, message: "SocketPort is not available on this platform.") open class SocketPort: Port {} diff --git a/Sources/Foundation/PropertyListSerialization.swift b/Sources/Foundation/PropertyListSerialization.swift index 5c56c9b3ec..193e3fc2e1 100644 --- a/Sources/Foundation/PropertyListSerialization.swift +++ b/Sources/Foundation/PropertyListSerialization.swift @@ -73,7 +73,7 @@ open class PropertyListSerialization : NSObject { } } -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) internal final class func propertyList(with stream: CFReadStream, options opt: ReadOptions, format: UnsafeMutablePointer ?) throws -> Any { var fmt = kCFPropertyListBinaryFormat_v1_0 var error: Unmanaged? = nil diff --git a/Sources/Foundation/Thread.swift b/Sources/Foundation/Thread.swift index 7d7dda2da8..de57ff4c3c 100644 --- a/Sources/Foundation/Thread.swift +++ b/Sources/Foundation/Thread.swift @@ -206,12 +206,12 @@ open class Thread : NSObject { #endif } - #if os(WASI) - @available(*, unavailable, message: "exit() is not available on WASI") + #if os(WASI) || os(Emscripten) + @available(*, unavailable, message: "exit() is not available on this platform") #endif @available(*, noasync) open class func exit() { -#if !os(WASI) +#if !os(WASI) && !os(Emscripten) Thread.current._status = .finished #if os(Windows) ExitThread(0) @@ -258,7 +258,7 @@ open class Thread : NSObject { #if !os(Windows) let _ = withUnsafeMutablePointer(to: &_attr) { attr in pthread_attr_init(attr) - #if !os(WASI) // WASI does not support scheduling contention scope + #if !os(WASI) && !os(Emscripten) // WASI/Emscripten do not support scheduling contention scope pthread_attr_setscope(attr, Int32(PTHREAD_SCOPE_SYSTEM)) #endif pthread_attr_setdetachstate(attr, Int32(PTHREAD_CREATE_DETACHED)) @@ -403,7 +403,7 @@ open class Thread : NSObject { let maxSupportedStackDepth = 128; let addrs = UnsafeMutablePointer.allocate(capacity: maxSupportedStackDepth) defer { addrs.deallocate() } -#if os(Android) || os(OpenBSD) || canImport(Musl) || os(WASI) +#if os(Android) || os(OpenBSD) || canImport(Musl) || os(WASI) || os(Emscripten) let count = 0 #elseif os(Windows) let count = RtlCaptureStackBackTrace(0, DWORD(maxSupportedStackDepth), @@ -426,7 +426,7 @@ open class Thread : NSObject { } open class var callStackSymbols: [String] { -#if os(Android) || os(OpenBSD) || canImport(Musl) || os(WASI) +#if os(Android) || os(OpenBSD) || canImport(Musl) || os(WASI) || os(Emscripten) return [] #elseif os(Windows) let hProcess: HANDLE = GetCurrentProcess() diff --git a/Sources/_CFXMLInterface/CMakeLists.txt b/Sources/_CFXMLInterface/CMakeLists.txt index 80c7520594..4ca87ce67b 100644 --- a/Sources/_CFXMLInterface/CMakeLists.txt +++ b/Sources/_CFXMLInterface/CMakeLists.txt @@ -29,10 +29,13 @@ target_compile_options(_CFXMLInterface PRIVATE "SHELL:$<$:${_Foundation_common_build_flags}>") target_link_libraries(_CFXMLInterface PRIVATE - dispatch LibXml2::LibXml2) -if(CMAKE_SYSTEM_NAME STREQUAL "WASI") +if(NOT CMAKE_SYSTEM_NAME STREQUAL "WASI" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + target_link_libraries(_CFXMLInterface PRIVATE dispatch) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "WASI" OR CMAKE_SYSTEM_NAME STREQUAL "Emscripten") target_link_libraries(_CFXMLInterface PRIVATE BlocksRuntime) endif()