Skip to content

Commit eff2571

Browse files
Merge pull request #104 from swiftwasm/katei/windows-wasi
Port a part of SystemExtras and WASI to Windows
2 parents 4729c8d + 1d30ab1 commit eff2571

File tree

21 files changed

+705
-181
lines changed

21 files changed

+705
-181
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ jobs:
123123
- uses: actions/checkout@v4
124124
- run: python3 ./Vendor/checkout-dependency testsuite
125125
- run: swift test
126+
- run: ./CI/check-wasi-testsuite.ps1
126127

127128
build-cmake:
128129
runs-on: ubuntu-20.04

CI/check-wasi-testsuite.ps1

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
python.exe .\Vendor\checkout-dependency wasi-testsuite
2+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
3+
python.exe -m pip install -r .\Vendor\wasi-testsuite\test-runner\requirements.txt
4+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
5+
python.exe .\IntegrationTests\WASI\run-tests.py
6+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

CI/check-wasi-testsuite.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ SOURCE_DIR="$(cd $(dirname $0)/.. && pwd)"
2626
cd $SOURCE_DIR && \
2727
./Vendor/checkout-dependency wasi-testsuite && \
2828
python3 -m pip install -r ./Vendor/wasi-testsuite/test-runner/requirements.txt && \
29-
exec ./IntegrationTests/WASI/run-tests.sh
29+
exec ./IntegrationTests/WASI/run-tests.py
3030
)

IntegrationTests/WASI/adapter.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
import shlex
66

77
# shlex.split() splits according to shell quoting rules
8-
WASMKIT_CLI = shlex.split(os.getenv("TEST_RUNTIME_EXE", "wasmkit-cli"))
8+
if sys.platform == "win32":
9+
WASMKIT_CLI = [os.getenv("TEST_RUNTIME_EXE", "wasmkit-cli.exe")]
10+
else:
11+
WASMKIT_CLI = shlex.split(os.getenv("TEST_RUNTIME_EXE", "wasmkit-cli"))
912

1013
parser = argparse.ArgumentParser()
1114
parser.add_argument("--version", action="store_true")

IntegrationTests/WASI/run-tests.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/usr/bin/env python3
2+
3+
import os
4+
import sys
5+
import subprocess
6+
7+
def main():
8+
source_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
9+
build_dir = os.path.join(source_dir, ".build", "debug")
10+
if sys.platform == "win32":
11+
default_runtime_exe = "wasmkit-cli.exe"
12+
skip_json_filename = "skip.windows.json"
13+
else:
14+
default_runtime_exe = "wasmkit-cli"
15+
skip_json_filename = "skip.json"
16+
default_runtime_exe = os.path.join(build_dir, default_runtime_exe)
17+
18+
if os.getenv("TEST_RUNTIME_EXE") is None and not os.path.exists(default_runtime_exe):
19+
print("Building wasmkit-cli")
20+
subprocess.run(["swift", "build", "--product", "wasmkit-cli"], check=True)
21+
22+
env = os.environ.copy()
23+
env["TEST_RUNTIME_EXE"] = os.getenv("TEST_RUNTIME_EXE", default_runtime_exe)
24+
25+
26+
subprocess.run(
27+
[sys.executable, "./Vendor/wasi-testsuite/test-runner/wasi_test_runner.py",
28+
"--test-suite", "./Vendor/wasi-testsuite/tests/assemblyscript/testsuite/",
29+
"./Vendor/wasi-testsuite/tests/c/testsuite/",
30+
"./Vendor/wasi-testsuite/tests/rust/testsuite/",
31+
"--runtime-adapter", "IntegrationTests/WASI/adapter.py",
32+
"--exclude-filter", os.path.join(source_dir, "IntegrationTests", "WASI", skip_json_filename),
33+
*sys.argv[1:]],
34+
env=env, check=True)
35+
36+
if __name__ == "__main__":
37+
main()

IntegrationTests/WASI/run-tests.sh

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"WASI Assemblyscript tests": {
3+
},
4+
"WASI C tests": {
5+
"fdopendir-with-access": "Not implemented",
6+
"fopen-with-access": "Not implemented",
7+
"lseek": "Not implemented",
8+
"pread-with-access": "Not implemented",
9+
"pwrite-with-access": "Not implemented",
10+
"stat-dev-ino": "Not implemented"
11+
},
12+
"WASI Rust tests": {
13+
"close_preopen": "Not implemented",
14+
"dangling_fd": "Not implemented",
15+
"dangling_symlink": "Not implemented",
16+
"directory_seek": "Not implemented",
17+
"fd_advise": "Not implemented",
18+
"fd_filestat_set": "Not implemented",
19+
"fd_flags_set": "Not implemented",
20+
"fd_readdir": "Not implemented",
21+
"interesting_paths": "Not implemented"
22+
}
23+
}

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ spectest:
1717

1818
.PHONY: wasitest
1919
wasitest:
20-
./IntegrationTests/WASI/run-tests.sh
20+
./IntegrationTests/WASI/run-tests.py
2121

