diff --git a/Sources/SwiftDriver/Execution/ArgsResolver.swift b/Sources/SwiftDriver/Execution/ArgsResolver.swift index afef17def..00a846657 100644 --- a/Sources/SwiftDriver/Execution/ArgsResolver.swift +++ b/Sources/SwiftDriver/Execution/ArgsResolver.swift @@ -15,6 +15,7 @@ import class Foundation.NSLock import func TSCBasic.withTemporaryDirectory import protocol TSCBasic.FileSystem import struct TSCBasic.AbsolutePath +import struct TSCBasic.SHA256 @_implementationOnly import Yams @@ -208,7 +209,8 @@ public final class ArgsResolver { assert(!forceResponseFiles || job.supportsResponseFiles, "Platform does not support response files for job: \(job)") // Match the integrated driver's behavior, which uses response file names of the form "arguments-[0-9a-zA-Z].resp". - let responseFilePath = temporaryDirectory.appending(component: "arguments-\(abs(job.hashValue)).resp") + let hash = SHA256().hash(resolvedArguments.joined(separator: " ")).hexadecimalRepresentation + let responseFilePath = temporaryDirectory.appending(component: "arguments-\(hash).resp") // FIXME: Need a way to support this for distributed build systems... if let absPath = responseFilePath.absolutePath { diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index a238a19d0..eb36598de 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -1704,6 +1704,27 @@ final class SwiftDriverTests: XCTestCase { XCTAssertFalse(resolvedArgs.contains { $0.hasPrefix("@") }) } } + + func testResponseFileDeterministicNaming() throws { + #if !os(macOS) + throw XCTSkip("Test assumes macOS response file quoting behavior") + #endif + do { + let testJob = Job(moduleName: "Foo", + kind: .compile, + tool: .init(path: try AbsolutePath(validating: "/swiftc"), supportsResponseFiles: true), + commandLine: (1...20000).map { .flag("-DTEST_\($0)") }, + inputs: [], + primaryInputs: [], + outputs: []) + let resolver = try ArgsResolver(fileSystem: localFileSystem) + let resolvedArgs: [String] = try resolver.resolveArgumentList(for: testJob) + XCTAssertTrue(resolvedArgs.count == 3) + XCTAssertEqual(resolvedArgs[2].first, "@") + let responseFilePath = try AbsolutePath(validating: String(resolvedArgs[2].dropFirst())) + XCTAssertEqual(responseFilePath.basename, "arguments-847d15e70d97df7c18033735497ca8dcc4441f461d5a9c2b764b127004524e81.resp") + } + } func testSpecificJobsResponseFiles() throws { // The jobs below often take large command lines (e.g., when passing a large number of Clang