From 9275761e14e57ad7ac45b8f201b28a0b9c857891 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 16 Aug 2024 11:03:23 +0000 Subject: [PATCH 1/2] Use apinote's SwiftPrivate instead of patching header file --- ...ambiguous-errno-error-when-importing.patch | 38 +++++++ ...o-as-nonisolated-unsafe-in-wasi-libc.patch | 106 ------------------ ...te-errno-as-SwiftPrivate-by-apinotes.patch | 97 ++++++++++++++++ 3 files changed, 135 insertions(+), 106 deletions(-) create mode 100644 schemes/main/swift/0001-Revert-wasm-Fix-ambiguous-errno-error-when-importing.patch delete mode 100644 schemes/main/swift/0001-wasm-Mark-errno-as-nonisolated-unsafe-in-wasi-libc.patch create mode 100644 schemes/main/swift/0002-wasm-Annotate-errno-as-SwiftPrivate-by-apinotes.patch diff --git a/schemes/main/swift/0001-Revert-wasm-Fix-ambiguous-errno-error-when-importing.patch b/schemes/main/swift/0001-Revert-wasm-Fix-ambiguous-errno-error-when-importing.patch new file mode 100644 index 00000000..921c0ad0 --- /dev/null +++ b/schemes/main/swift/0001-Revert-wasm-Fix-ambiguous-errno-error-when-importing.patch @@ -0,0 +1,38 @@ +From 90799cfdf73e69147baab6f92f934c3a74235c5e Mon Sep 17 00:00:00 2001 +From: Yuta Saito +Date: Sat, 10 Aug 2024 13:29:48 +0000 +Subject: [PATCH] Revert "[wasm] Fix ambiguous `errno` error when importing + WASILibc module" + +This reverts commit 164ec0adaa80e7a29d2a10fb31ee72baddeda6b2. +--- + stdlib/public/Platform/Platform.swift | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/stdlib/public/Platform/Platform.swift b/stdlib/public/Platform/Platform.swift +index ca7417c5357..0c2d63a0cff 100644 +--- a/stdlib/public/Platform/Platform.swift ++++ b/stdlib/public/Platform/Platform.swift +@@ -84,11 +84,6 @@ func _convertDarwinBooleanToBool(_ x: DarwinBoolean) -> Bool { + + #endif + +-// wasi-libc defines `errno` in a way ClangImporter can understand, so we don't +-// need to define shims for it. On the contrary, if we define the shim, we will +-// get an ambiguity error when importing WASILibc module and SwiftWASILibc Clang +-// module (or a Clang module that re-exports SwiftWASILibc). +-#if !os(WASI) + //===----------------------------------------------------------------------===// + // sys/errno.h + //===----------------------------------------------------------------------===// +@@ -101,7 +96,6 @@ public var errno : Int32 { + return _swift_stdlib_setErrno(val) + } + } +-#endif + + + //===----------------------------------------------------------------------===// +-- +2.43.2 + diff --git a/schemes/main/swift/0001-wasm-Mark-errno-as-nonisolated-unsafe-in-wasi-libc.patch b/schemes/main/swift/0001-wasm-Mark-errno-as-nonisolated-unsafe-in-wasi-libc.patch deleted file mode 100644 index 2233edb9..00000000 --- a/schemes/main/swift/0001-wasm-Mark-errno-as-nonisolated-unsafe-in-wasi-libc.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 1fa232de1d1da9b434e2686c8a30021a579b25ae Mon Sep 17 00:00:00 2001 -From: Yuta Saito -Date: Sat, 10 Aug 2024 14:40:44 +0000 -Subject: [PATCH] [wasm] Mark `errno` as nonisolated(unsafe) in wasi-libc - -This patch is a workaround to reflect the fact that `errno` is thread-local -and can be accessed from any actor. This is a temporary solution until we -have `__swift_attr__` support in apinotes or `thread_local` support in -ClangImporter. - -This change is required to build swift-corelibs-foundation with Swift 6 -language mode. ---- - test/stdlib/WASILibcAPI.swift | 19 ++++++++++ - .../products/wasisysroot.py | 35 ++++++++++++++++++- - 2 files changed, 53 insertions(+), 1 deletion(-) - create mode 100644 test/stdlib/WASILibcAPI.swift - -diff --git a/test/stdlib/WASILibcAPI.swift b/test/stdlib/WASILibcAPI.swift -new file mode 100644 -index 00000000000..fe599bb9f38 ---- /dev/null -+++ b/test/stdlib/WASILibcAPI.swift -@@ -0,0 +1,19 @@ -+// RUN: %target-swift-frontend -typecheck -swift-version 6 %s -verify -+// REQUIRES: executable_test -+// REQUIRES: OS=wasi -+ -+import WASILibc -+ -+// errno is a global thread-local variable, so it should be accessible -+// from any context. -+ -+enum TestErrno { -+ static func testSyncContext() { -+ _ = errno -+ errno = 0 -+ } -+ static func testAsyncContext() async { -+ _ = errno -+ errno = 0 -+ } -+} -diff --git a/utils/swift_build_support/swift_build_support/products/wasisysroot.py b/utils/swift_build_support/swift_build_support/products/wasisysroot.py -index e780809ff38..77c57c0e8bb 100644 ---- a/utils/swift_build_support/swift_build_support/products/wasisysroot.py -+++ b/utils/swift_build_support/swift_build_support/products/wasisysroot.py -@@ -58,6 +58,7 @@ class WASILibc(product.Product): - - sysroot_build_dir = WASILibc.sysroot_build_path( - build_root, host_target, target_triple) -+ sysroot_install_dir = WASILibc.sysroot_install_path(build_root, target_triple) - # FIXME: Manually create an empty dir that is usually created during - # check-symbols. The directory is required during sysroot installation step. - os.makedirs(os.path.join(sysroot_build_dir, "share"), exist_ok=True) -@@ -74,7 +75,7 @@ class WASILibc(product.Product): - '-C', self.source_dir, - 'OBJDIR=' + os.path.join(self.build_dir, 'obj-' + thread_model), - 'SYSROOT=' + sysroot_build_dir, -- 'INSTALL_DIR=' + WASILibc.sysroot_install_path(build_root, target_triple), -+ 'INSTALL_DIR=' + sysroot_install_dir, - 'CC=' + os.path.join(clang_tools_path, 'clang'), - 'AR=' + os.path.join(llvm_tools_path, 'llvm-ar'), - 'NM=' + os.path.join(llvm_tools_path, 'llvm-nm'), -@@ -82,6 +83,38 @@ class WASILibc(product.Product): - 'TARGET_TRIPLE=' + target_triple, - ]) - -+ # FIXME(katei): Workaround to access `errno` without actor isolation. -+ # Remove the workaround once we fixed -+ # https://github.com/swiftlang/swift/issues/75819 or -+ # https://github.com/swiftlang/swift/issues/75820 -+ errno_patch = """diff --git a/__errno.h b/__errno.h -+index 4fd983a..7e9e2d9 100644 -+--- a/__errno.h -++++ b/__errno.h -+@@ -5,6 +5,15 @@ -+ extern "C" { -+ #endif -+ -++// BEGIN SWIFT PATCH -++#if __swift__ -++// NOTE: Mark errno as nonisolated(unsafe) so that it can be accessed from any -++// actor. This is a workaround until we have one of the following: -++// - `__swift_attr__` support in apinotes -++// - `thread_local` support in ClangImporter -++__attribute__((__swift_attr__("nonisolated(unsafe)"))) -++#endif -++// END SWIFT PATCH -+ #ifdef __cplusplus -+ extern thread_local int errno; -+ #else -+ """ -+ to_patch = os.path.join(sysroot_install_dir, "include", "__errno.h") -+ import tempfile -+ with tempfile.NamedTemporaryFile(mode='w') as f: -+ f.write(errno_patch) -+ f.flush() -+ shell.call(["patch", to_patch, f.name]) -+ - @classmethod - def get_dependencies(cls): - return [llvm.LLVM] --- -2.43.2 - diff --git a/schemes/main/swift/0002-wasm-Annotate-errno-as-SwiftPrivate-by-apinotes.patch b/schemes/main/swift/0002-wasm-Annotate-errno-as-SwiftPrivate-by-apinotes.patch new file mode 100644 index 00000000..735c25d0 --- /dev/null +++ b/schemes/main/swift/0002-wasm-Annotate-errno-as-SwiftPrivate-by-apinotes.patch @@ -0,0 +1,97 @@ +From be08ebb12a99636832f055e94956cb500af1a86d Mon Sep 17 00:00:00 2001 +From: Yuta Saito +Date: Sat, 10 Aug 2024 13:50:57 +0000 +Subject: [PATCH] [wasm] Annotate errno as SwiftPrivate by apinotes + +This patch adds an apinotes file for SwiftWASILibc clang module to mark +`errno` macro hidden from Swift code. This resolves ambiguity between +the C macro definition and the Swift wrapper in WASILibc overlay module. + +This change installs the apinotes file to the resource directories for +both lib/swift/apinotes and lib/swift_static/apinotes. +--- + stdlib/public/Platform/CMakeLists.txt | 28 +++++++++++++++++++ + stdlib/public/Platform/SwiftWASILibc.apinotes | 5 ++++ + test/stdlib/WASILibcAPI.swift | 19 +++++++++++++ + 3 files changed, 52 insertions(+) + create mode 100644 stdlib/public/Platform/SwiftWASILibc.apinotes + create mode 100644 test/stdlib/WASILibcAPI.swift + +diff --git a/stdlib/public/Platform/CMakeLists.txt b/stdlib/public/Platform/CMakeLists.txt +index 928b5d9cb63..7a7cab3da6d 100644 +--- a/stdlib/public/Platform/CMakeLists.txt ++++ b/stdlib/public/Platform/CMakeLists.txt +@@ -527,6 +527,34 @@ if("WASI" IN_LIST SWIFT_SDKS) + DESTINATION "lib/swift_static/${arch_subdir}" + COMPONENT sdk-overlay) + endif() ++ ++ set(wasilibc_apinotes_source "SwiftWASILibc.apinotes") ++ add_custom_command_target( ++ copy_wasilibc_apinotes_resource ++ COMMAND ++ "${CMAKE_COMMAND}" "-E" "make_directory" ${SWIFTLIB_DIR}/apinotes ${SWIFTSTATICLIB_DIR}/apinotes ++ COMMAND ++ "${CMAKE_COMMAND}" "-E" "copy_if_different" ++ "${CMAKE_CURRENT_SOURCE_DIR}/${wasilibc_apinotes_source}" ${SWIFTLIB_DIR}/apinotes ++ COMMAND ++ "${CMAKE_COMMAND}" "-E" "copy_if_different" ++ "${CMAKE_CURRENT_SOURCE_DIR}/${wasilibc_apinotes_source}" ${SWIFTSTATICLIB_DIR}/apinotes ++ OUTPUT ++ ${SWIFTLIB_DIR}/apinotes/${wasilibc_apinotes_source} ++ ${SWIFTSTATICLIB_DIR}/apinotes/${wasilibc_apinotes_source} ++ COMMENT "Copying WASILibc API notes to resource directories") ++ ++ list(APPEND wasilibc_modulemap_target_list ${copy_wasilibc_apinotes_resource}) ++ add_dependencies(sdk-overlay ${copy_wasilibc_apinotes_resource}) ++ swift_install_in_component(FILES "${wasilibc_apinotes_source}" ++ DESTINATION "lib/swift/apinotes" ++ COMPONENT sdk-overlay) ++ if(SWIFT_BUILD_STATIC_STDLIB) ++ swift_install_in_component(FILES "${wasilibc_apinotes_source}" ++ DESTINATION "lib/swift_static/apinotes" ++ COMPONENT sdk-overlay) ++ endif() ++ + endforeach() + endif() + add_custom_target(wasilibc_modulemap DEPENDS ${wasilibc_modulemap_target_list}) +diff --git a/stdlib/public/Platform/SwiftWASILibc.apinotes b/stdlib/public/Platform/SwiftWASILibc.apinotes +new file mode 100644 +index 00000000000..001acc7ebb5 +--- /dev/null ++++ b/stdlib/public/Platform/SwiftWASILibc.apinotes +@@ -0,0 +1,5 @@ ++Name: SwiftWASILibc ++Globals: ++ # errno macro is importable but we provide explicit Swift wrapper ++ - Name: errno ++ SwiftPrivate: true +diff --git a/test/stdlib/WASILibcAPI.swift b/test/stdlib/WASILibcAPI.swift +new file mode 100644 +index 00000000000..fe599bb9f38 +--- /dev/null ++++ b/test/stdlib/WASILibcAPI.swift +@@ -0,0 +1,19 @@ ++// RUN: %target-swift-frontend -typecheck -swift-version 6 %s -verify ++// REQUIRES: executable_test ++// REQUIRES: OS=wasi ++ ++import WASILibc ++ ++// errno is a global thread-local variable, so it should be accessible ++// from any context. ++ ++enum TestErrno { ++ static func testSyncContext() { ++ _ = errno ++ errno = 0 ++ } ++ static func testAsyncContext() async { ++ _ = errno ++ errno = 0 ++ } ++} +-- +2.43.2 + From aefc51c52d3fdd1e4529a81ed7dd1589c274da13 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 16 Aug 2024 11:22:32 +0000 Subject: [PATCH 2/2] Remove upstreamed patches for swift-foundation --- ...-use-cross-compilation-to-build-for-.patch | 155 ----------- ...ory-enumeration-related-code-to-WASI.patch | 241 ------------------ 2 files changed, 396 deletions(-) delete mode 100644 schemes/main/swift-foundation/0001-FoundationMacros-use-cross-compilation-to-build-for-.patch delete mode 100644 schemes/main/swift-foundation/0002-Port-directory-enumeration-related-code-to-WASI.patch diff --git a/schemes/main/swift-foundation/0001-FoundationMacros-use-cross-compilation-to-build-for-.patch b/schemes/main/swift-foundation/0001-FoundationMacros-use-cross-compilation-to-build-for-.patch deleted file mode 100644 index ff777fb8..00000000 --- a/schemes/main/swift-foundation/0001-FoundationMacros-use-cross-compilation-to-build-for-.patch +++ /dev/null @@ -1,155 +0,0 @@ -From 81a6b14e381b5f0baaee6e9ea7e192b2ce82ac2e Mon Sep 17 00:00:00 2001 -From: Saleem Abdulrasool -Date: Wed, 3 Jul 2024 08:37:19 -0700 -Subject: [PATCH 1/2] FoundationMacros: use cross-compilation to build for host - -Use `ExternalProject` to switch FoundationMacros to cross-compilation. -This allows us to build the macros for the right OS/architecture when -cross-compiling Foundation for other environments. - -Co-authored-by: Alex Lorenz ---- - CMakeLists.txt | 2 + - Sources/CMakeLists.txt | 6 --- - Sources/FoundationEssentials/CMakeLists.txt | 7 ++- - Sources/FoundationMacros/CMakeLists.txt | 53 ++++++++++++++------- - 4 files changed, 40 insertions(+), 28 deletions(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 108b657..3243e53 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -55,6 +55,8 @@ set(BUILD_TESTING NO) - set(COLLECTIONS_SINGLE_MODULE YES) - set(COLLECTIONS_FOUNDATION_TOOLCHAIN_MODULE YES) - -+set(SwiftFoundation_MACRO "" CACHE STRING "Path to Foundation macro plugin") -+ - # Make sure our dependencies exists - include(FetchContent) - if (_SwiftFoundationICU_SourceDIR) -diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt -index f7f7ba1..ef235c4 100644 ---- a/Sources/CMakeLists.txt -+++ b/Sources/CMakeLists.txt -@@ -13,11 +13,5 @@ - ##===----------------------------------------------------------------------===## - - add_subdirectory(_FoundationCShims) -- --# Disable the macro build on Windows until we can correctly build it for the host architecture --if(NOT CMAKE_SYSTEM_NAME STREQUAL Windows) -- add_subdirectory(FoundationMacros) --endif() -- - add_subdirectory(FoundationEssentials) - add_subdirectory(FoundationInternationalization) -diff --git a/Sources/FoundationEssentials/CMakeLists.txt b/Sources/FoundationEssentials/CMakeLists.txt -index e8417d1..98c419a 100644 ---- a/Sources/FoundationEssentials/CMakeLists.txt -+++ b/Sources/FoundationEssentials/CMakeLists.txt -@@ -49,10 +49,9 @@ add_subdirectory(String) - add_subdirectory(TimeZone) - add_subdirectory(URL) - --if(NOT CMAKE_SYSTEM_NAME STREQUAL Windows) -- # Depend on FoundationMacros -- add_dependencies(FoundationEssentials FoundationMacros) -- target_compile_options(FoundationEssentials PRIVATE -plugin-path ${CMAKE_BINARY_DIR}/lib) -+if(SwiftFoundation_MACRO) -+ target_compile_options(FoundationEssentials PRIVATE -+ "SHELL:-plugin-path ${SwiftFoundation_MACRO}") - endif() - - if(CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL Android) -diff --git a/Sources/FoundationMacros/CMakeLists.txt b/Sources/FoundationMacros/CMakeLists.txt -index c95c541..9710476 100644 ---- a/Sources/FoundationMacros/CMakeLists.txt -+++ b/Sources/FoundationMacros/CMakeLists.txt -@@ -12,29 +12,45 @@ - ## - ##===----------------------------------------------------------------------===## - -+cmake_minimum_required(VERSION 3.22) -+ -+if(POLICY CMP0156) -+ # Deduplicate linked libraries where appropriate -+ cmake_policy(SET CMP0156 NEW) -+endif() -+if(POLICY CMP0157) -+ # New Swift build model: improved incremental build performance and LSP support -+ cmake_policy(SET CMP0157 NEW) -+endif() -+ -+project(FoundationMacros -+ LANGUAGES Swift) -+ - # SwiftSyntax Dependency --include(FetchContent) --find_package(SwiftSyntax) -+find_package(SwiftSyntax QUIET) - if(NOT SwiftSyntax_FOUND) -+ include(FetchContent) -+ - # If building at desk, check out and link against the SwiftSyntax repo's targets - FetchContent_Declare(SwiftSyntax - GIT_REPOSITORY https://github.com/swiftlang/swift-syntax.git - GIT_TAG 4c6cc0a3b9e8f14b3ae2307c5ccae4de6167ac2c) # 600.0.0-prerelease-2024-06-12 - FetchContent_MakeAvailable(SwiftSyntax) -+else() -+ message(STATUS "Using swift-syntax from ${SwiftSyntax_DIR}") - endif() - - add_library(FoundationMacros SHARED - FoundationMacros.swift - PredicateMacro.swift) -- -+ - target_compile_definitions(FoundationMacros PRIVATE FOUNDATION_MACROS_LIBRARY) - --set_target_properties(FoundationMacros -- PROPERTIES -- ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib -- LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib -- INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_BINARY_DIR}/lib --) -+target_compile_options(FoundationMacros PRIVATE -parse-as-library) -+target_compile_options(FoundationMacros PRIVATE -+ "SHELL:$<$:-Xfrontend -enable-experimental-feature -Xfrontend AccessLevelOnImport>" -+ "SHELL:$<$:-Xfrontend -enable-experimental-feature -Xfrontend StrictConcurrency>" -+ "SHELL:$<$:-Xfrontend -enable-upcoming-feature -Xfrontend InferSendableFromCaptures>") - - target_link_libraries(FoundationMacros PUBLIC - SwiftSyntax::SwiftSyntax -@@ -43,18 +59,19 @@ target_link_libraries(FoundationMacros PUBLIC - SwiftSyntax::SwiftSyntaxBuilder - ) - --# The macro is installed into lib/swift/host/plugins, but needs to load libraries from lib/swift/host and lib/swift/${SWIFT_SYSTEM_NAME} - set_target_properties(FoundationMacros PROPERTIES -+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib -+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib -+ PDB_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin -+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin -+ -+ INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_BINARY_DIR}/lib -+ -+ # The macro is installed into lib/swift/host/plugins, but needs to load -+ # libraries from lib/swift/host and lib/swift/${SWIFT_SYSTEM_NAME} - INSTALL_RPATH "$ORIGIN/../../../swift/${SWIFT_SYSTEM_NAME}:$ORIGIN/.." - INSTALL_REMOVE_ENVIRONMENT_RPATH ON) - --target_compile_options(FoundationMacros PRIVATE -parse-as-library) --target_compile_options(FoundationMacros PRIVATE -- "SHELL:$<$:-Xfrontend -enable-experimental-feature -Xfrontend AccessLevelOnImport>" -- "SHELL:$<$:-Xfrontend -enable-experimental-feature -Xfrontend StrictConcurrency>" -- "SHELL:$<$:-Xfrontend -enable-upcoming-feature -Xfrontend InferSendableFromCaptures>") -- - install(TARGETS FoundationMacros -- ARCHIVE DESTINATION lib/swift/host/plugins - LIBRARY DESTINATION lib/swift/host/plugins -- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -+ RUNTIME DESTINATION bin) --- -2.43.2 - diff --git a/schemes/main/swift-foundation/0002-Port-directory-enumeration-related-code-to-WASI.patch b/schemes/main/swift-foundation/0002-Port-directory-enumeration-related-code-to-WASI.patch deleted file mode 100644 index 7123d725..00000000 --- a/schemes/main/swift-foundation/0002-Port-directory-enumeration-related-code-to-WASI.patch +++ /dev/null @@ -1,241 +0,0 @@ -From d5561e82120f325e38418eefd82b44a2b94a01c6 Mon Sep 17 00:00:00 2001 -From: Yuta Saito -Date: Fri, 26 Jul 2024 07:41:19 +0000 -Subject: [PATCH 2/2] Port directory enumeration related code to WASI - -For now wasi-libc does not include fts(3) implementation, so mark -features depending on it as unsupported on WASI. Once wasi-libc includes -fts or we decide to implement and maintain our own fts-like API, we can -remove these `#if os(WASI)` guards. - -wasi-libc issue tracking fts support: -https://github.com/WebAssembly/wasi-libc/issues/520 - -Also, wasi-libc defines some constants in a way that ClangImporter can't -understand, so we need to grab them manually through _FoundationCShims in -function call form. ---- - .../FileManager/FileManager+Directories.swift | 3 ++ - .../FileOperations+Enumeration.swift | 20 +++++++- - .../FileManager/FileOperations.swift | 49 ++++++++++++++++++- - .../WASILibc+Extensions.swift | 21 ++++++++ - .../include/platform_shims.h | 23 +++++++++ - 5 files changed, 113 insertions(+), 3 deletions(-) - -diff --git a/Sources/FoundationEssentials/FileManager/FileManager+Directories.swift b/Sources/FoundationEssentials/FileManager/FileManager+Directories.swift -index a29b311..bcbb5e9 100644 ---- a/Sources/FoundationEssentials/FileManager/FileManager+Directories.swift -+++ b/Sources/FoundationEssentials/FileManager/FileManager+Directories.swift -@@ -193,6 +193,9 @@ extension _FileManagerImpl { - } - } - return results -+#elseif os(WASI) -+ // wasi-libc does not support FTS for now -+ throw CocoaError.errorWithFilePath(.featureUnsupported, path) - #else - return try path.withFileSystemRepresentation { fileSystemRep in - guard let fileSystemRep else { -diff --git a/Sources/FoundationEssentials/FileManager/FileOperations+Enumeration.swift b/Sources/FoundationEssentials/FileManager/FileOperations+Enumeration.swift -index 22111f5..904f5fb 100644 ---- a/Sources/FoundationEssentials/FileManager/FileOperations+Enumeration.swift -+++ b/Sources/FoundationEssentials/FileManager/FileOperations+Enumeration.swift -@@ -115,10 +115,16 @@ import posix_filesystem.dirent - #elseif canImport(Glibc) - import Glibc - internal import _FoundationCShims -+#elseif os(WASI) -+import WASILibc -+internal import _FoundationCShims - #endif - - // MARK: Directory Iteration - -+// No FTS support in wasi-libc for now (https://github.com/WebAssembly/wasi-libc/issues/520) -+#if !os(WASI) -+ - struct _FTSSequence: Sequence { - enum Element { - struct SwiftFTSENT { -@@ -315,10 +321,12 @@ extension Sequence<_FTSSequence.Element> { - } - } - -+#endif // !os(WASI) -+ - struct _POSIXDirectoryContentsSequence: Sequence { - #if canImport(Darwin) - typealias DirectoryEntryPtr = UnsafeMutablePointer -- #elseif os(Android) || canImport(Glibc) -+ #elseif os(Android) || canImport(Glibc) || os(WASI) - typealias DirectoryEntryPtr = OpaquePointer - #endif - -@@ -343,10 +351,18 @@ struct _POSIXDirectoryContentsSequence: Sequence { - continue - } - // Use name -- let fileName = withUnsafeBytes(of: &dent.pointee.d_name) { buf in -+ let fileName: String -+ #if os(WASI) -+ // Use shim on WASI because wasi-libc defines `d_name` as -+ // "flexible array member" which is not supported by -+ // ClangImporter yet. -+ fileName = String(cString: _platform_shims_dirent_d_name(dent)) -+ #else -+ fileName = withUnsafeBytes(of: &dent.pointee.d_name) { buf in - let ptr = buf.baseAddress!.assumingMemoryBound(to: CChar.self) - return String(cString: ptr) - } -+ #endif - - if fileName == "." || fileName == ".." || fileName == "._" { - continue -diff --git a/Sources/FoundationEssentials/FileManager/FileOperations.swift b/Sources/FoundationEssentials/FileManager/FileOperations.swift -index d934685..ac961be 100644 ---- a/Sources/FoundationEssentials/FileManager/FileOperations.swift -+++ b/Sources/FoundationEssentials/FileManager/FileOperations.swift -@@ -512,7 +512,14 @@ enum _FileOperations { - // We failed for a reason other than the directory not being empty, so throw - throw CocoaError.removeFileError(errno, resolve(path: pathStr)) - } -- -+ -+ #if os(WASI) -+ -+ // wasi-libc does not support FTS, so we don't support removing non-empty directories on WASI for now. -+ throw CocoaError.errorWithFilePath(.featureUnsupported, pathStr) -+ -+ #else -+ - let seq = _FTSSequence(path, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR | FTS_NOSTAT) - let iterator = seq.makeIterator() - var isFirst = true -@@ -561,6 +568,7 @@ enum _FileOperations { - } - } - } -+ #endif - - } - #endif -@@ -912,6 +920,44 @@ enum _FileOperations { - } - #endif - -+ #if os(WASI) -+ private static func _linkOrCopyFile(_ srcPtr: UnsafePointer, _ dstPtr: UnsafePointer, with fileManager: FileManager, delegate: some LinkOrCopyDelegate) throws { -+ let src = String(cString: srcPtr) -+ let dst = String(cString: dstPtr) -+ guard delegate.shouldPerformOnItemAtPath(src, to: dst) else { return } -+ -+ var stat = stat() -+ guard lstat(srcPtr, &stat) == 0, !stat.isDirectory else { -+ // wasi-libc does not support FTS for now, so we don't support copying/linking -+ // directories on WASI for now. -+ throw CocoaError.errorWithFilePath(.featureUnsupported, String(cString: srcPtr)) -+ } -+ -+ // For now, we support only copying regular files and symlinks. -+ // After we get FTS support (https://github.com/WebAssembly/wasi-libc/pull/522), -+ // we can remove this method and use the below FTS-based implementation. -+ -+ if stat.isSymbolicLink { -+ try withUnsafeTemporaryAllocation(of: CChar.self, capacity: FileManager.MAX_PATH_SIZE) { tempBuff in -+ tempBuff.initialize(repeating: 0) -+ defer { tempBuff.deinitialize() } -+ let len = readlink(srcPtr, tempBuff.baseAddress!, FileManager.MAX_PATH_SIZE - 1) -+ if len >= 0, symlink(tempBuff.baseAddress!, dstPtr) != -1 { -+ return -+ } -+ try delegate.throwIfNecessary(errno, src, dst) -+ } -+ } else { -+ if delegate.copyData { -+ try _copyRegularFile(srcPtr, dstPtr, delegate: delegate) -+ } else { -+ if link(srcPtr, dstPtr) != 0 { -+ try delegate.throwIfNecessary(errno, src, dst) -+ } -+ } -+ } -+ } -+ #else - private static func _linkOrCopyFile(_ srcPtr: UnsafePointer, _ dstPtr: UnsafePointer, with fileManager: FileManager, delegate: some LinkOrCopyDelegate) throws { - try withUnsafeTemporaryAllocation(of: CChar.self, capacity: FileManager.MAX_PATH_SIZE) { buffer in - let dstLen = Platform.copyCString(dst: buffer.baseAddress!, src: dstPtr, size: FileManager.MAX_PATH_SIZE) -@@ -1024,6 +1070,7 @@ enum _FileOperations { - } - } - } -+ #endif - - private static func linkOrCopyFile(_ src: String, dst: String, with fileManager: FileManager, delegate: some LinkOrCopyDelegate) throws { - try src.withFileSystemRepresentation { srcPtr in -diff --git a/Sources/FoundationEssentials/WASILibc+Extensions.swift b/Sources/FoundationEssentials/WASILibc+Extensions.swift -index 1c05f99..351fe19 100644 ---- a/Sources/FoundationEssentials/WASILibc+Extensions.swift -+++ b/Sources/FoundationEssentials/WASILibc+Extensions.swift -@@ -29,4 +29,25 @@ internal var CLOCK_MONOTONIC_RAW: clockid_t { - return CLOCK_MONOTONIC - } - -+// MARK: - File Operations -+ -+internal var DT_DIR: UInt8 { -+ return _platform_shims_DT_DIR() -+} -+internal var DT_UNKNOWN: UInt8 { -+ return _platform_shims_DT_UNKNOWN() -+} -+internal var O_CREAT: Int32 { -+ return _platform_shims_O_CREAT() -+} -+internal var O_EXCL: Int32 { -+ return _platform_shims_O_EXCL() -+} -+internal var O_TRUNC: Int32 { -+ return _platform_shims_O_TRUNC() -+} -+internal var O_WRONLY: Int32 { -+ return _platform_shims_O_WRONLY() -+} -+ - #endif // os(WASI) -diff --git a/Sources/_FoundationCShims/include/platform_shims.h b/Sources/_FoundationCShims/include/platform_shims.h -index f45f5fd..6bc0a0e 100644 ---- a/Sources/_FoundationCShims/include/platform_shims.h -+++ b/Sources/_FoundationCShims/include/platform_shims.h -@@ -79,6 +79,29 @@ static inline _Nonnull clockid_t _platform_shims_clock_monotonic(void) { - static inline _Nonnull clockid_t _platform_shims_clock_realtime(void) { - return CLOCK_REALTIME; - } -+ -+// Define dirent shims so that we can use them in Swift because wasi-libc defines -+// `d_name` as "flexible array member" which is not supported by ClangImporter yet. -+ -+#include -+ -+static inline char * _Nonnull _platform_shims_dirent_d_name(struct dirent * _Nonnull entry) { -+ return entry->d_name; -+} -+ -+// Define getter shims for constants because wasi-libc defines them as function-like macros -+// which are not supported by ClangImporter yet. -+ -+#include -+#include -+#include -+ -+static inline uint8_t _platform_shims_DT_DIR(void) { return DT_DIR; } -+static inline uint8_t _platform_shims_DT_UNKNOWN(void) { return DT_UNKNOWN; } -+static inline int32_t _platform_shims_O_CREAT(void) { return O_CREAT; } -+static inline int32_t _platform_shims_O_EXCL(void) { return O_EXCL; } -+static inline int32_t _platform_shims_O_TRUNC(void) { return O_TRUNC; } -+static inline int32_t _platform_shims_O_WRONLY(void) { return O_WRONLY; } - #endif - - #endif /* CSHIMS_PLATFORM_SHIMS */ --- -2.43.2 -