Skip to content

6.0: Fix WASI support #825

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Aug 29, 2024
Merged
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: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -116,6 +116,14 @@ foreach(version ${_SwiftFoundation_versions})
endforeach()
endforeach()

# wasi-libc emulation feature flags
set(_SwiftFoundation_wasi_libc_flags)
if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
list(APPEND _SwiftFoundation_wasi_libc_flags
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xcc -D_WASI_EMULATED_SIGNAL>"
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xcc -D_WASI_EMULATED_MMAN>")
endif()

include(GNUInstallDirs)
include(SwiftFoundationSwiftSupport)

35 changes: 26 additions & 9 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -70,6 +70,11 @@ var dependencies: [Package.Dependency] {
}
}

let wasiLibcCSettings: [CSetting] = [
.define("_WASI_EMULATED_SIGNAL", .when(platforms: [.wasi])),
.define("_WASI_EMULATED_MMAN", .when(platforms: [.wasi])),
]

let package = Package(
name: "FoundationPreview",
platforms: [.macOS("13.3"), .iOS("16.4"), .tvOS("16.4"), .watchOS("9.4")],
@@ -91,15 +96,23 @@ let package = Package(
path: "Sources/Foundation"),

// _FoundationCShims (Internal)
.target(name: "_FoundationCShims",
cSettings: [.define("_CRT_SECURE_NO_WARNINGS",
.when(platforms: [.windows]))]),
.target(
name: "_FoundationCShims",
cSettings: [
.define("_CRT_SECURE_NO_WARNINGS", .when(platforms: [.windows]))
] + wasiLibcCSettings
),

// TestSupport (Internal)
.target(name: "TestSupport", dependencies: [
"FoundationEssentials",
"FoundationInternationalization",
], swiftSettings: availabilityMacros + concurrencyChecking),
.target(
name: "TestSupport",
dependencies: [
"FoundationEssentials",
"FoundationInternationalization",
],
cSettings: wasiLibcCSettings,
swiftSettings: availabilityMacros + concurrencyChecking
),

// FoundationEssentials
.target(
@@ -130,11 +143,14 @@ let package = Package(
],
cSettings: [
.define("_GNU_SOURCE", .when(platforms: [.linux]))
],
] + wasiLibcCSettings,
swiftSettings: [
.enableExperimentalFeature("VariadicGenerics"),
.enableExperimentalFeature("AccessLevelOnImport")
] + availabilityMacros + concurrencyChecking
] + availabilityMacros + concurrencyChecking,
linkerSettings: [
.linkedLibrary("wasi-emulated-getpid", .when(platforms: [.wasi])),
]
),
.testTarget(
name: "FoundationEssentialsTests",
@@ -166,6 +182,7 @@ let package = Package(
"CMakeLists.txt",
"Predicate/CMakeLists.txt"
],
cSettings: wasiLibcCSettings,
swiftSettings: [
.enableExperimentalFeature("AccessLevelOnImport")
] + availabilityMacros + concurrencyChecking
1 change: 1 addition & 0 deletions Sources/FoundationEssentials/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -65,6 +65,7 @@ target_compile_options(FoundationEssentials PRIVATE
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-experimental-feature -Xfrontend StrictConcurrency>"
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-upcoming-feature -Xfrontend InferSendableFromCaptures>")
target_compile_options(FoundationEssentials PRIVATE ${_SwiftFoundation_availability_macros})
target_compile_options(FoundationEssentials PRIVATE ${_SwiftFoundation_wasi_libc_flags})
target_compile_options(FoundationEssentials PRIVATE -package-name "SwiftFoundation")

target_link_libraries(FoundationEssentials PUBLIC
2 changes: 2 additions & 0 deletions Sources/FoundationEssentials/Calendar/Calendar.swift
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ import Glibc
import Musl
#elseif canImport(CRT)
import CRT
#elseif os(WASI)
import WASILibc
#endif

#if FOUNDATION_FRAMEWORK
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ import Glibc
import Musl
#elseif canImport(CRT)
import CRT
#elseif os(WASI)
import WASILibc
#endif


2 changes: 2 additions & 0 deletions Sources/FoundationEssentials/Data/Data+Reading.swift
Original file line number Diff line number Diff line change
@@ -27,6 +27,8 @@ import Musl
#elseif os(Windows)
import CRT
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

func _fgetxattr(_ fd: Int32, _ name: UnsafePointer<CChar>!, _ value: UnsafeMutableRawPointer!, _ size: Int, _ position: UInt32, _ options: Int32) -> Int {
9 changes: 9 additions & 0 deletions Sources/FoundationEssentials/Data/Data+Writing.swift
Original file line number Diff line number Diff line change
@@ -29,6 +29,8 @@ import Musl
#elseif os(Windows)
import CRT
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

#if !NO_FILESYSTEM
@@ -129,6 +131,10 @@ private func cleanupTemporaryDirectory(at inPath: String?) {

/// Caller is responsible for calling `close` on the `Int32` file descriptor.
private func createTemporaryFile(at destinationPath: String, inPath: PathOrURL, prefix: String, options: Data.WritingOptions) throws -> (Int32, String) {
#if os(WASI)
// WASI does not have temp directories
throw CocoaError(.featureUnsupported)
#else
var directoryPath = destinationPath
if !directoryPath.isEmpty && directoryPath.last! != "/" {
directoryPath.append("/")
@@ -183,6 +189,7 @@ private func createTemporaryFile(at destinationPath: String, inPath: PathOrURL,
}
}
} while true
#endif // os(WASI)
}

/// Returns `(file descriptor, temporary file path, temporary directory path)`
@@ -516,6 +523,7 @@ private func writeToFileAux(path inPath: PathOrURL, buffer: UnsafeRawBufferPoint

cleanupTemporaryDirectory(at: temporaryDirectoryPath)

#if !os(WASI) // WASI does not support fchmod for now
if let mode {
// Try to change the mode if the path has not changed. Do our best, but don't report an error.
#if FOUNDATION_FRAMEWORK
@@ -539,6 +547,7 @@ private func writeToFileAux(path inPath: PathOrURL, buffer: UnsafeRawBufferPoint
fchmod(fd, mode)
#endif
}
#endif // os(WASI)
}
}
}
14 changes: 8 additions & 6 deletions Sources/FoundationEssentials/Data/Data.swift
Original file line number Diff line number Diff line change
@@ -76,6 +76,8 @@ import Glibc
import Musl
#elseif canImport(ucrt)
import ucrt
#elseif canImport(WASILibc)
import WASILibc
#endif

#if os(Windows)
@@ -580,11 +582,11 @@ public struct Data : Equatable, Hashable, RandomAccessCollection, MutableCollect
@usableFromInline
@frozen
internal struct InlineData : Sendable {
#if arch(x86_64) || arch(arm64) || arch(s390x) || arch(powerpc64) || arch(powerpc64le)
#if _pointerBitWidth(_64)
@usableFromInline typealias Buffer = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) //len //enum
@usableFromInline var bytes: Buffer
#elseif arch(i386) || arch(arm) || arch(arm64_32)
#elseif _pointerBitWidth(_32)
@usableFromInline typealias Buffer = (UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8) //len //enum
@usableFromInline var bytes: Buffer
@@ -615,9 +617,9 @@ public struct Data : Equatable, Hashable, RandomAccessCollection, MutableCollect
@inlinable // This is @inlinable as a trivial initializer.
init(count: Int = 0) {
assert(count <= MemoryLayout<Buffer>.size)
#if arch(x86_64) || arch(arm64) || arch(s390x) || arch(powerpc64) || arch(powerpc64le)
#if _pointerBitWidth(_64)
bytes = (UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0))
#elseif arch(i386) || arch(arm) || arch(arm64_32)
#elseif _pointerBitWidth(_32)
bytes = (UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0))
#else
#error ("Unsupported architecture: initialization for Buffer is required for this architecture")
@@ -802,9 +804,9 @@ public struct Data : Equatable, Hashable, RandomAccessCollection, MutableCollect
}
}

