Skip to content

Commit c86aaca

Browse files
committed
Add ability to override/disable response file use in ArgsResolver
This change deprecates 'ArgsResolver' API that takes a boolean 'forceResponseFiles' in favour of a new API that takes an 'ResponseFileHandling' enum. This enum allows the previous behaviors of '.forced' and '.heuristic' ('true' and 'false', respectively of 'forceResponseFiles'), and adds an option to override disable use of response files completely ('.disabled'). This is useful in the example of dependency scanning when it is done via a C interface to a compiler library: even for exceedingly long command-line argument lists, using response files is not necessary since we just pass in a pointer to an already-allocated memory buffer containing the argument list, directly. Resolves rdar://99296444
1 parent 3740426 commit c86aaca

File tree

8 files changed

+67
-30
lines changed

8 files changed

+67
-30
lines changed

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1380,7 +1380,7 @@ extension Driver {
13801380
// In verbose mode, print out the job
13811381
if parsedOptions.contains(.v) {
13821382
let arguments: [String] = try executor.resolver.resolveArgumentList(for: inPlaceJob,
1383-
forceResponseFiles: forceResponseFiles)
1383+
useResponseFiles: forceResponseFiles ? .forced : .heuristic)
13841384
stdoutStream <<< arguments.map { $0.spm_shellEscaped() }.joined(separator: " ") <<< "\n"
13851385
stdoutStream.flush()
13861386
}

Sources/SwiftDriver/Execution/ArgsResolver.swift

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ import class Foundation.NSLock
1414
import TSCBasic
1515
@_implementationOnly import Yams
1616

17+
/// How the resolver is to handle usage of response files
18+
public enum ResponseFileHandling {
19+
case forced
20+
case disabled
21+
case heuristic
22+
}
23+
1724
/// Resolver for a job's argument template.
1825
public final class ArgsResolver {
1926
/// The map of virtual path to the actual path.
@@ -45,22 +52,36 @@ public final class ArgsResolver {
4552
}
4653
}
4754

