Skip to content

Embedded: Swift SDK now passes the -Xcc -D__EMBEDDED_SWIFT__ #369

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

Merged
merged 2 commits into from
Aug 15, 2025
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
84 changes: 77 additions & 7 deletions Plugins/PackageToJS/Tests/ExampleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,78 @@ extension Trait where Self == ConditionTrait {

static func requireSwiftSDK(triple: String) -> ConditionTrait {
.enabled(
if: ProcessInfo.processInfo.environment["SWIFT_SDK_ID"] != nil
&& ProcessInfo.processInfo.environment["SWIFT_PATH"] != nil
&& ProcessInfo.processInfo.environment["SWIFT_SDK_ID"]!.hasSuffix(triple),
if: {
guard let swiftSDKID = ProcessInfo.processInfo.environment["SWIFT_SDK_ID"],
ProcessInfo.processInfo.environment["SWIFT_PATH"] != nil
else {
return false
}
func sanityCheckCompatibility(triple: String) -> Bool {
return swiftSDKID.hasSuffix(triple)
}
// For compatibility with old SDKs, we check wasm32-unknown-wasi as well when
// wasm32-unknown-wasip1 is requested.
if triple == "wasm32-unknown-wasip1" {
if sanityCheckCompatibility(triple: "wasm32-unknown-wasi") {
return true
}
}
return sanityCheckCompatibility(triple: triple)
}(),
"Requires SWIFT_SDK_ID and SWIFT_PATH environment variables"
)
}

static var requireEmbeddedSwift: ConditionTrait {
static func requireEmbeddedSwiftInToolchain(triple: String) -> ConditionTrait {
// Check if $SWIFT_PATH/../lib/swift/embedded/wasm32-unknown-none-wasm/ exists
return .enabled(
if: {
guard let swiftPath = ProcessInfo.processInfo.environment["SWIFT_PATH"] else {
return false
}
let embeddedPath = URL(fileURLWithPath: swiftPath).deletingLastPathComponent()
.appending(path: "lib/swift/embedded/wasm32-unknown-none-wasm")
.appending(path: "lib/swift/embedded/\(triple)")
return FileManager.default.fileExists(atPath: embeddedPath.path)
}(),
"Requires embedded Swift SDK under $SWIFT_PATH/../lib/swift/embedded"
)
}

static func requireEmbeddedSwiftInSwiftSDK() -> ConditionTrait {
// Check if ${SWIFT_SDK_ID}-embedded is available
return .enabled(
if: {
/// Check if the Swift SDK with the given ID is available.
func isSwiftSDKAvailable(_ id: String, swiftPath: String) -> Bool {
let swiftExecutable = URL(
fileURLWithPath: "swift",
relativeTo: URL(fileURLWithPath: swiftPath)
)
let process = Process()
process.executableURL = swiftExecutable
let arguments = ["sdk", "configure", "--show-configuration", id]
process.arguments = arguments
process.standardOutput = FileHandle.nullDevice
process.standardError = FileHandle.nullDevice
do {
try process.run()
process.waitUntilExit()
return process.terminationStatus == 0
} catch {
return false
}
}
guard let swiftPath = ProcessInfo.processInfo.environment["SWIFT_PATH"],
let swiftSDKID = ProcessInfo.processInfo.environment["SWIFT_SDK_ID"]
else {
return false
}
let embeddedSDKID = "\(swiftSDKID)-embedded"
return isSwiftSDKAvailable(embeddedSDKID, swiftPath: swiftPath)
}(),
"Requires SWIFT_SDK_ID to contain 'embedded'"
)
}
}

@Suite struct ExampleTests {
Expand All @@ -46,6 +97,11 @@ extension Trait where Self == ConditionTrait {
ProcessInfo.processInfo.environment["SWIFT_PATH"]
}

static func getEmbeddedSwiftSDKID() -> String? {
guard let swiftSDKID = getSwiftSDKID() else { return nil }
return "\(swiftSDKID)-embedded"
}

static let repoPath = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.deletingLastPathComponent()
Expand Down Expand Up @@ -220,7 +276,7 @@ extension Trait where Self == ConditionTrait {
let swiftPath = try #require(Self.getSwiftPath())
try withPackage(at: "Examples/Testing") { packageDir, runProcess, runSwift in
try runSwift(
["package", "--swift-sdk", swiftSDKID, "js", "test", "--enable-code-coverage"],
["package", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test", "--enable-code-coverage"],
[
"LLVM_PROFDATA_PATH": URL(fileURLWithPath: swiftPath).appending(path: "llvm-profdata").path
]
Expand Down Expand Up @@ -267,7 +323,8 @@ extension Trait where Self == ConditionTrait {
}
}

@Test(.requireEmbeddedSwift) func embedded() throws {
@Test(.requireEmbeddedSwiftInToolchain(triple: "wasm32-unknown-none-wasm"))
func embeddedWasmUnknownNone() throws {
try withPackage(at: "Examples/Embedded") { packageDir, _, runSwift in
try runSwift(
["package", "--triple", "wasm32-unknown-none-wasm", "js", "-c", "release"],
Expand All @@ -278,6 +335,19 @@ extension Trait where Self == ConditionTrait {
}
}

@Test(.requireEmbeddedSwiftInSwiftSDK())
func embeddedWasmUnknownWasi() throws {
let swiftSDKID = try #require(Self.getEmbeddedSwiftSDKID())
try withPackage(at: "Examples/Embedded") { packageDir, _, runSwift in
try runSwift(
["package", "--swift-sdk", swiftSDKID, "js", "-c", "release"],
[
"JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM": "true"
]
)
}
}

@Test(.requireSwiftSDK)
func continuationLeakInTest_XCTest() throws {
let swiftSDKID = try #require(Self.getSwiftSDKID())
Expand Down
5 changes: 1 addition & 4 deletions Sources/_CJavaScriptKit/_CJavaScriptKit.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ void swjs_cleanup_host_function_call(void *argv_buffer) {
free(argv_buffer);
}

// NOTE: This __wasi__ check is a hack for Embedded compatibility (assuming that if __wasi__ is defined, we are not building for Embedded)
// cdecls don't work in Embedded, but @_expose(wasm) can be used with Swift >=6.0
// the previously used `#if __Embedded` did not play well with SwiftPM (defines needed to be on every target up the chain)
# ifdef __wasi__
# if defined(__wasi__) && !defined(__EMBEDDED_SWIFT__)
bool _call_host_function_impl(const JavaScriptHostFuncRef host_func_ref,
const RawJSValue *argv, const int argc,
const JavaScriptObjectRef callback_func);
Expand Down