#if arch(x86_64) || arch(arm64) || arch(s390x) || arch(powerpc64) || arch(powerpc64le)
#if _pointerBitWidth(_64)
@usableFromInline internal typealias HalfInt = Int32
#elseif arch(i386) || arch(arm) || arch(arm64_32)
#elseif _pointerBitWidth(_32)
@usableFromInline internal typealias HalfInt = Int16
#else
#error ("Unsupported architecture: a definition of half of the pointer sized Int needs to be defined for this architecture")
2 changes: 2 additions & 0 deletions Sources/FoundationEssentials/Date.swift
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ import Glibc
import Musl
#elseif canImport(WinSDK)
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

#if !FOUNDATION_FRAMEWORK
2 changes: 2 additions & 0 deletions Sources/FoundationEssentials/Decimal/Decimal+Math.swift
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ import Glibc
import Musl
#elseif canImport(CRT)
import CRT
#elseif os(WASI)
import WASILibc
#endif

private let powerOfTen: [Decimal.VariableLengthInteger] = [
2 changes: 2 additions & 0 deletions Sources/FoundationEssentials/Error/CocoaError+FilePath.swift
Original file line number Diff line number Diff line change
@@ -24,6 +24,8 @@ import Musl
#elseif os(Windows)
import CRT
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

extension CocoaError.Code {
4 changes: 4 additions & 0 deletions Sources/FoundationEssentials/Error/ErrorCodes+POSIX.swift
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@
#elseif os(Windows)
import CRT
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

#if FOUNDATION_FRAMEWORK
@@ -467,11 +469,13 @@ extension POSIXError {
return .ESTALE
}

#if !os(WASI)
/// Too many levels of remote in path.
public static var EREMOTE: POSIXErrorCode {
return .EREMOTE
}
#endif
#endif

#if canImport(Darwin)
/// RPC struct is bad.
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@ import Musl
#elseif os(Windows)
import CRT
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

#if os(Windows)
Original file line number Diff line number Diff line change
@@ -28,6 +28,8 @@ import Musl
#elseif os(Windows)
import CRT
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

internal import _FoundationCShims
23 changes: 20 additions & 3 deletions Sources/FoundationEssentials/FileManager/FileManager+Files.swift
Original file line number Diff line number Diff line change
@@ -29,6 +29,9 @@ internal import _FoundationCShims
#elseif os(Windows)
import CRT
import WinSDK
#elseif os(WASI)
internal import _FoundationCShims
import WASILibc
#endif

extension Date {
@@ -471,7 +474,7 @@ extension _FileManagerImpl {
parent = fileManager.currentDirectoryPath
}

#if os(Windows)
#if os(Windows) || os(WASI)
return fileManager.isWritableFile(atPath: parent) && fileManager.isWritableFile(atPath: path)
#else
guard fileManager.isWritableFile(atPath: parent),
@@ -494,7 +497,7 @@ extension _FileManagerImpl {
#endif
}

#if !os(Windows)
#if !os(Windows) && !os(WASI)
private func _extendedAttribute(_ key: UnsafePointer<CChar>, at path: UnsafePointer<CChar>, followSymlinks: Bool) throws -> Data? {
#if canImport(Darwin)
var size = getxattr(path, key, nil, 0, 0, followSymlinks ? 0 : XATTR_NOFOLLOW)
@@ -648,10 +651,11 @@ extension _FileManagerImpl {

var attributes = statAtPath.fileAttributes
try? Self._catInfo(for: URL(filePath: path, directoryHint: .isDirectory), statInfo: statAtPath, into: &attributes)

#if !os(WASI) // WASI does not support extended attributes
if let extendedAttrs = try? _extendedAttributes(at: fsRep, followSymlinks: false) {
attributes[._extendedAttributes] = extendedAttrs
}
#endif

#if !targetEnvironment(simulator) && FOUNDATION_FRAMEWORK
if statAtPath.isRegular || statAtPath.isDirectory {
@@ -713,6 +717,9 @@ extension _FileManagerImpl {
]
}
}
#elseif os(WASI)
// WASI does not support file system attributes
return [:]
#else
try fileManager.withFileSystemRepresentation(for: path) { rep in
guard let rep else {
@@ -928,19 +935,29 @@ extension _FileManagerImpl {
let groupID = _readFileAttributePrimitive(attributes[.groupOwnerAccountID], as: UInt.self)

if user != nil || userID != nil || group != nil || groupID != nil {
#if os(WASI)
// WASI does not have the concept of users or groups
throw CocoaError.errorWithFilePath(.featureUnsupported, path)
#else
// Bias toward userID & groupID - try to prevent round trips to getpwnam if possible.
var leaveUnchanged: UInt32 { UInt32(bitPattern: -1) }
let rawUserID = userID.flatMap(uid_t.init) ?? user.flatMap(Self._userAccountNameToNumber) ?? leaveUnchanged
let rawGroupID = groupID.flatMap(gid_t.init) ?? group.flatMap(Self._groupAccountNameToNumber) ?? leaveUnchanged
if chown(fileSystemRepresentation, rawUserID, rawGroupID) != 0 {
throw CocoaError.errorWithFilePath(path, errno: errno, reading: false)
}
#endif
}

try Self._setCatInfoAttributes(attributes, path: path)

if let extendedAttrs = attributes[.init("NSFileExtendedAttributes")] as? [String : Data] {
#if os(WASI)
// WASI does not support extended attributes
throw CocoaError.errorWithFilePath(.featureUnsupported, path)
#else
try Self._setAttributes(extendedAttrs, at: fileSystemRepresentation, followSymLinks: false)
#endif
}

if let date = attributes[.modificationDate] as? Date {
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ import Musl
import CRT
import WinSDK
internal import _FoundationCShims
#elseif os(WASI)
import WASILibc
#endif

extension _FileManagerImpl {
Original file line number Diff line number Diff line change
@@ -34,6 +34,8 @@ internal import _FoundationCShims
#elseif os(Windows)
import CRT
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

#if os(Windows)
@@ -176,7 +178,7 @@ extension _FileManagerImpl {
#endif
}

#if !os(Windows)
#if !os(Windows) && !os(WASI)
static func _setAttribute(_ key: UnsafePointer<CChar>, value: Data, at path: UnsafePointer<CChar>, followSymLinks: Bool) throws {
try value.withUnsafeBytes { buffer in
#if canImport(Darwin)
@@ -274,7 +276,7 @@ extension _FileManagerImpl {
}
#endif

#if !os(Windows)
#if !os(Windows) && !os(WASI)
static func _userAccountNameToNumber(_ name: String) -> uid_t? {
name.withCString { ptr in
getpwnam(ptr)?.pointee.pw_uid
23 changes: 23 additions & 0 deletions Sources/FoundationEssentials/FileManager/FileOperations.swift
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@ import Musl
#elseif os(Windows)
import CRT
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

#if FOUNDATION_FRAMEWORK
@@ -866,12 +868,14 @@ enum _FileOperations {
}
defer { close(dstfd) }

#if !os(WASI) // WASI doesn't have fchmod for now
// 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 {
try delegate.throwIfNecessary(errno, String(cString: srcPtr), String(cString: dstPtr))
return
}
#endif

if fileInfo.st_size == 0 {
// no copying required
@@ -882,12 +886,31 @@ enum _FileOperations {
let chunkSize: Int = Int(fileInfo.st_blksize)
var current: off_t = 0

#if os(WASI)
// WASI doesn't have sendfile, so we need to do it in user space with read/write
try withUnsafeTemporaryAllocation(of: UInt8.self, capacity: chunkSize) { buffer in
while current < total {
let readSize = Swift.min(total - Int(current), chunkSize)
let bytesRead = read(srcfd, buffer.baseAddress, readSize)
guard bytesRead >= 0 else {
try delegate.throwIfNecessary(errno, String(cString: srcPtr), String(cString: dstPtr))
return
}
guard write(dstfd, buffer.baseAddress, bytesRead) == bytesRead else {
try delegate.throwIfNecessary(errno, String(cString: srcPtr), String(cString: dstPtr))
return
}
current += off_t(bytesRead)
}
}
#else
while current < total {
guard sendfile(dstfd, srcfd, &current, Swift.min(total - Int(current), chunkSize)) != -1 else {
try delegate.throwIfNecessary(errno, String(cString: srcPtr), String(cString: dstPtr))
return
}
}
#endif
}
#endif

Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ import Glibc
import Musl
#elseif os(Windows)
import CRT
#elseif os(WASI)
import WASILibc
#endif

// MARK: - BinaryInteger + Numeric string representation
9 changes: 9 additions & 0 deletions Sources/FoundationEssentials/LockedState.swift
Original file line number Diff line number Diff line change
@@ -35,6 +35,9 @@ package struct LockedState<State> {
typealias Primitive = pthread_mutex_t
#elseif canImport(WinSDK)
typealias Primitive = SRWLOCK
#elseif os(WASI)
// WASI is single-threaded, so we don't need a lock.
typealias Primitive = Void
#endif

typealias PlatformLock = UnsafeMutablePointer<Primitive>
@@ -47,6 +50,8 @@ package struct LockedState<State> {
pthread_mutex_init(platformLock, nil)
#elseif canImport(WinSDK)
InitializeSRWLock(platformLock)
#elseif os(WASI)
// no-op
#endif
}

@@ -64,6 +69,8 @@ package struct LockedState<State> {
pthread_mutex_lock(platformLock)
#elseif canImport(WinSDK)
AcquireSRWLockExclusive(platformLock)
#elseif os(WASI)
// no-op
#endif
}

@@ -74,6 +81,8 @@ package struct LockedState<State> {
pthread_mutex_unlock(platformLock)
#elseif canImport(WinSDK)
ReleaseSRWLockExclusive(platformLock)
#elseif os(WASI)
// no-op
#endif
}
}
4 changes: 2 additions & 2 deletions Sources/FoundationEssentials/Platform.swift
Original file line number Diff line number Diff line change
@@ -114,7 +114,7 @@ private let _cachedUGIDs: (uid_t, gid_t) = {
}()
#endif

#if !os(Windows)
#if !os(Windows) && !os(WASI)
extension Platform {
private static var ROOT_USER: UInt32 { 0 }
static func getUGIDs(allowEffectiveRootUID: Bool = true) -> (uid: UInt32, gid: UInt32) {
@@ -175,7 +175,7 @@ extension Platform {
// FIXME: bionic implements this as `return 0;` and does not expose the
// function via headers. We should be able to shim this and use the call
// if it is available.
#if !os(Android)
#if !os(Android) && !os(WASI)
guard issetugid() == 0 else { return nil }
#endif
if let value = getenv(name) {
4 changes: 3 additions & 1 deletion Sources/FoundationEssentials/ProcessInfo/ProcessInfo.swift
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ import Glibc
import Musl
#elseif os(Windows)
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

#if !NO_PROCESS
@@ -391,7 +393,7 @@ extension _ProcessInfo {
patch: Int(osVersionInfo.dwBuildNumber)
)
#else
return OperatingSystemVersion(majorVersion: -1, minorVersion: 0, patchVersion: 0)
return (major: -1, minor: 0, patch: 0)
#endif
}

2 changes: 2 additions & 0 deletions Sources/FoundationEssentials/PropertyList/OpenStepPlist.swift
Original file line number Diff line number Diff line change
@@ -16,6 +16,8 @@ import Darwin
import Bionic
#elseif canImport(Glibc)
import Glibc
#elseif os(WASI)
import WASILibc
#elseif canImport(Musl)
import Musl
#endif
4 changes: 4 additions & 0 deletions Sources/FoundationEssentials/String/String+Path.swift
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ import Glibc
import Musl
#elseif os(Windows)
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

internal import _FoundationCShims
@@ -452,6 +454,7 @@ extension String {
return envVar.standardizingPath
}

#if !os(WASI) // WASI does not have user concept
// Next, attempt to find the home directory via getpwnam/getpwuid
var pass: UnsafeMutablePointer<passwd>?
if let user {
@@ -465,6 +468,7 @@ extension String {
if let dir = pass?.pointee.pw_dir {
return String(cString: dir).standardizingPath
}
#endif

// Fallback to HOME for the current user if possible
if user == nil, let home = getenv("HOME") {
8 changes: 8 additions & 0 deletions Sources/FoundationEssentials/_ThreadLocal.swift
Original file line number Diff line number Diff line change
@@ -32,6 +32,8 @@ struct _ThreadLocal {
fileprivate typealias PlatformKey = tss_t
#elseif canImport(WinSDK)
fileprivate typealias PlatformKey = DWORD
#elseif os(WASI)
fileprivate typealias PlatformKey = UnsafeMutablePointer<UnsafeMutableRawPointer?>
#endif

struct Key<Value> {
@@ -48,6 +50,8 @@ struct _ThreadLocal {
self.key = key
#elseif canImport(WinSDK)
key = FlsAlloc(nil)
#elseif os(WASI)
key = UnsafeMutablePointer<UnsafeMutableRawPointer?>.allocate(capacity: 1)
#endif
}
}
@@ -60,6 +64,8 @@ struct _ThreadLocal {
tss_get(key)
#elseif canImport(WinSDK)
FlsGetValue(key)
#elseif os(WASI)
key.pointee
#endif
}

@@ -70,6 +76,8 @@ struct _ThreadLocal {
tss_set(key, newValue)
#elseif canImport(WinSDK)
FlsSetValue(key, newValue)
#elseif os(WASI)
key.pointee = newValue
#endif
}
}
1 change: 1 addition & 0 deletions Sources/FoundationInternationalization/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@ target_compile_options(FoundationInternationalization PRIVATE
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-experimental-feature -Xfrontend StrictConcurrency>"
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-upcoming-feature -Xfrontend InferSendableFromCaptures>")
target_compile_options(FoundationInternationalization PRIVATE ${_SwiftFoundation_availability_macros})
target_compile_options(FoundationInternationalization PRIVATE ${_SwiftFoundation_wasi_libc_flags})
target_compile_options(FoundationInternationalization PRIVATE -package-name "SwiftFoundation")

target_link_libraries(FoundationInternationalization PUBLIC
Original file line number Diff line number Diff line change
@@ -24,6 +24,8 @@ import Musl
import CRT
#elseif canImport(Darwin)
import Darwin
#elseif os(WASI)
import WASILibc
#endif

internal import _FoundationICU
Original file line number Diff line number Diff line change
@@ -24,6 +24,8 @@ import Glibc
import Musl
#elseif os(Windows)
import CRT
#elseif os(WASI)
import WASILibc
#endif

@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
16 changes: 15 additions & 1 deletion Sources/_FoundationCShims/include/_CStdlib.h
Original file line number Diff line number Diff line change
@@ -60,7 +60,21 @@
#endif

#if __has_include(<signal.h>)
#include <signal.h>
/// Guard against including `signal.h` on WASI. The `signal.h` header file
/// itself is available in wasi-libc, but it's just a stub that doesn't actually
/// do anything. And also including it requires a special macro definition
/// (`_WASI_EMULATED_SIGNAL`) and it causes compilation errors without the macro.
# if !TARGET_OS_WASI || defined(_WASI_EMULATED_SIGNAL)
# include <signal.h>
# endif
#endif

#if __has_include(<sys/mman.h>)
/// Similar to `signal.h`, guard against including `sys/mman.h` on WASI unless
/// `_WASI_EMULATED_MMAN` is enabled.
# if !TARGET_OS_WASI || defined(_WASI_EMULATED_MMAN)
# include <sys/mman.h>
# endif
#endif

#if __has_include(<stdalign.h>)
12 changes: 6 additions & 6 deletions Sources/_FoundationCShims/include/platform_shims.h
Original file line number Diff line number Diff line change
@@ -31,19 +31,19 @@
#include <security.h>
#endif

INTERNAL char * _Nullable * _Nullable _platform_shims_get_environ();
INTERNAL char * _Nullable * _Nullable _platform_shims_get_environ(void);

INTERNAL void _platform_shims_lock_environ();
INTERNAL void _platform_shims_unlock_environ();
INTERNAL void _platform_shims_lock_environ(void);
INTERNAL void _platform_shims_unlock_environ(void);

#if __has_include(<mach/vm_page_size.h>)
#include <mach/vm_page_size.h>
INTERNAL vm_size_t _platform_shims_vm_size();
INTERNAL vm_size_t _platform_shims_vm_size(void);
#endif

#if __has_include(<mach/mach.h>)
#include <mach/mach.h>
INTERNAL mach_port_t _platform_mach_task_self();
INTERNAL mach_port_t _platform_mach_task_self(void);
#endif

#if __has_include(<libkern/OSThermalNotification.h>)
@@ -65,7 +65,7 @@ typedef enum {
} _platform_shims_OSThermalPressureLevel;


INTERNAL const char * _Nonnull _platform_shims_kOSThermalNotificationPressureLevelName();
INTERNAL const char * _Nonnull _platform_shims_kOSThermalNotificationPressureLevelName(void);
#endif

#endif /* CSHIMS_PLATFORM_SHIMS */
20 changes: 12 additions & 8 deletions Sources/_FoundationCShims/platform_shims.c
Original file line number Diff line number Diff line change
@@ -21,21 +21,25 @@
extern char **environ;
#endif

#if __wasi__
#include <wasi/libc-environ.h> // for __wasilibc_get_environ
#endif

#if __has_include(<libc_private.h>)
#import <libc_private.h>
void _platform_shims_lock_environ() {
void _platform_shims_lock_environ(void) {
environ_lock_np();
}

void _platform_shims_unlock_environ() {
void _platform_shims_unlock_environ(void) {
environ_unlock_np();
}
#else
void _platform_shims_lock_environ() { /* noop */ }
void _platform_shims_unlock_environ() { /* noop */ }
void _platform_shims_lock_environ(void) { /* noop */ }
void _platform_shims_unlock_environ(void) { /* noop */ }
#endif

char ** _platform_shims_get_environ() {
char ** _platform_shims_get_environ(void) {
#if __has_include(<crt_externs.h>)
return *_NSGetEnviron();
#elif defined(_WIN32)
@@ -48,20 +52,20 @@ char ** _platform_shims_get_environ() {
}

#if __has_include(<libkern/OSThermalNotification.h>)
const char * _platform_shims_kOSThermalNotificationPressureLevelName() {
const char * _platform_shims_kOSThermalNotificationPressureLevelName(void) {
return kOSThermalNotificationPressureLevelName;
}
#endif

#if __has_include(<mach/vm_page_size.h>)
vm_size_t _platform_shims_vm_size() {
vm_size_t _platform_shims_vm_size(void) {
// This shim exists because vm_page_size is not marked const, and therefore looks like global mutable state to Swift.
return vm_page_size;
}
#endif

#if __has_include(<mach/mach.h>)
mach_port_t _platform_mach_task_self() {
mach_port_t _platform_mach_task_self(void) {
// This shim exists because mach_task_self_ is not marked const, and therefore looks like global mutable state to Swift.
return mach_task_self();
}