48-
public func resolveArgumentList(for job: Job, forceResponseFiles: Bool,
55+
public func resolveArgumentList(for job: Job, useResponseFiles: ResponseFileHandling = .heuristic,
4956
quotePaths: Bool = false) throws -> [String] {
50-
let (arguments, _) = try resolveArgumentList(for: job, forceResponseFiles: forceResponseFiles,
57+
let (arguments, _) = try resolveArgumentList(for: job, useResponseFiles: useResponseFiles,
5158
quotePaths: quotePaths)
5259
return arguments
5360
}
5461

55-
public func resolveArgumentList(for job: Job, forceResponseFiles: Bool,
62+
public func resolveArgumentList(for job: Job, useResponseFiles: ResponseFileHandling = .heuristic,
5663
quotePaths: Bool = false) throws -> ([String], usingResponseFile: Bool) {
5764
let tool = try resolve(.path(job.tool), quotePaths: quotePaths)
5865
var arguments = [tool] + (try job.commandLine.map { try resolve($0, quotePaths: quotePaths) })
5966
let usingResponseFile = try createResponseFileIfNeeded(for: job, resolvedArguments: &arguments,
60-
forceResponseFiles: forceResponseFiles)
67+
useResponseFiles: useResponseFiles)
6168
return (arguments, usingResponseFile)
6269
}
6370

71+
@available(*, deprecated, message: "use resolveArgumentList(for:,useResponseFiles:,quotePaths:)")
72+
public func resolveArgumentList(for job: Job, forceResponseFiles: Bool,
73+
quotePaths: Bool = false) throws -> [String] {
74+
let useResponseFiles: ResponseFileHandling = forceResponseFiles ? .forced : .heuristic
75+
return try resolveArgumentList(for: job, useResponseFiles: useResponseFiles, quotePaths: quotePaths)
76+
}
77+
78+
@available(*, deprecated, message: "use resolveArgumentList(for:,useResponseFiles:,quotePaths:)")
79+
public func resolveArgumentList(for job: Job, forceResponseFiles: Bool,
80+
quotePaths: Bool = false) throws -> ([String], usingResponseFile: Bool) {
81+
let useResponseFiles: ResponseFileHandling = forceResponseFiles ? .forced : .heuristic
82+
return try resolveArgumentList(for: job, useResponseFiles: useResponseFiles, quotePaths: quotePaths)
83+
}
84+
6485
/// Resolve the given argument.
6586
public func resolve(_ arg: Job.ArgTemplate,
6687
quotePaths: Bool = false) throws -> String {
@@ -167,11 +188,15 @@ public final class ArgsResolver {
167188
return string.trimmingCharacters(in: .whitespacesAndNewlines)
168189
}
169190

170-
private func createResponseFileIfNeeded(for job: Job, resolvedArguments: inout [String], forceResponseFiles: Bool) throws -> Bool {
191+
private func createResponseFileIfNeeded(for job: Job, resolvedArguments: inout [String], useResponseFiles: ResponseFileHandling) throws -> Bool {
171192
func quote(_ string: String) -> String {
172193
return "\"\(String(string.flatMap { ["\\", "\""].contains($0) ? "\\\($0)" : "\($0)" }))\""
173194
}
174-
195+
guard useResponseFiles != .disabled else {
196+
return false
197+
}
198+
199+
let forceResponseFiles = useResponseFiles == .forced
175200
if forceResponseFiles ||
176201
(job.supportsResponseFiles && !commandLineFitsWithinSystemLimits(path: resolvedArguments[0], args: resolvedArguments)) {
177202
assert(!forceResponseFiles || job.supportsResponseFiles,

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ public extension Driver {
125125
if isSwiftScanLibAvailable {
126126
let cwd = workingDirectory ?? fileSystem.currentWorkingDirectory!
127127
var command = try itemizedJobCommand(of: preScanJob,
128-
forceResponseFiles: forceResponseFiles,
128+
useResponseFiles: .disabled,
129129
using: executor.resolver)
130130
sanitizeCommandForLibScanInvocation(&command)
131131
imports =
@@ -154,7 +154,7 @@ public extension Driver {
154154
if isSwiftScanLibAvailable {
155155
let cwd = workingDirectory ?? fileSystem.currentWorkingDirectory!
156156
var command = try itemizedJobCommand(of: scannerJob,
157-
forceResponseFiles: forceResponseFiles,
157+
useResponseFiles: .disabled,
158158
using: executor.resolver)
159159
sanitizeCommandForLibScanInvocation(&command)
160160
dependencyGraph =
@@ -183,7 +183,7 @@ public extension Driver {
183183
if isSwiftScanLibAvailable {
184184
let cwd = workingDirectory ?? fileSystem.currentWorkingDirectory!
185185
var command = try itemizedJobCommand(of: batchScanningJob,
186-
forceResponseFiles: forceResponseFiles,
186+
useResponseFiles: .disabled,
187187
using: executor.resolver)
188188
sanitizeCommandForLibScanInvocation(&command)
189189
moduleVersionedGraphMap =
@@ -328,10 +328,10 @@ public extension Driver {
328328
contents)
329329
}
330330

331-
fileprivate func itemizedJobCommand(of job: Job, forceResponseFiles: Bool,
331+
fileprivate func itemizedJobCommand(of job: Job, useResponseFiles: ResponseFileHandling,
332332
using resolver: ArgsResolver) throws -> [String] {
333333
let (args, _) = try resolver.resolveArgumentList(for: job,
334-
forceResponseFiles: forceResponseFiles)
334+
useResponseFiles: useResponseFiles)
335335
return args
336336
}
337337
}

Sources/SwiftDriverExecution/MultiJobExecutor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ class ExecuteJobRule: LLBuildRule {
579579
var pid = 0
580580
do {
581581
let arguments: [String] = try resolver.resolveArgumentList(for: job,
582-
forceResponseFiles: context.forceResponseFiles)
582+
useResponseFiles: context.forceResponseFiles ? .forced : .heuristic)
583583

584584

585585
let process : ProcessProtocol

Sources/SwiftDriverExecution/SwiftDriverExecutor.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ public final class SwiftDriverExecutor: DriverExecutor {
3535
public func execute(job: Job,
3636
forceResponseFiles: Bool = false,
3737
recordedInputModificationDates: [TypedVirtualPath: Date] = [:]) throws -> ProcessResult {
38+
let useResponseFiles : ResponseFileHandling = forceResponseFiles ? .forced : .heuristic
3839
let arguments: [String] = try resolver.resolveArgumentList(for: job,
39-
forceResponseFiles: forceResponseFiles)
40+
useResponseFiles: useResponseFiles)
4041

4142
try job.verifyInputsNotModified(since: recordedInputModificationDates,
4243
fileSystem: fileSystem)
@@ -86,7 +87,8 @@ public final class SwiftDriverExecutor: DriverExecutor {
8687
}
8788

8889
public func description(of job: Job, forceResponseFiles: Bool) throws -> String {
89-
let (args, usedResponseFile) = try resolver.resolveArgumentList(for: job, forceResponseFiles: forceResponseFiles)
90+
let useResponseFiles : ResponseFileHandling = forceResponseFiles ? .forced : .heuristic
91+
let (args, usedResponseFile) = try resolver.resolveArgumentList(for: job, useResponseFiles: useResponseFiles)
9092
var result = args.map { $0.spm_shellEscaped() }.joined(separator: " ")
9193

9294
if usedResponseFile {

Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,8 +1054,7 @@ final class ExplicitModuleBuildTests: XCTestCase {
10541054

10551055
let resolver = try ArgsResolver(fileSystem: localFileSystem)
10561056
let (args, _) = try resolver.resolveArgumentList(for: scannerJob,
1057-
forceResponseFiles: false,
1058-
quotePaths: true)
1057+
useResponseFiles: .disabled)
10591058
XCTAssertTrue(args.count > 1)
10601059
XCTAssertFalse(args[0].hasSuffix(".resp"))
10611060
}

Tests/SwiftDriverTests/ParsableMessageTests.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ final class ParsableMessageTests: XCTestCase {
150150
"-working-directory", workdir.pathString])
151151
let jobs = try driver.planBuild()
152152
let compileJob = jobs[0]
153-
let args : [String] = try resolver.resolveArgumentList(for: compileJob, forceResponseFiles: false)
153+
let args : [String] = try resolver.resolveArgumentList(for: compileJob, useResponseFiles: .disabled)
154154
let toolDelegate = ToolExecutionDelegate(mode: .parsableOutput,
155155
buildRecordInfo: nil,
156156
showJobLifecycle: false,
@@ -237,7 +237,7 @@ final class ParsableMessageTests: XCTestCase {
237237
"-working-directory", "/WorkDir"])
238238
let jobs = try driver.planBuild()
239239
compileJob = jobs[0]
240-
args = try resolver.resolveArgumentList(for: compileJob!, forceResponseFiles: false)
240+
args = try resolver.resolveArgumentList(for: compileJob!)
241241
toolDelegate = ToolExecutionDelegate(mode: .parsableOutput,
242242
buildRecordInfo: nil,
243243
showJobLifecycle: false,
@@ -313,8 +313,7 @@ final class ParsableMessageTests: XCTestCase {
313313
"-working-directory", "/WorkDir"])
314314
let jobs = try driver.planBuild()
315315
compileJob = jobs[0]
316-
args = try resolver.resolveArgumentList(for: compileJob!,
317-
forceResponseFiles: false)
316+
args = try resolver.resolveArgumentList(for: compileJob!)
318317
toolDelegate = ToolExecutionDelegate(mode: .parsableOutput,
319318
buildRecordInfo: nil,
320319
showJobLifecycle: false,

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,7 +1485,7 @@ final class SwiftDriverTests: XCTestCase {
14851485
XCTAssertTrue(jobs.count == 1 && jobs[0].kind == .interpret)
14861486
let interpretJob = jobs[0]
14871487
let resolver = try ArgsResolver(fileSystem: localFileSystem)
1488-
let resolvedArgs: [String] = try resolver.resolveArgumentList(for: interpretJob, forceResponseFiles: false)
1488+
let resolvedArgs: [String] = try resolver.resolveArgumentList(for: interpretJob)
14891489
XCTAssertTrue(resolvedArgs.count == 2)
14901490
XCTAssertEqual(resolvedArgs[1].first, "@")
14911491
let responseFilePath = try AbsolutePath(validating: String(resolvedArgs[1].dropFirst()))
@@ -1494,14 +1494,26 @@ final class SwiftDriverTests: XCTestCase {
14941494
XCTAssertTrue(contents.contains("\"-D\"\n\"TEST_20000\""))
14951495
XCTAssertTrue(contents.contains("\"-D\"\n\"TEST_1\""))
14961496
}
1497+
1498+
// Needs response file + disable override
1499+
do {
1500+
var driver = try Driver(args: ["swift"] + manyArgs + ["foo.swift"])
1501+
let jobs = try driver.planBuild()
1502+
XCTAssertTrue(jobs.count == 1 && jobs[0].kind == .interpret)
1503+
let interpretJob = jobs[0]
1504+
let resolver = try ArgsResolver(fileSystem: localFileSystem)
1505+
let resolvedArgs: [String] = try resolver.resolveArgumentList(for: interpretJob, useResponseFiles: .disabled)
1506+
XCTAssertFalse(resolvedArgs.contains { $0.hasPrefix("@") })
1507+
}
1508+
14971509
// Forced response file
14981510
do {
14991511
var driver = try Driver(args: ["swift"] + ["foo.swift"])
15001512
let jobs = try driver.planBuild()
15011513
XCTAssertTrue(jobs.count == 1 && jobs[0].kind == .interpret)
15021514
let interpretJob = jobs[0]
15031515
let resolver = try ArgsResolver(fileSystem: localFileSystem)
1504-
let resolvedArgs: [String] = try resolver.resolveArgumentList(for: interpretJob, forceResponseFiles: true)
1516+
let resolvedArgs: [String] = try resolver.resolveArgumentList(for: interpretJob, useResponseFiles: .forced)
15051517
XCTAssertTrue(resolvedArgs.count == 2)
15061518
XCTAssertEqual(resolvedArgs[1].first, "@")
15071519
let responseFilePath = try AbsolutePath(validating: String(resolvedArgs[1].dropFirst()))
@@ -1516,8 +1528,8 @@ final class SwiftDriverTests: XCTestCase {
15161528
XCTAssertTrue(jobs.count == 1 && jobs[0].kind == .interpret)
15171529
let interpretJob = jobs[0]
15181530
let resolver = try ArgsResolver(fileSystem: localFileSystem)
1519-
let resolvedArgs: [String] = try resolver.resolveArgumentList(for: interpretJob, forceResponseFiles: false)
1520-
XCTAssertFalse(resolvedArgs.map { $0.hasPrefix("@") }.reduce(false){ $0 || $1 })
1531+
let resolvedArgs: [String] = try resolver.resolveArgumentList(for: interpretJob)
1532+
XCTAssertFalse(resolvedArgs.contains { $0.hasPrefix("@") })
15211533
}
15221534
}
15231535

@@ -1539,15 +1551,15 @@ final class SwiftDriverTests: XCTestCase {
15391551

15401552
let emitModuleJob = jobs.first(where: { $0.kind == .emitModule })!
15411553
let emitModuleResolvedArgs: [String] =
1542-
try resolver.resolveArgumentList(for: emitModuleJob, forceResponseFiles: false)
1554+
try resolver.resolveArgumentList(for: emitModuleJob)
15431555
XCTAssertEqual(emitModuleResolvedArgs.count, 2)
15441556
XCTAssertEqual(emitModuleResolvedArgs[1].first, "@")
15451557

15461558
let compileJobs = jobs.filter { $0.kind == .compile }
15471559
for compileJob in compileJobs {
15481560
XCTAssertEqual(compileJobs.count, 2)
15491561
let compileResolvedArgs: [String] =
1550-
try resolver.resolveArgumentList(for: compileJob, forceResponseFiles: false)
1562+
try resolver.resolveArgumentList(for: compileJob)
15511563
XCTAssertEqual(compileResolvedArgs.count, 2)
15521564
XCTAssertEqual(compileResolvedArgs[1].first, "@")
15531565
}
@@ -1565,15 +1577,15 @@ final class SwiftDriverTests: XCTestCase {
15651577

15661578
let mergeModuleJob = jobs.first(where: { $0.kind == .mergeModule })!
15671579
let mergeModuleResolvedArgs: [String] =
1568-
try resolver.resolveArgumentList(for: mergeModuleJob, forceResponseFiles: false)
1580+
try resolver.resolveArgumentList(for: mergeModuleJob)
15691581
XCTAssertEqual(mergeModuleResolvedArgs.count, 2)
15701582
XCTAssertEqual(mergeModuleResolvedArgs[1].first, "@")
15711583

15721584
let compileJobs = jobs.filter { $0.kind == .compile }
15731585
for compileJob in compileJobs {
15741586
XCTAssertEqual(compileJobs.count, 2)
15751587
let compileResolvedArgs: [String] =
1576-
try resolver.resolveArgumentList(for: compileJob, forceResponseFiles: false)
1588+
try resolver.resolveArgumentList(for: compileJob)
15771589
XCTAssertEqual(compileResolvedArgs.count, 2)
15781590
XCTAssertEqual(compileResolvedArgs[1].first, "@")
15791591
}
@@ -1590,7 +1602,7 @@ final class SwiftDriverTests: XCTestCase {
15901602

15911603
let generatePCMJob = jobs[0]
15921604
let generatePCMResolvedArgs: [String] =
1593-
try resolver.resolveArgumentList(for: generatePCMJob, forceResponseFiles: false)
1605+
try resolver.resolveArgumentList(for: generatePCMJob)
15941606
XCTAssertEqual(generatePCMResolvedArgs.count, 2)
15951607
XCTAssertEqual(generatePCMResolvedArgs[1].first, "@")
15961608
}

0 commit comments

Comments
 (0)