Skip to content

Commit

Permalink
Fix build on non-macOS Apple platforms
Browse files Browse the repository at this point in the history
  • Loading branch information
kateinoigakukun committed Jul 28, 2024
1 parent 5cb496d commit 34a99c7
Show file tree
Hide file tree
Showing 15 changed files with 272 additions and 232 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 54,10 @@ jobs:
EOS
- run: ./Vendor/checkout-dependency
- run: swift test --sanitize address
- run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=iOS
- run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=watchOS
- run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=tvOS
- run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=visionOS

build-linux:
strategy:
Expand Down
4 changes: 2 additions & 2 deletions Sources/CLI/Run/Run.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 42,7 @@ struct Run: ParsableCommand {
log("Started parsing module", verbose: true)

let module: Module
if verbose, #available(macOS 13.0, *) {
if verbose, #available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) {
let (parsedModule, parseTime) = try measure {
try parseWasm(filePath: FilePath(path))
}
Expand Down Expand Up @@ -70,7 70,7 @@ struct Run: ParsableCommand {
invoke = entry
}

if #available(macOS 13.0, *) {
if #available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) {
let (_, invokeTime) = try measure(execution: invoke)
log("Finished invoking function \"\(path)\": \(invokeTime)", verbose: true)
} else {
Expand Down
2 changes: 1 addition & 1 deletion Sources/WITExtractor/ModuleTranslation.swift
Original file line number Diff line number Diff line change
@@ -1,4 1,4 @@
@available(macOS 11, *)
@available(macOS 11, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
struct ModuleTranslation {
let diagnostics: DiagnosticCollection
let typeMapping: TypeMapping
Expand Down
2 changes: 1 addition & 1 deletion Sources/WITExtractor/SourceSummary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 49,7 @@ public struct SwiftFunctionSource {
let name: String
}

@available(macOS 11, *)
@available(macOS 11, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
struct SourceSummaryBuilder {
let diagnostics: DiagnosticCollection
let typeMapping: TypeMapping
Expand Down
42 changes: 23 additions & 19 deletions Sources/WITExtractor/SwiftAPIDigester.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,26 116,30 @@ struct SwiftAPIDigester {
typealias SDKNodeType = SDKNodeInherit<SDKNodeBody, SDKNodeTypeBody>
typealias SDKNodeTypeNominal = SDKNodeInherit<SDKNodeType, SDKNodeTypeNominalBody>

@available(macOS 11, *)
@available(macOS 11, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
func dumpSDK(moduleName: String, arguments: [String]) throws -> Output {
var args = [
"-dump-sdk",
"-module", moduleName,
// Emit output to stdout
"-o", "-",
]
args = arguments
let process = Process()
process.executableURL = executableURL
process.arguments = args
let stdoutPipe = Pipe()
process.standardOutput = stdoutPipe
try process.run()
guard let output = try stdoutPipe.fileHandleForReading.readToEnd() else {
throw SwiftAPIDigesterError.unexpectedEmptyOutput
}
process.waitUntilExit()
return try Output.parse(output)
#if os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
fatalError("WITExtractor does not support platforms where Foundation.Process is unavailable")
#else
var args = [
"-dump-sdk",
"-module", moduleName,
// Emit output to stdout
"-o", "-",
]
args = arguments
let process = Process()
process.executableURL = executableURL
process.arguments = args
let stdoutPipe = Pipe()
process.standardOutput = stdoutPipe
try process.run()
guard let output = try stdoutPipe.fileHandleForReading.readToEnd() else {
throw SwiftAPIDigesterError.unexpectedEmptyOutput
}
process.waitUntilExit()
return try Output.parse(output)
#endif
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/WITExtractor/TypeMapping.swift
Original file line number Diff line number Diff line change
@@ -1,4 1,4 @@
@available(macOS 11, *)
@available(macOS 11, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
struct TypeMapping {
typealias DeclScope = [SwiftAPIDigester.SDKNodeDecl]
struct DeclSource {
Expand Down
8 changes: 6 additions & 2 deletions Sources/WITExtractor/WITExtractor.swift
Original file line number Diff line number Diff line change
@@ -1,5 1,9 @@
import Foundation

@available(iOS, unavailable)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
@available(visionOS, unavailable)
public struct WITExtractor {
public struct Output {
public var witContents: String
Expand Down Expand Up @@ -31,7 35,7 @@ public struct WITExtractor {
}

public func run(moduleName: String) throws -> Output {
guard #available(macOS 11, *) else {
guard #available(macOS 11, iOS 14.0, watchOS 7.0, tvOS 14.0, *) else {
fatalError("WITExtractor requires macOS 11 ")
}
let header = """
Expand All @@ -45,7 49,7 @@ public struct WITExtractor {
return output
}

@available(macOS 11, *)
@available(macOS 11, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
func runWithoutHeader(moduleName: String) throws -> Output {
let output = try digester.dumpSDK(moduleName: moduleName, arguments: extraDigesterArguments)
var typeMapping = TypeMapping()
Expand Down
76 changes: 40 additions & 36 deletions Sources/WITTool/WITTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,45 123,49 @@ struct ExtractWIT: ParsableCommand {
var digesterArgs: [String] = []

func run() throws {
guard #available(macOS 11, *) else {
fatalError("ExtractWIT requires macOS 11 ")
}

let extractor = WITExtractor(
namespace: namespace,
packageName: packageName,
digesterPath: digesterPath,
extraDigesterArguments: digesterArgs
)
let output = try extractor.run(moduleName: moduleName)
try output.witContents.write(toFile: witOutputPath, atomically: true, encoding: .utf8)

for diagnostic in extractor.diagnostics {
try FileHandle.standardError.write(contentsOf: Data((diagnostic.description "\n").utf8))
}
#if os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
fatalError("WITExtractor does not support platforms where Foundation.Process is unavailable")
#else
guard #available(macOS 11, *) else {
fatalError("ExtractWIT requires macOS 11 ")
}

// Generate overlay shim to export extracted WIT interface
do {
let sourceFile = try SourceFileSyntax.parse(
output.witContents,
fileName: "<extracted>.wit"
let extractor = WITExtractor(
namespace: namespace,
packageName: packageName,
digesterPath: digesterPath,
extraDigesterArguments: digesterArgs
)
let packageResolver = PackageResolver()
let packageUnit = try packageResolver.register(packageSources: [sourceFile])
let context = SemanticsContext(rootPackage: packageUnit, packageResolver: packageResolver)
let (interface, _) = try context.lookupInterface(name: output.interfaceName, contextPackage: packageUnit)

let swiftSource = try generateGuestExportInterface(
context: context,
sourceFile: sourceFile,
interface: interface,
sourceSummaryProvider: SwiftSourceSummaryProvider(
summary: output.sourceSummary,
typeMapping: output.typeMapping
let output = try extractor.run(moduleName: moduleName)
try output.witContents.write(toFile: witOutputPath, atomically: true, encoding: .utf8)

for diagnostic in extractor.diagnostics {
try FileHandle.standardError.write(contentsOf: Data((diagnostic.description "\n").utf8))
}

// Generate overlay shim to export extracted WIT interface
do {
let sourceFile = try SourceFileSyntax.parse(
output.witContents,
fileName: "<extracted>.wit"
)
)
try swiftSource.write(toFile: swiftOutputPath, atomically: true, encoding: .utf8)
}
let packageResolver = PackageResolver()
let packageUnit = try packageResolver.register(packageSources: [sourceFile])
let context = SemanticsContext(rootPackage: packageUnit, packageResolver: packageResolver)
let (interface, _) = try context.lookupInterface(name: output.interfaceName, contextPackage: packageUnit)

let swiftSource = try generateGuestExportInterface(
context: context,
sourceFile: sourceFile,
interface: interface,
sourceSummaryProvider: SwiftSourceSummaryProvider(
summary: output.sourceSummary,
typeMapping: output.typeMapping
)
)
try swiftSource.write(toFile: swiftOutputPath, atomically: true, encoding: .utf8)
}
#endif
}

private func writeFile(_ filePath: String, contents: String) throws {
Expand Down
54 changes: 29 additions & 25 deletions Tests/WATTests/EncoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,35 75,39 @@ class EncoderTests: XCTestCase {
}

func testSpectest() throws {
guard let wast2json = TestSupport.lookupExecutable("wast2json") else {
throw XCTSkip("wast2json not found in PATH")
}
#if os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
throw XCTSkip("Spectest compatibility test requires Foundation.Process")
#else
guard let wast2json = TestSupport.lookupExecutable("wast2json") else {
throw XCTSkip("wast2json not found in PATH")
}

var stats = CompatibilityTestStats()
let excluded: [String] = []
for wastFile in Spectest.wastFiles(include: [], exclude: excluded) {
try TestSupport.withTemporaryDirectory { tempDir, shouldRetain in
let jsonFileName = wastFile.deletingPathExtension().lastPathComponent ".json"
let json = URL(fileURLWithPath: tempDir).appendingPathComponent(jsonFileName)
var stats = CompatibilityTestStats()
let excluded: [String] = []
for wastFile in Spectest.wastFiles(include: [], exclude: excluded) {
try TestSupport.withTemporaryDirectory { tempDir, shouldRetain in
let jsonFileName = wastFile.deletingPathExtension().lastPathComponent ".json"
let json = URL(fileURLWithPath: tempDir).appendingPathComponent(jsonFileName)

let wast2jsonProcess = try Process.run(
wast2json,
arguments: [wastFile.path, "-o", json.path]
)
wast2jsonProcess.waitUntilExit()
let wast2jsonProcess = try Process.run(
wast2json,
arguments: [wastFile.path, "-o", json.path]
)
wast2jsonProcess.waitUntilExit()

do {
try checkWabtCompatibility(wast: wastFile, json: json, stats: &stats)
} catch {
stats.failed.insert(wastFile.lastPathComponent)
shouldRetain = true
XCTFail("Error while checking compatibility between \(wastFile) and \(json.path): \(error)")
do {
try checkWabtCompatibility(wast: wastFile, json: json, stats: &stats)
} catch {
stats.failed.insert(wastFile.lastPathComponent)
shouldRetain = true
XCTFail("Error while checking compatibility between \(wastFile) and \(json.path): \(error)")
}
}
}
}
print("Spectest compatibility: \(stats.run - stats.failed.count) / \(stats.run)")
if !stats.failed.isEmpty {
print("Failed test cases: \(stats.failed.sorted())")
}
print("Spectest compatibility: \(stats.run - stats.failed.count) / \(stats.run)")
if !stats.failed.isEmpty {
print("Failed test cases: \(stats.failed.sorted())")
}
#endif
}
}
70 changes: 37 additions & 33 deletions Tests/WITExtractorPluginTests/TestSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,40 47,44 @@ struct TestSupport {
}

func assertSwiftPackage(fixturePackage: String, _ trailingArguments: [String]) throws -> String {
guard let config = TestSupport.Configuration.default else {
throw XCTSkip("Please create 'Tests/default.json'")
}
let swiftExecutable = config.hostSwiftExecutablePath
let packagePath = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.appendingPathComponent("Fixtures")
.appendingPathComponent(fixturePackage)

return try TestSupport.withTemporaryDirectory { buildDir in
var arguments = ["package", "--package-path", packagePath.path, "--scratch-path", buildDir]
if let sdkRootPath = config.hostSdkRootPath {
arguments = ["--sdk", sdkRootPath]
#if os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
throw XCTSkip("WITExtractor does not support platforms where Foundation.Process is unavailable")
#else
guard let config = TestSupport.Configuration.default else {
throw XCTSkip("Please create 'Tests/default.json'")
}
arguments = trailingArguments
let stdoutPipe = Pipe()
let process = Process()
process.executableURL = URL(fileURLWithPath: swiftExecutable.path)
process.arguments = arguments
process.standardOutput = stdoutPipe
try process.run()
process.waitUntilExit()
let swiftExecutable = config.hostSwiftExecutablePath
let packagePath = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.appendingPathComponent("Fixtures")
.appendingPathComponent(fixturePackage)

guard process.terminationStatus == 0 else {
throw TestSupport.Error(
description: "Failed to execute \(([swiftExecutable.path] arguments).joined(separator: " "))"
)
}
guard let stdoutBytes = try stdoutPipe.fileHandleForReading.readToEnd() else { return "" }
struct Output: Codable {
let witOutputPath: String
let swiftOutputPath: String
return try TestSupport.withTemporaryDirectory { buildDir in
var arguments = ["package", "--package-path", packagePath.path, "--scratch-path", buildDir]
if let sdkRootPath = config.hostSdkRootPath {
arguments = ["--sdk", sdkRootPath]
}
arguments = trailingArguments
let stdoutPipe = Pipe()
let process = Process()
process.executableURL = URL(fileURLWithPath: swiftExecutable.path)
process.arguments = arguments
process.standardOutput = stdoutPipe
try process.run()
process.waitUntilExit()

guard process.terminationStatus == 0 else {
throw TestSupport.Error(
description: "Failed to execute \(([swiftExecutable.path] arguments).joined(separator: " "))"
)
}
guard let stdoutBytes = try stdoutPipe.fileHandleForReading.readToEnd() else { return "" }
struct Output: Codable {
let witOutputPath: String
let swiftOutputPath: String
}
let jsonOutput = try JSONDecoder().decode(Output.self, from: stdoutBytes)
return try String(contentsOfFile: jsonOutput.witOutputPath)
}
let jsonOutput = try JSONDecoder().decode(Output.self, from: stdoutBytes)
return try String(contentsOfFile: jsonOutput.witOutputPath)
}
#endif
}
Loading

0 comments on commit 34a99c7

Please sign in to comment.