2222
### Utilities
2323

Package.swift

Lines changed: 31 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ let package = Package(
1111
name: "WasmKit",
1212
targets: ["WasmKit"]
1313
),
14+
.library(
15+
name: "WasmKitWASI",
16+
targets: ["WasmKitWASI"]
17+
),
18+
.library(
19+
name: "WASI",
20+
targets: ["WASI"]
21+
),
1422
.library(
1523
name: "WasmParser",
1624
targets: ["WasmParser"]
@@ -33,6 +41,7 @@ let package = Package(
3341
name: "CLI",
3442
dependencies: [
3543
"WasmKit",
44+
"WasmKitWASI",
3645
.product(name: "ArgumentParser", package: "swift-argument-parser"),
3746
.product(name: "SystemPackage", package: "swift-system"),
3847
],
@@ -47,6 +56,7 @@ let package = Package(
4756
dependencies: [
4857
"WasmParser",
4958
"WasmTypes",
59+
"SystemExtras",
5060
.product(name: "SystemPackage", package: "swift-system"),
5161
],
5262
exclude: ["CMakeLists.txt"]
@@ -60,6 +70,27 @@ let package = Package(
6070
],
6171
exclude: ["CMakeLists.txt"]
6272
),
73+
.target(
74+
name: "WASI",
75+
dependencies: ["WasmTypes", "SystemExtras"],
76+
exclude: ["CMakeLists.txt"]
77+
),
78+
.target(
79+
name: "WasmKitWASI",
80+
dependencies: ["WasmKit", "WASI"],
81+
exclude: ["CMakeLists.txt"]
82+
),
83+
.testTarget(
84+
name: "WASITests",
85+
dependencies: ["WASI"]
86+
),
87+
.target(
88+
name: "SystemExtras",
89+
dependencies: [
90+
.product(name: "SystemPackage", package: "swift-system")
91+
],
92+
exclude: ["CMakeLists.txt"]
93+
),
6394
.executableTarget(
6495
name: "Spectest",
6596
dependencies: [
@@ -115,52 +146,6 @@ if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
115146
}
116147

117148
#if !os(Windows)
118-
// Add WASI-related products and targets
119-
package.products.append(contentsOf: [
120-
.library(
121-
name: "WasmKitWASI",
122-
targets: ["WasmKitWASI"]
123-
),
124-
.library(
125-
name: "WASI",
126-
targets: ["WASI"]
127-
),
128-
])
129-
package.targets.append(contentsOf: [
130-
.target(
131-
name: "WASI",
132-
dependencies: ["WasmTypes", "SystemExtras"],
133-
exclude: ["CMakeLists.txt"]
134-
),
135-
.target(
136-
name: "WasmKitWASI",
137-
dependencies: ["WasmKit", "WASI"],
138-
exclude: ["CMakeLists.txt"]
139-
),
140-
.target(
141-
name: "SystemExtras",
142-
dependencies: [
143-
.product(name: "SystemPackage", package: "swift-system")
144-
],
145-
exclude: ["CMakeLists.txt"]
146-
),
147-
.testTarget(
148-
name: "WASITests",
149-
dependencies: ["WASI"]
150-
),
151-
])
152-
let targetDependenciesToAdd = [
153-
"CLI": ["WasmKitWASI"],
154-
"WasmKit": ["SystemExtras"],
155-
]
156-
for (targetName, dependencies) in targetDependenciesToAdd {
157-
if let target = package.targets.first(where: { $0.name == targetName }) {
158-
target.dependencies += dependencies.map { .target(name: $0) }
159-
} else {
160-
fatalError("Target \(targetName) not found!?")
161-
}
162-
}
163-
164149
// Add build tool plugins only for non-Windows platforms
165150
package.products.append(contentsOf: [
166151
.plugin(name: "WITOverlayPlugin", targets: ["WITOverlayPlugin"]),

Sources/CLI/Run/Run.swift

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import ArgumentParser
22
import SystemPackage
3-
#if canImport(WasmKitWASI)
43
import WasmKitWASI
5-
#endif
64
import WasmKit
75

86
struct Run: ParsableCommand {
@@ -80,7 +78,6 @@ struct Run: ParsableCommand {
8078
}
8179
}
8280

83-
#if canImport(SystemExtras)
8481
func deriveInterceptor() throws -> (interceptor: GuestTimeProfiler, finalize: () -> Void)? {
8582
guard let outputPath = self.profileOutput else { return nil }
8683
let fileHandle = try FileDescriptor.open(
@@ -100,15 +97,8 @@ struct Run: ParsableCommand {
10097
}
10198
)
10299
}
103-
#else
104-
// GuestTimeProfiler is not available without SystemExtras
105-
func deriveInterceptor() throws -> (interceptor: RuntimeInterceptor, finalize: () -> Void)? {
106-
nil
107-
}
108-
#endif
109100

110101
func instantiateWASI(module: Module, interceptor: RuntimeInterceptor?) throws -> () throws -> Void {
111-
#if canImport(WasmKitWASI)
112102
// Flatten environment variables into a dictionary (Respect the last value if a key is duplicated)
113103
let environment = environment.reduce(into: [String: String]()) {
114104
$0[$1.key] = $1.value
@@ -123,9 +113,6 @@ struct Run: ParsableCommand {
123113
let exitCode = try wasi.start(moduleInstance, runtime: runtime)
124114
throw ExitCode(Int32(exitCode))
125115
}
126-
#else
127-
fatalError("WASI is not supported on this platform")
128-
#endif
129116
}
130117

131118
func instantiateNonWASI(module: Module, interceptor: RuntimeInterceptor?) throws -> (() throws -> Void)? {

Sources/SystemExtras/FileAtOperations.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Darwin
44
import Glibc
55
#elseif os(Windows)
66
import ucrt
7+
import WinSDK
78
#else
89
#error("Unsupported Platform")
910
#endif
@@ -52,6 +53,7 @@ extension FileDescriptor {
5253
#endif
5354
*/
5455

56+
#if !os(Windows)
5557
/// Indicates the operation removes directory
5658
///
5759
/// If you specify this option and the file path you pass to
@@ -61,6 +63,7 @@ extension FileDescriptor {
6163
/// The corresponding C constant is `AT_REMOVEDIR`.
6264
@_alwaysEmitIntoClient
6365
public static var removeDirectory: AtOptions { AtOptions(rawValue: _AT_REMOVEDIR) }
66+
#endif
6467
}
6568

6669
/// Opens or creates a file relative to a directory file descriptor
@@ -126,6 +129,9 @@ extension FileDescriptor {
126129
permissions: FilePermissions?,
127130
retryOnInterrupt: Bool
128131
) -> Result<FileDescriptor, Errno> {
132+
#if os(Windows)
133+
return .failure(Errno(rawValue: ERROR_NOT_SUPPORTED))
134+
#else
129135
let oFlag = mode.rawValue | options.rawValue
130136
let descOrError: Result<CInt, Errno> = valueOrErrno(retryOnInterrupt: retryOnInterrupt) {
131137
if let permissions = permissions {
@@ -136,6 +142,7 @@ extension FileDescriptor {
136142
return system_openat(self.rawValue, path, oFlag)
137143
}
138144
return descOrError.map { FileDescriptor(rawValue: $0) }
145+
#endif
139146
}
140147

141148
/// Returns attributes information about a file relative to a directory file descriptor
@@ -168,11 +175,15 @@ extension FileDescriptor {
168175

169176
@usableFromInline
170177
internal func _attributes(at path: UnsafePointer<CInterop.PlatformChar>, options: AtOptions) -> Result<Attributes, Errno> {
178+
#if os(Windows)
179+
return .failure(Errno(rawValue: ERROR_NOT_SUPPORTED))
180+
#else
171181
var stat: stat = stat()
172182
return nothingOrErrno(retryOnInterrupt: false) {
173183
system_fstatat(self.rawValue, path, &stat, options.rawValue)
174184
}
175185
.map { Attributes(rawValue: stat) }
186+
#endif
176187
}
177188

178189
/// Remove a file entry relative to a directory file descriptor
@@ -205,9 +216,13 @@ extension FileDescriptor {
205216
internal func _remove(
206217
at path: UnsafePointer<CInterop.PlatformChar>, options: AtOptions
207218
) -> Result<(), Errno> {
219+
#if os(Windows)
220+
return .failure(Errno(rawValue: ERROR_NOT_SUPPORTED))
221+
#else
208222
return nothingOrErrno(retryOnInterrupt: false) {
209223
system_unlinkat(self.rawValue, path, options.rawValue)
210224
}
225+
#endif
211226
}
212227

213228
/// Create a directory relative to a directory file descriptor
@@ -244,9 +259,13 @@ extension FileDescriptor {
244259
internal func _createDirectory(
245260
at path: UnsafePointer<CInterop.PlatformChar>, permissions: FilePermissions
246261
) -> Result<(), Errno> {
262+
#if os(Windows)
263+
return .failure(Errno(rawValue: ERROR_NOT_SUPPORTED))
264+
#else
247265
return nothingOrErrno(retryOnInterrupt: false) {
248266
system_mkdirat(self.rawValue, path, permissions.rawValue)
249267
}
268+
#endif
250269
}
251270

252271
/// Create a symbolic link relative to a directory file descriptor
@@ -285,8 +304,12 @@ extension FileDescriptor {
285304
original: UnsafePointer<CInterop.PlatformChar>,
286305
link: UnsafePointer<CInterop.PlatformChar>
287306
) -> Result<(), Errno> {
307+
#if os(Windows)
308+
return .failure(Errno(rawValue: ERROR_NOT_SUPPORTED))
309+
#else
288310
return nothingOrErrno(retryOnInterrupt: false) {
289311
system_symlinkat(original, self.rawValue, link)
290312
}
313+
#endif
291314
}
292315
}

0 commit comments

Comments
 (0)