diff --git a/Sources/XToolSupport/SDKBuilder.swift b/Sources/XToolSupport/SDKBuilder.swift index 09af2dd7..59042163 100644 --- a/Sources/XToolSupport/SDKBuilder.swift +++ b/Sources/XToolSupport/SDKBuilder.swift @@ -234,14 +234,7 @@ struct SDKBuilder { } // swiftlint:disable:next function_body_length - private func installToolset(in output: URL) async throws { - let toolsetDir = output.appendingPathComponent("toolset") - - try FileManager.default.createDirectory( - at: toolsetDir, - withIntermediateDirectories: false - ) - + private func downloadToolset(into toolsetDir: URL) async throws { @Dependency(\.httpClient) var httpClient let url = URL(string: """ https://github.com/xtool-org/darwin-tools-linux-llvm/releases/download/\ @@ -280,6 +273,30 @@ struct SDKBuilder { try await execution.standardInputWriter.finish() } .checkSuccess() + } + + private func installToolset(in output: URL) async throws { + let toolsetDir = output.appendingPathComponent("toolset") + + try FileManager.default.createDirectory( + at: toolsetDir, + withIntermediateDirectories: false + ) + + if let local = ProcessInfo.processInfo.environment["XTOOL_TOOLSET_TARBALL"] { + // absolute: tar runs in toolsetDir, where a relative path would point + let tarball = URL(fileURLWithPath: local).standardizedFileURL.path + try await Subprocess.run( + .name("tar"), + arguments: ["xzf", tarball], + workingDirectory: FilePath(toolsetDir), + output: .discarded, + error: .discarded, + ) + .checkSuccess() + } else { + try await downloadToolset(into: toolsetDir) + } // swift-build assumes we have an Apple-flavored librarian for Apple platforms // (https://github.com/swiftlang/swift-build/blob/b2433e74e/Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift#L1735) @@ -386,6 +403,15 @@ struct SDKBuilder { } private func installMacros(in output: URL) async throws { + let outputPath = output.appendingPathComponent("OpenAppleMacrosServer").path + if let local = ProcessInfo.processInfo.environment["XTOOL_OAM_SERVER"] { + // copyItem copies a symlink as a symlink (it may be relative): copy its target + let source = URL(fileURLWithPath: local).resolvingSymlinksInPath().path + try FileManager.default.copyItem(atPath: source, toPath: outputPath) + // the source may be read-only (e.g. in /nix/store); the copy keeps its mode + try FileManager.default.setAttributes([.posixPermissions: 0o755], ofItemAtPath: outputPath) + return + } @Dependency(\.httpClient) var httpClient let url = URL(string: """ https://github.com/xtool-org/OpenAppleMacros/releases/download/\ @@ -400,7 +426,6 @@ struct SDKBuilder { case .unknown: nil } - let outputPath = output.appendingPathComponent("OpenAppleMacrosServer").path do { let handle = try FileDescriptor.open( FilePath(outputPath),