Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down
13 changes: 9 additions & 4 deletions Sources/CoreFoundation/CFPlatform.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include <mach-o/dyld.h>
#endif

#if TARGET_OS_WASI
#if TARGET_OS_WASI && !defined(__EMSCRIPTEN__)
#include <wasi/libc-environ.h>
#include <wasi/api.h>
#endif
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
13 changes: 8 additions & 5 deletions Sources/CoreFoundation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
15 changes: 14 additions & 1 deletion Sources/CoreFoundation/include/CFTargetConditionals.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@

*/

#if __has_include(<TargetConditionals.h>)
// When cross-compiling for Emscripten or WASI on a macOS host, the system

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid manually wrapping comments in Foundation's sources, thanks.

// 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(<TargetConditionals.h>) && !defined(__EMSCRIPTEN__) && !defined(__wasi__)
#include <TargetConditionals.h>
#else

Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion Sources/CoreFoundation/include/ForSwiftFoundationOnly.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,17 @@
#define _CRT_NONSTDC_NO_DEPRECATE
#include <Windows.h>
#else
#if __has_include(<fts.h>)
#include <fts.h>
#endif
#endif
#if __has_include(<unistd.h>)
#include <unistd.h>
#endif
#if _POSIX_THREADS
#include <pthread.h>
#endif
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__wasi__)
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__wasi__) || defined(__EMSCRIPTEN__)
#include <dirent.h>
#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion Sources/Foundation/FileHandle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(_:_:_:)
Expand Down Expand Up @@ -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
Expand Down
31 changes: 30 additions & 1 deletion Sources/Foundation/FileManager+POSIX.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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?
Expand Down Expand Up @@ -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<FTS>? = nil
var _current : UnsafeMutablePointer<FTSENT>? = nil
#endif
var _rootError : Error? = nil
var _gotRoot : Bool = false

Expand All @@ -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) }
Expand All @@ -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
Expand Down Expand Up @@ -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]? {
Expand Down
2 changes: 2 additions & 0 deletions Sources/Foundation/FileManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import WinSDK

#if os(WASI)
import WASILibc
#elseif os(Emscripten)
@preconcurrency import EmscriptenLibc
#elseif canImport(Bionic)
@preconcurrency import Bionic
#endif
Expand Down
6 changes: 3 additions & 3 deletions Sources/Foundation/Host.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<Int8>.allocate(capacity: Int(NI_MAXHOST))
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Sources/Foundation/JSONSerialization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Foundation/NSArray.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion Sources/Foundation/NSCalendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
24 changes: 13 additions & 11 deletions Sources/Foundation/NSData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//

@_implementationOnly import CoreFoundation
#if !os(WASI)
#if !os(WASI) && !os(Emscripten)
import Dispatch
#endif
#if canImport(Android)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
Loading