diff --git a/swift/swan-swiftc/Package.resolved b/swift/swan-swiftc/Package.resolved index 083cfd9..9c66982 100644 --- a/swift/swan-swiftc/Package.resolved +++ b/swift/swan-swiftc/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/mtynior/ColorizeSwift.git", "state": { "branch": null, - "revision": "2a354639173d021f4648cf1912b2b00a3a7cd83c", - "version": "1.6.0" + "revision": "4e7daa138510b77a3cce9f6a31a116f8536347dd", + "version": "1.7.0" } }, { @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/apple/swift-argument-parser", "state": { "branch": null, - "revision": "3d79b2b5a2e5af52c14e462044702ea7728f5770", - "version": "0.1.0" + "revision": "41982a3656a71c768319979febd796c6fd111d5c", + "version": "1.5.0" } } ] diff --git a/swift/swan-swiftc/Package.swift b/swift/swan-swiftc/Package.swift index b200727..0ea60a4 100644 --- a/swift/swan-swiftc/Package.swift +++ b/swift/swan-swiftc/Package.swift @@ -1,19 +1,23 @@ -// swift-tools-version:5.1 +// swift-tools-version:6.0 import PackageDescription let package = Package( - name: "swan-swiftc", - products: [ - .executable(name: "swan-swiftc", targets: ["swan-swiftc"]) - ], - dependencies: [ - .package(url: "https://github.com/mtynior/ColorizeSwift.git", from: "1.5.0"), - .package(url: "https://github.com/apple/swift-argument-parser", from: "0.0.1") - ], - targets: [ - .target( - name: "swan-swiftc", - dependencies: ["ArgumentParser", "ColorizeSwift"]) - ] + name: "swan-swiftc", + products: [ + .executable(name: "swan-swiftc", targets: ["swan-swiftc"]) + ], + dependencies: [ + .package(url: "https://github.com/mtynior/ColorizeSwift.git", from: "1.5.0"), + .package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"), + ], + targets: [ + .executableTarget( + name: "swan-swiftc", + dependencies: [ + .product(name: "ArgumentParser", package: "swift-argument-parser"), + .product(name: "ColorizeSwift", package: "ColorizeSwift"), + ] + ) + ] ) diff --git a/swift/swan-swiftc/Sources/swan-swiftc/main.swift b/swift/swan-swiftc/Sources/swan-swiftc/swan-swiftc.swift similarity index 54% rename from swift/swan-swiftc/Sources/swan-swiftc/main.swift rename to swift/swan-swiftc/Sources/swan-swiftc/swan-swiftc.swift index 23e3f09..325d4fe 100644 --- a/swift/swan-swiftc/Sources/swan-swiftc/main.swift +++ b/swift/swan-swiftc/Sources/swan-swiftc/swan-swiftc.swift @@ -22,93 +22,100 @@ import ColorizeSwift import Foundation struct Constants { - static let defaultSwanDir = "swan-dir/" - static let swiftcLog = "swiftc.log" + static let defaultSwanDir = URL(fileURLWithPath: "swan-dir/") + static let swiftcLog = "swiftc.log" + static let defaultSDK = SDK.macosx } -extension String: Error {} +enum SDK: String, ExpressibleByArgument { + case driverkit = "driverkit" + case ios = "iphoneos" + case iphonesimulator = "iphonesimulator" + case macosx = "macosx" + case appletvos = "appletvos" + case appletvsimulator = "appletvsimulator" + case xros = "xros" + case watchos = "watchos" + case watchsimulator = "watchsimulator" +} + +extension URL: @retroactive ExpressibleByArgument { + public init(argument: String) { + self = URL(fileURLWithPath: argument).absoluteURL + } +} +@main struct SWANSwiftcBuild: ParsableCommand { static let configuration = CommandConfiguration( - abstract: "Build and dump SIL for a Swift application using swiftc.") - - // Ignore the warning generated from this. - @Option(default: Constants.defaultSwanDir, help: "Output directory for SIL.") - var swanDir: String? - - @Argument(help: "Prefix these arguments with --") + abstract: "Build and dump SIL for a Swift application using swiftc." + ) + + @Option(help: "Output directory for SIL.") + var swanDir: URL = Constants.defaultSwanDir + + @Argument(help: "Additional arguments to pass to swiftc. Prefix these arguments with --") var swiftcArgs: [String] - - init() { } - + + @Option(help: "The SDK to use.") + var sdk: SDK = Constants.defaultSDK + + lazy var srcCopyDir = swanDir.appendingPathComponent("src") + lazy var swiftcLog = swanDir.appendingPathComponent(Constants.swiftcLog) + func generateSwiftcArgs() -> [String] { - return ["swiftc"] + self.swiftcArgs + [ + ["xcrun", "--sdk", self.sdk.rawValue, "swiftc"] + self.swiftcArgs + [ "-emit-sil", "-Xfrontend", - "-gsil", + "-sil-based-debuginfo", "-Xllvm", "-sil-print-debuginfo", "-Xllvm", - "-sil-print-before=SerializeSILPass" + "-sil-print-before=SerializeSILPass", ] } - + func printStatus(_ msg: String) { print(msg.foregroundColor(.steelBlue1_2).bold()) } - + func printFailure(_ msg: String) { print(msg.foregroundColor(.red).bold()) } - + func printWarning(_ msg: String) { print(msg.foregroundColor(.orange3).bold()) } - - func run() throws { - - let outputDir = URL(fileURLWithPath: self.swanDir!) - let srcCopyDir = outputDir.appendingPathComponent("src") - - let swiftcLog = outputDir.appendingPathComponent(Constants.swiftcLog) - var outputSilFileName = "out.sil" - + mutating func validate() throws { do { - try FileManager.default.createDirectory(at: outputDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory(at: swanDir, withIntermediateDirectories: true) } catch { - printFailure("The output directory could not be created at " + outputDir.path - + ".\nReason: " + error.localizedDescription) + printFailure( + "The output directory could not be created at " + swanDir.path + + ".\nReason: " + error.localizedDescription) throw ExitCode.failure } - if (FileManager().fileExists(atPath: srcCopyDir.path)) { - try FileManager().removeItem(atPath: srcCopyDir.path) - } - + try? FileManager.default.removeItem(at: srcCopyDir) + do { try FileManager.default.createDirectory(at: srcCopyDir, withIntermediateDirectories: true) } catch { - printFailure("The src directory could not be created at " + srcCopyDir.path - + ".\nReason: " + error.localizedDescription) + printFailure( + "The src directory could not be created at " + srcCopyDir.path + + ".\nReason: " + error.localizedDescription) throw ExitCode.failure } - - // swan-swiftc doesn't actually expect multiple source files - // I'm not sure what the output would look like for that - try self.swiftcArgs.forEach { (str) in - if (str.hasSuffix(".swift")) { - outputSilFileName = str + ".sil" - try FileManager().copyItem(atPath: URL(fileURLWithPath: str).path, toPath: srcCopyDir.appendingPathComponent(str).path) - } - } - + } + + mutating func runSwiftC() throws -> String { let args = generateSwiftcArgs() printStatus("Running " + args.joined(separator: " ")) - + let task = Process() let pipe = Pipe() - + task.launchPath = URL(string: "/usr/bin/env")?.absoluteString task.arguments = args task.standardInput = FileHandle.nullDevice @@ -121,49 +128,73 @@ struct SWANSwiftcBuild: ParsableCommand { let data = pipe.fileHandleForReading.readDataToEndOfFile() task.waitUntilExit() - + let output: String = String(data: data, encoding: String.Encoding.utf8)! - let end = DispatchTime.now() let nanoTime = (end.uptimeNanoseconds - start.uptimeNanoseconds) let timeInterval = Int(round(Double(nanoTime) / 1_000_000_000)) - + printStatus("\nswiftc finished in \(timeInterval.description)s") - + do { try output.write(to: swiftcLog, atomically: true, encoding: String.Encoding.utf8) printStatus("swiftc output written to \(Constants.swiftcLog)") } catch { - printFailure("Could not write swiftc output to " + Constants.swiftcLog + "\nReason: " + error.localizedDescription) - return + printFailure( + "Could not write swiftc output to " + Constants.swiftcLog + "\nReason: " + + error.localizedDescription) + throw ExitCode.failure } - - if (task.terminationStatus != 0) { + + if task.terminationStatus != 0 { printFailure("\nswiftc failed. Please see \(swiftcLog.relativeString)\n") throw ExitCode.failure } - + print("") - + + return output + } + + mutating func run() throws { + var outputSilFileName = "out.sil" + + // swan-swiftc doesn't actually expect multiple source files + // I'm not sure what the output would look like for that + try self.swiftcArgs.forEach { (str) in + if str.hasSuffix(".swift") { + let path = URL(fileURLWithPath: str) + + outputSilFileName = path.lastPathComponent + ".sil" + let copyPath = srcCopyDir.appendingPathComponent(path.lastPathComponent) + + do { + try FileManager.default.copyItem(at: path, to: copyPath) + } catch { + printFailure( + "Could not copy file from \(path) to \(copyPath)\nReason: \(error.localizedDescription)" + ) + throw ExitCode.failure + } + } + } + + let output = try runSwiftC() + var sil = output.components(separatedBy: "\nsil_stage canonical")[1] sil = "sil_stage canonical\(sil)\n\n" - - let filename = outputDir.appendingPathComponent(outputSilFileName) + + let filename = swanDir.appendingPathComponent(outputSilFileName) do { try sil.write(to: filename, atomically: true, encoding: String.Encoding.utf8) } catch { printFailure("Could not write SIL to \(filename)\nReason: \(error.localizedDescription)") } - - do { - // Delete unneeded generated file '-.gsil_0.sil' - try FileManager().removeItem(at: URL(fileURLWithPath: "-.gsil_0.sil")) - } catch {} - - printStatus("\nSIL written to \(outputDir.path)") + + // Delete unneeded generated file '-.sil_dbg_0.sil' + try? FileManager().removeItem(at: URL(fileURLWithPath: "-.sil_dbg_0.sil")) + + printStatus("\nSIL written to \(swanDir.path)") } - } - -SWANSwiftcBuild.main()