Skip to content
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

6.0: Fix WASI support #825

Merged
merged 13 commits into from
Aug 29, 2024
Merged
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: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
35 changes: 26 additions & 9 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")],
Expand All @@ -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(
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -166,6 +182,7 @@ let package = Package(
"CMakeLists.txt",
"Predicate/CMakeLists.txt"
],
cSettings: wasiLibcCSettings,
swiftSettings: [
.enableExperimentalFeature("AccessLevelOnImport")
] + availabilityMacros + concurrencyChecking
Expand Down
1 change: 1 addition & 0 deletions Sources/FoundationEssentials/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions Sources/FoundationEssentials/Calendar/Calendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import Glibc
import Musl
#elseif canImport(CRT)
import CRT
#elseif os(WASI)
import WASILibc
#endif

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


Expand Down
2 changes: 2 additions & 0 deletions Sources/FoundationEssentials/Data/Data+Reading.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 9 additions & 0 deletions Sources/FoundationEssentials/Data/Data+Writing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import Musl
#elseif os(Windows)
import CRT
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

#if !NO_FILESYSTEM
Expand Down Expand Up @@ -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("/")
Expand Down Expand Up @@ -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)`
Expand Down Expand Up @@ -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
Expand All @@ -539,6 +547,7 @@ private func writeToFileAux(path inPath: PathOrURL, buffer: UnsafeRawBufferPoint
fchmod(fd, mode)
#endif
}
#endif // os(WASI)
}
}
}
Expand Down
14 changes: 8 additions & 6 deletions Sources/FoundationEssentials/Data/Data.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ import Glibc
import Musl
#elseif canImport(ucrt)
import ucrt
#elseif canImport(WASILibc)
import WASILibc
#endif

#if os(Windows)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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")
Expand Down
2 changes: 2 additions & 0 deletions Sources/FoundationEssentials/Date.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import Glibc
import Musl
#elseif canImport(WinSDK)
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

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

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

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

#if FOUNDATION_FRAMEWORK
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import Musl
#elseif os(Windows)
import CRT
import WinSDK
#elseif os(WASI)
import WASILibc
#endif

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

internal import _FoundationCShims
Expand Down
23 changes: 20 additions & 3 deletions Sources/FoundationEssentials/FileManager/FileManager+Files.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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),
Expand All @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import Musl
import CRT
import WinSDK
internal import _FoundationCShims
#elseif os(WASI)
import WASILibc
#endif

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

#if os(Windows)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
Loading