Skip to content

Commit d075877

Browse files
authored
Fix ArgumentParser build failure for WASI (WebAssembly System Interface) (#794)
ArgumentParser is very useful for command-line tools that are built for wasm32-unknown-wasi and run on WebAssembly runtimes (e.g., wasmtime, wasmer, WasmKit). However, starting from version 1.6.0, the use of `DispatchSemaphore` has caused the build for wasm32-unknown-wasi to break. This change is intended to fix that issue.
1 parent 6f1a029 commit d075877

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

.github/workflows/pull_request.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,25 @@ jobs:
5151
- name: Build
5252
run: cmake --build .cmake-build
5353

54+
wasm-build:
55+
name: Wasm Build
56+
runs-on: ubuntu-latest
57+
container:
58+
image: swift:6.1-noble
59+
steps:
60+
- name: Checkout repo
61+
uses: actions/checkout@v4
62+
- name: Install Swift SDKs for WebAssembly
63+
run: |
64+
# TODO: We can replace these Swift SDKs with the swift.org one once it supports Foundation.
65+
swift sdk install https://github.com/swiftwasm/swift/releases/download/swift-wasm-6.1-RELEASE/swift-wasm-6.1-RELEASE-wasm32-unknown-wasi.artifactbundle.zip --checksum 7550b4c77a55f4b637c376f5d192f297fe185607003a6212ad608276928db992
66+
swift sdk install https://github.com/swiftwasm/swift/releases/download/swift-wasm-6.1-RELEASE/swift-wasm-6.1-RELEASE-wasm32-unknown-wasip1-threads.artifactbundle.zip --checksum 0dd273be28741f8e1eb00682c39bdc956361ed24b5572e183dd8a4e9d1c5f6ec
67+
swift sdk list
68+
- name: Build
69+
run: |
70+
swift build --swift-sdk wasm32-unknown-wasi --target ArgumentParser
71+
swift build --swift-sdk wasm32-unknown-wasip1-threads --target ArgumentParser
72+
5473
soundness:
5574
name: Soundness
5675
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main

Sources/ArgumentParser/Parsable Properties/CompletionKind.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ public struct CompletionKind {
4141
case directory
4242
case shellCommand(String)
4343
case custom(@Sendable ([String], Int, String) -> [String])
44+
#if !canImport(Dispatch)
45+
@available(*, unavailable, message: "DispatchSemaphore is unavailable")
46+
#endif
4447
case customAsync(@Sendable ([String], Int, String) async -> [String])
4548
case customDeprecated(@Sendable ([String]) -> [String])
4649
}
@@ -181,11 +184,18 @@ public struct CompletionKind {
181184
///
182185
/// The same as `custom(@Sendable @escaping ([String], Int, String) -> [String])`,
183186
/// except that the closure is asynchronous.
187+
#if !canImport(Dispatch)
188+
@available(*, unavailable, message: "DispatchSemaphore is unavailable")
189+
#endif
184190
@available(macOS 10.15, macCatalyst 13, iOS 13, tvOS 13, watchOS 6, *)
185191
public static func custom(
186192
_ completion: @Sendable @escaping ([String], Int, String) async -> [String]
187193
) -> CompletionKind {
194+
#if !canImport(Dispatch)
195+
fatalError("DispatchSemaphore is unavailable")
196+
#else
188197
CompletionKind(kind: .customAsync(completion))
198+
#endif
189199
}
190200

191201
/// Deprecated; only kept for backwards compatibility.

Sources/ArgumentParser/Parsing/CommandParser.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@
1010
//===----------------------------------------------------------------------===//
1111

1212
#if swift(>=6.0)
13+
#if canImport(Dispatch)
1314
@preconcurrency private import class Dispatch.DispatchSemaphore
15+
#endif
1416
internal import class Foundation.NSLock
1517
internal import class Foundation.ProcessInfo
1618
#else
19+
#if canImport(Dispatch)
1720
@preconcurrency import class Dispatch.DispatchSemaphore
21+
#endif
1822
import class Foundation.NSLock
1923
import class Foundation.ProcessInfo
2024
#endif
@@ -474,12 +478,16 @@ extension CommandParser {
474478
completingPrefix
475479
)
476480
case .customAsync(let complete):
481+
#if canImport(Dispatch)
477482
if #available(macOS 10.15, macCatalyst 13, iOS 13, tvOS 13, watchOS 6, *)
478483
{
479484
completions = try asyncCustomCompletions(from: args, complete: complete)
480485
} else {
481486
throw ParserError.invalidState
482487
}
488+
#else
489+
throw ParserError.invalidState
490+
#endif
483491
case .customDeprecated(let complete):
484492
completions = complete(args)
485493
default:
@@ -528,11 +536,17 @@ private func parseCustomCompletionArguments(
528536
return (Array(args), completingArgumentIndex, completingPrefix)
529537
}
530538

539+
#if !canImport(Dispatch)
540+
@available(*, unavailable, message: "DispatchSemaphore is unavailable")
541+
#endif
531542
@available(macOS 10.15, macCatalyst 13, iOS 13, tvOS 13, watchOS 6, *)
532543
private func asyncCustomCompletions(
533544
from args: [String],
534545
complete: @escaping @Sendable ([String], Int, String) async -> [String]
535546
) throws -> [String] {
547+
#if !canImport(Dispatch)
548+
throw ParserError.invalidState
549+
#else
536550
let (args, completingArgumentIndex, completingPrefix) =
537551
try parseCustomCompletionArguments(from: args)
538552

@@ -550,6 +564,7 @@ private func asyncCustomCompletions(
550564

551565
semaphore.wait()
552566
return completionsBox.value
567+
#endif
553568
}
554569

555570
// Helper class to make values sendable across concurrency boundaries

0 commit comments

Comments
 (0)