Skip to content

Commit 469fc41

Browse files
authored
Fix errors when building WasmKit for WASI (#206)
Wasm is the only unsupported platform for WasmKit in [the Swift Package Index build matrix](https://swiftpackageindex.com/swiftwasm/WasmKit). One possible use case is using features like WAT assembler or component model tools in the browser. Another use case could be polyfilling a future Wasm feature running with older Wasm features, when running WasmKit itself in an older Wasm engine. For proper testing we also need to fix `swift test` in the Swift toolchain.
1 parent 8eed37f commit 469fc41

File tree

22 files changed

+186
-93
lines changed

22 files changed

+186
-93
lines changed

.github/workflows/main.yml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ jobs:
126126
wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9"
127127
test-args: "-Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY"
128128

129-
runs-on: ubuntu-22.04
129+
runs-on: ubuntu-24.04
130130
name: "build-linux (${{ matrix.swift }})"
131131

132132
steps:
@@ -240,7 +240,7 @@ jobs:
240240
run: swift test
241241

242242
build-cmake:
243-
runs-on: ubuntu-22.04
243+
runs-on: ubuntu-24.04
244244
container:
245245
image: swift:6.2-noble
246246
steps:
@@ -254,3 +254,17 @@ jobs:
254254
- run: cmake -G Ninja -B ./build
255255
- run: cmake --build ./build
256256
- run: ./build/bin/wasmkit-cli --version
257+
258+
build-wasi:
259+
runs-on: ubuntu-24.04
260+
container:
261+
image: swift:6.2-noble
262+
steps:
263+
- uses: actions/checkout@v4
264+
- name: Install jq
265+
run: apt-get update && apt-get install -y jq
266+
- name: Install Swift SDK
267+
run: swift sdk install https://download.swift.org/swift-6.2-release/wasm/swift-6.2-RELEASE/swift-6.2-RELEASE_wasm.artifactbundle.tar.gz --checksum fe4e8648309fce86ea522e9e0d1dc48e82df6ba6e5743dbf0c53db8429fb5224
268+
- name: Build with the Swift SDK
269+
run: swift build --swift-sdk "$(swiftc -print-target-info | jq -r '.swiftCompilerTag')_wasm"
270+

Package.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,17 @@ let package = Package(
8989
.target(
9090
name: "SystemExtras",
9191
dependencies: [
92-
.product(name: "SystemPackage", package: "swift-system")
92+
.product(name: "SystemPackage", package: "swift-system"),
93+
.target(name: "CSystemExtras", condition: .when(platforms: [.wasi])),
9394
],
9495
exclude: ["CMakeLists.txt"],
9596
swiftSettings: [
9697
.define("SYSTEM_PACKAGE_DARWIN", .when(platforms: DarwinPlatforms))
9798
]
9899
),
99100

101+
.target(name: "CSystemExtras"),
102+
100103
.executableTarget(
101104
name: "WITTool",
102105
dependencies: [
@@ -120,8 +123,8 @@ let package = Package(
120123

121124
if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
122125
package.dependencies += [
123-
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.2.2"),
124-
.package(url: "https://github.com/apple/swift-system", .upToNextMajor(from: "1.3.0")),
126+
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.1"),
127+
.package(url: "https://github.com/apple/swift-system", from: "1.5.0"),
125128
]
126129
} else {
127130
package.dependencies += [

Sources/CLI/Commands/Run.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,16 @@ struct Run: ParsableCommand {
5959
var directories: [String] = []
6060

6161
enum ThreadingModel: String, ExpressibleByArgument, CaseIterable {
62-
case direct
62+
#if !os(WASI)
63+
case direct
64+
#endif
6365
case token
6466

6567
func resolve() -> EngineConfiguration.ThreadingModel {
6668
switch self {
67-
case .direct: return .direct
69+
#if !os(WASI)
70+
case .direct: return .direct
71+
#endif
6872
case .token: return .token
6973
}
7074
}

Sources/CSystemExtras/CSystemExtras.c

Whitespace-only changes.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include <time.h>
2+
3+
inline static clockid_t csystemextras_monotonic_clockid() {
4+
return CLOCK_MONOTONIC;
5+
}

Sources/SystemExtras/Clock.swift

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import Android
1212
#elseif os(Windows)
1313
import CSystem
1414
import ucrt
15+
#elseif os(WASI)
16+
import CSystemExtras
17+
import WASILibc
1518
#else
1619
#error("Unsupported Platform")
1720
#endif
@@ -41,12 +44,17 @@ extension Clock {
4144
public static var rawMonotonic: Clock { Clock(rawValue: _CLOCK_MONOTONIC_RAW) }
4245
#endif
4346

44-
#if SYSTEM_PACKAGE_DARWIN || os(Linux) || os(Android) || os(OpenBSD) || os(FreeBSD) || os(WASI)
47+
#if SYSTEM_PACKAGE_DARWIN || os(Linux) || os(Android) || os(OpenBSD) || os(FreeBSD)
4548
@_alwaysEmitIntoClient
4649
public static var monotonic: Clock { Clock(rawValue: _CLOCK_MONOTONIC) }
4750
#endif
4851

49-
#if os(OpenBSD) || os(FreeBSD) || os(WASI)
52+
#if os(WASI)
53+
@_alwaysEmitIntoClient
54+
public static var monotonic: Clock { Clock(rawValue: csystemextras_monotonic_clockid()) }
55+
#endif
56+
57+
#if os(OpenBSD) || os(FreeBSD)
5058
@_alwaysEmitIntoClient
5159
public static var uptime: Clock { Clock(rawValue: _CLOCK_UPTIME) }
5260
#endif
@@ -92,10 +100,10 @@ extension Clock {
92100
public var rawValue: CInterop.TimeSpec
93101

94102
@_alwaysEmitIntoClient
95-
public var seconds: Int { rawValue.tv_sec }
103+
public var seconds: Int64 { .init(rawValue.tv_sec) }
96104

97105
@_alwaysEmitIntoClient
98-
public var nanoseconds: Int { rawValue.tv_nsec }
106+
public var nanoseconds: Int64 { .init(rawValue.tv_nsec) }
99107

100108
@_alwaysEmitIntoClient
101109
public init(rawValue: CInterop.TimeSpec) {
@@ -104,17 +112,25 @@ extension Clock {
104112

105113
@_alwaysEmitIntoClient
106114
public init(seconds: Int, nanoseconds: Int) {
107-
self.init(rawValue: CInterop.TimeSpec(tv_sec: seconds, tv_nsec: nanoseconds))
115+
self.init(rawValue: CInterop.TimeSpec(tv_sec: .init(seconds), tv_nsec: nanoseconds))
108116
}
109117

110118
@_alwaysEmitIntoClient
111119
public static var now: TimeSpec {
120+
#if os(WASI)
121+
return TimeSpec(rawValue: CInterop.TimeSpec(tv_sec: 0, tv_nsec: Int(UTIME_NOW)))
122+
#else
112123
return TimeSpec(rawValue: CInterop.TimeSpec(tv_sec: 0, tv_nsec: Int(_UTIME_NOW)))
124+
#endif
113125
}
114126

115127
@_alwaysEmitIntoClient
116128
public static var omit: TimeSpec {
129+
#if os(WASI)
130+
return TimeSpec(rawValue: CInterop.TimeSpec(tv_sec: 0, tv_nsec: Int(UTIME_OMIT)))
131+
#else
117132
return TimeSpec(rawValue: CInterop.TimeSpec(tv_sec: 0, tv_nsec: Int(_UTIME_OMIT)))
133+
#endif
118134
}
119135
}
120136
}

Sources/SystemExtras/Constants.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import Android
1212
#elseif os(Windows)
1313
import CSystem
1414
import ucrt
15+
#elseif os(WASI)
16+
import WASILibc
1517
#else
1618
#error("Unsupported Platform")
1719
#endif
@@ -43,7 +45,7 @@ internal var _AT_NO_AUTOMOUNT: CInt { AT_NO_AUTOMOUNT }
4345
#endif
4446
*/
4547

46-
#if !os(Windows)
48+
#if !os(Windows) && !os(WASI)
4749
@_alwaysEmitIntoClient
4850
internal var _F_GETFL: CInt { F_GETFL }
4951
@_alwaysEmitIntoClient
@@ -61,7 +63,7 @@ internal var _O_SYNC: CInt { O_SYNC }
6163
internal var _O_RSYNC: CInt { O_RSYNC }
6264
#endif
6365

64-
#if !os(Windows)
66+
#if !os(Windows) && !os(WASI)
6567
@_alwaysEmitIntoClient
6668
internal var _UTIME_NOW: CInt {
6769
#if os(Linux) || os(Android)
@@ -132,16 +134,15 @@ internal var _CLOCK_BOOTTIME: CInterop.ClockId { CLOCK_BOOTTIME }
132134
@_alwaysEmitIntoClient
133135
internal var _CLOCK_MONOTONIC_RAW: CInterop.ClockId { CLOCK_MONOTONIC_RAW }
134136
#endif
135-
#if SYSTEM_PACKAGE_DARWIN || os(Linux) || os(Android) || os(OpenBSD) || os(FreeBSD) || os(WASI)
137+
#if SYSTEM_PACKAGE_DARWIN || os(Linux) || os(Android) || os(OpenBSD) || os(FreeBSD)
136138
@_alwaysEmitIntoClient
137139
internal var _CLOCK_MONOTONIC: CInterop.ClockId { CLOCK_MONOTONIC }
138140
#endif
139-
140141
#if SYSTEM_PACKAGE_DARWIN
141142
@_alwaysEmitIntoClient
142143
internal var _CLOCK_UPTIME_RAW: CInterop.ClockId { CLOCK_UPTIME_RAW }
143144
#endif
144-
#if os(OpenBSD) || os(FreeBSD) || os(WASI)
145+
#if os(OpenBSD) || os(FreeBSD)
145146
@_alwaysEmitIntoClient
146147
internal var _CLOCK_UPTIME: CInterop.ClockId { CLOCK_UPTIME }
147148
#endif

Sources/SystemExtras/FileAtOperations.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import Android
1212
#elseif os(Windows)
1313
import ucrt
1414
import WinSDK
15+
#elseif os(WASI)
16+
import WASILibc
1517
#else
1618
#error("Unsupported Platform")
1719
#endif

Sources/SystemExtras/FileOperations.swift

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import Android
1212
#elseif os(Windows)
1313
import ucrt
1414
import WinSDK
15+
#elseif os(WASI)
16+
import WASILibc
1517
#else
1618
#error("Unsupported Platform")
1719
#endif
@@ -344,6 +346,8 @@ extension FileDescriptor {
344346
#if os(Windows)
345347
// FIXME: Need to query by `NtQueryInformationFile`?
346348
return .success(OpenOptions(rawValue: 0))
349+
#elseif os(WASI)
350+
return .failure(Errno.notSupported)
347351
#else
348352
valueOrErrno(retryOnInterrupt: false) {
349353
system_fcntl(self.rawValue, _F_GETFL)
@@ -511,15 +515,31 @@ extension FileDescriptor {
511515

512516
@_alwaysEmitIntoClient
513517
public var name: String {
518+
#if os(WASI)
519+
// ClangImporter can't handle `char d_name[]`, but it's right after `unsigned char d_type`.
520+
withUnsafePointer(to: &rawValue.pointee.d_type) { dType in
521+
let dName = dType + 1
522+
return dName.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: dName)) {
523+
// String initializer copies the given buffer contents, so it's safe.
524+
return String(cString: $0)
525+
}
526+
}
527+
#else
514528
withUnsafePointer(to: &rawValue.pointee.d_name) { dName in
515529
dName.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: dName)) {
516530
// String initializer copies the given buffer contents, so it's safe.
517531
return String(cString: $0)
518532
}
519533
}
534+
#endif
520535
}
521536

522537
public var fileType: FileType {
538+
#if os(WASI)
539+
// https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#-filetype-variant
540+
// https://github.com/WebAssembly/wasi-libc/blob/6b45da5b05bc0edda355a6de46101d4b21631985/libc-bottom-half/headers/public/wasi/api.h#L780C9-L780C32
541+
FileType(rawValue: .init(rawValue.pointee.d_type))
542+
#else
523543
switch CInt(rawValue.pointee.d_type) {
524544
case _DT_REG: return .file
525545
case _DT_BLK: return .blockDevice
@@ -529,6 +549,7 @@ extension FileDescriptor {
529549
case _DT_SOCK: return .socket
530550
default: return .unknown
531551
}
552+
#endif
532553
}
533554
}
534555

@@ -657,7 +678,7 @@ public enum FileTime {
657678
public typealias FileTime = Clock.TimeSpec
658679
#endif
659680

660-
#if !os(Windows)
681+
#if !os(Windows) && !os(WASI)
661682

662683
// MARK: - Synchronized Input and Output
663684

Sources/SystemExtras/Syscalls.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import Android
1212
#elseif os(Windows)
1313
import ucrt
1414
import WinSDK
15+
#elseif os(WASI)
16+
import WASILibc
1517
#else
1618
#error("Unsupported Platform")
1719
#endif
@@ -127,7 +129,7 @@ internal func system_symlinkat(
127129
extension CInterop {
128130
#if SYSTEM_PACKAGE_DARWIN
129131
public typealias DirP = UnsafeMutablePointer<DIR>
130-
#elseif os(Linux) || os(Android)
132+
#elseif os(Linux) || os(Android) || os(WASI)
131133
public typealias DirP = OpaquePointer
132134
#else
133135
#error("Unsupported Platform")

0 commit comments

Comments
 (0)