Skip to content
Draft
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
14 changes: 6 additions & 8 deletions Sources/XToolSupport/SDKBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,13 @@
}

let input: Input
let outputPath: String
let output: URL
let arch: Arch

@discardableResult
func buildSDK() async throws -> String {
func buildSDK() async throws {
// TODO: store relevant info for staleness check
let sdkVersion = "develop"

let output = URL(fileURLWithPath: outputPath, isDirectory: true)
.appendingPathComponent("darwin.artifactbundle")

try? FileManager.default.removeItem(at: output)
try FileManager.default.createDirectory(
at: output,
Expand Down Expand Up @@ -171,8 +167,6 @@

try Data("\(sdkVersion)\n".utf8)
.write(to: output.appendingPathComponent("darwin-sdk-version.txt"))

return output.path
}

private func installToolset(in output: URL) async throws {
Expand Down Expand Up @@ -224,7 +218,7 @@
}

// swiftlint:disable:next cyclomatic_complexity
private func installDeveloper(in output: URL) async throws -> URL {

Check warning on line 221 in Sources/XToolSupport/SDKBuilder.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Function body should span 100 lines or less excluding comments and whitespace: currently spans 101 lines (function_body_length)
let dev = output.appendingPathComponent("Developer")

let appDir: URL
Expand Down Expand Up @@ -353,6 +347,10 @@
)
}

try FileManager.default.removeItem(
at: dev.appending(path: "Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/clang/include")
)

return dev
}

Expand Down
63 changes: 49 additions & 14 deletions Sources/XToolSupport/SDKCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ struct DevSDKBuildCommand: AsyncParsableCommand {
func run() async throws {
let builderArch = try arch.sdkBuilderArch
let input = try SDKBuilder.Input(path: path)
let builder = SDKBuilder(input: input, outputPath: outputDir, arch: builderArch)
let sdkPath = try await builder.buildSDK()
print("Built SDK at \(sdkPath)")
let output = URL(fileURLWithPath: outputDir, isDirectory: true).appending(path: "darwin.xtoolsdk")
let builder = SDKBuilder(input: input, output: output, arch: builderArch)
try await builder.buildSDK()
print("Built SDK at \(output.path). You can install it with `xtool sdk install`.")
}
}

Expand Down Expand Up @@ -83,8 +84,8 @@ struct DevSDKInstallCommand: AsyncParsableCommand {
)

@Argument(
help: "Path to Xcode.xip or Xcode.app",
completion: .file(extensions: ["xip", "app"])
help: "Path to Xcode.xip, Xcode.app, or darwin.xtoolsdk",
completion: .file(extensions: ["xip", "app", "xtoolsdk"])
)
var path: String

Expand Down Expand Up @@ -132,7 +133,7 @@ struct DarwinSDK {
if let version = try? Data(contentsOf: bundle.appendingPathComponent("darwin-sdk-version.txt")) {
self.version = String(decoding: version, as: UTF8.self)
.trimmingCharacters(in: .whitespacesAndNewlines)
} else if bundle.lastPathComponent == "darwin.artifactbundle" {
} else if bundle.lastPathComponent == "darwin.xtoolsdk" {
self.version = "unknown"
} else {
return nil
Expand All @@ -148,12 +149,38 @@ struct DarwinSDK {
let url = URL(fileURLWithPath: path)
guard DarwinSDK(bundle: url) != nil else { throw Console.Error("Invalid Darwin SDK at '\(path)'")}

try await addHostClangResourceDir(to: url)

let process = Process()
process.executableURL = try await ToolRegistry.locate("swift")
process.arguments = ["sdk", "install", url.path]
try await process.runUntilExit()
}

private static func addHostClangResourceDir(to sdk: URL) async throws {
let outPipe = Pipe()
let clang = Process()
clang.executableURL = try await ToolRegistry.locate("clang")
clang.arguments = ["-print-resource-dir"]
clang.standardOutput = outPipe
clang.standardError = FileHandle.standardError
async let outputData = Data(reading: outPipe.fileHandleForReading)
do {
try await clang.runUntilExit()
} catch is Process.Failure {
throw Console.Error("Failed to query host clang -print-resource-dir")
}
let path = String(decoding: try await outputData, as: UTF8.self)
.trimmingCharacters(in: .whitespacesAndNewlines)
guard !path.isEmpty else {
throw Console.Error("Host clang returned an empty resource directory")
}
let hostClangResources = URL(fileURLWithPath: path, isDirectory: true)
let hostInclude = hostClangResources.appending(path: "include")
let sdkInclude = sdk.appending(path: "Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/clang/include")
try FileManager.default.copyItem(at: hostInclude, to: sdkInclude)
}

static func current() async throws -> DarwinSDK? {
let output = Pipe()

Expand Down Expand Up @@ -243,20 +270,28 @@ struct InstallSDKOperation {
#if os(macOS)
print("Skipping SDK install; the iOS SDK ships with Xcode on macOS")
#else
// validate input before removing existing SDK
let input = try SDKBuilder.Input(path: path)
let arch = try ArchSelection.auto.sdkBuilderArch

let tempDir = try TemporaryDirectory(name: "DarwinSDKBuild")
let sdkPath = tempDir.url.appending(path: "darwin.artifactbundle")

if path.hasSuffix(".xtoolsdk") {
print("Installing prebuilt SDK...")
try FileManager.default.copyItem(at: URL(filePath: path), to: sdkPath)
} else {
// validate input before removing existing SDK
let input = try SDKBuilder.Input(path: path)
let arch = try ArchSelection.auto.sdkBuilderArch

let builder = SDKBuilder(input: input, output: sdkPath, arch: arch)
try await builder.buildSDK()
}

if let sdk = try await DarwinSDK.current() {
print("Removing existing SDK...")
try sdk.remove()
}

let tempDir = try TemporaryDirectory(name: "DarwinSDKBuild")
let builder = SDKBuilder(input: input, outputPath: tempDir.url.path, arch: arch)
let sdkPath = try await builder.buildSDK()

try await DarwinSDK.install(from: sdkPath)
try await DarwinSDK.install(from: sdkPath.path)

// don't destroy tempDir before this point
withExtendedLifetime(tempDir) {}
Expand Down
Loading