Skip to content

Commit a59e2c3

Browse files
committed
Allow relative paths for rsp file, skip forwarded args in rsp expansion, fail on invalid rsp files
1 parent 0aa2178 commit a59e2c3

File tree

2 files changed

+86
-10
lines changed

2 files changed

+86
-10
lines changed

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -524,13 +524,22 @@ extension Driver {
524524
private static func expandResponseFiles(
525525
_ args: [String],
526526
diagnosticsEngine: DiagnosticsEngine,
527-
visitedResponseFiles: inout Set<AbsolutePath>
527+
visitedResponseFiles: inout Set<VirtualPath>
528528
) throws -> [String] {
529529
var result: [String] = []
530-
530+
var skipNext = false
531+
// FIXME: This is very fragile
532+
let forwardingOptions: Set<String> = Set([
533+
Option.Xcc, .XclangLinker, .Xfrontend, .Xlinker, .Xllvm,
534+
].map { $0.spelling })
531535
// Go through each arg and add arguments from response files.
532536
for arg in args {
533-
if arg.first == "@", let responseFile = try? AbsolutePath(validating: String(arg.dropFirst())) {
537+
defer { skipNext = forwardingOptions.contains(arg) }
538+
if !skipNext, arg.first == "@" {
539+
guard let responseFile = diagnosticsEngine
540+
.wrap({ try VirtualPath(path: String(arg.dropFirst())) }) else {
541+
continue
542+
}
534543
// Guard against infinite parsing loop.
535544
guard visitedResponseFiles.insert(responseFile).inserted else {
536545
diagnosticsEngine.emit(.warn_recursive_response_file(responseFile))
@@ -540,7 +549,11 @@ extension Driver {
540549
visitedResponseFiles.remove(responseFile)
541550
}
542551

543-
let contents = try localFileSystem.readFileContents(responseFile).cString
552+
guard let contents = diagnosticsEngine.wrap({
553+
try localFileSystem.readFileContents(responseFile).cString
554+
}) else {
555+
continue
556+
}
544557
let lines = tokenizeResponseFile(contents)
545558
result.append(contentsOf: try expandResponseFiles(lines, diagnosticsEngine: diagnosticsEngine, visitedResponseFiles: &visitedResponseFiles))
546559
} else {
@@ -556,7 +569,7 @@ extension Driver {
556569
_ args: [String],
557570
diagnosticsEngine: DiagnosticsEngine
558571
) throws -> [String] {
559-
var visitedResponseFiles = Set<AbsolutePath>()
572+
var visitedResponseFiles = Set<VirtualPath>()
560573
return try expandResponseFiles(args, diagnosticsEngine: diagnosticsEngine, visitedResponseFiles: &visitedResponseFiles)
561574
}
562575
}
@@ -714,7 +727,7 @@ extension Driver {
714727
}
715728

716729
extension Diagnostic.Message {
717-
static func warn_recursive_response_file(_ path: AbsolutePath) -> Diagnostic.Message {
730+
static func warn_recursive_response_file(_ path: VirtualPath) -> Diagnostic.Message {
718731
.warning("response file '\(path)' is recursively expanded")
719732
}
720733

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -582,16 +582,19 @@ final class SwiftDriverTests: XCTestCase {
582582
let diags = DiagnosticsEngine()
583583
let fooPath = path.appending(component: "foo.rsp")
584584
let barPath = path.appending(component: "bar.rsp")
585+
let notAFilePath = path.appending(component: "nonexistent.rsp")
585586
try localFileSystem.writeFileContents(fooPath) {
586587
$0 <<< "hello\nbye\nbye\\ to\\ you\n@\(barPath.pathString)"
587588
}
588589
try localFileSystem.writeFileContents(barPath) {
589-
$0 <<< "from\nbar\n@\(fooPath.pathString)"
590+
$0 <<< "from\nbar\n@\(fooPath.pathString)\n@\(notAFilePath.pathString)"
590591
}
591592
let args = try Driver.expandResponseFiles(["swift", "compiler", "-Xlinker", "@loader_path", "@" + fooPath.pathString, "something"], diagnosticsEngine: diags)
592593
XCTAssertEqual(args, ["swift", "compiler", "-Xlinker", "@loader_path", "hello", "bye", "bye to you", "from", "bar", "something"])
593-
XCTAssertEqual(diags.diagnostics.count, 1)
594+
XCTAssertEqual(diags.diagnostics.count, 2)
594595
XCTAssert(diags.diagnostics.first!.description.contains("is recursively expanded"))
596+
// FIXME: Error message about nonexistent response file could be improved
597+
XCTAssertEqual(diags.diagnostics[1].description, "noEntry")
595598
}
596599
}
597600

@@ -610,7 +613,6 @@ final class SwiftDriverTests: XCTestCase {
610613
// this is another comment
611614
but this is \\\\\a command
612615
@\#(barPath.pathString)
613-
@NotAFile
614616
-flag="quoted string with a \"quote\" inside" -another-flag
615617
"""#
616618
<<< "\nthis line\thas lots \t of whitespace"
@@ -634,7 +636,7 @@ final class SwiftDriverTests: XCTestCase {
634636
$0 <<< "swift\n--driver-mode=swiftc\n-v\r\n//comment\n\"the end\""
635637
}
636638
let args = try Driver.expandResponseFiles(["@" + fooPath.pathString], diagnosticsEngine: diags)
637-
XCTAssertEqual(args, ["Command1", "--kkc", "but", "this", "is", #"\\a"#, "command", #"swift"#, "rocks!" ,"compiler", "-Xlinker", "@loader_path", "mkdir", "Quoted Dir", "cd", "Unquoted Dir", "@NotAFile", #"-flag=quoted string with a "quote" inside"#, "-another-flag", "this", "line", "has", "lots", "of", "whitespace"])
639+
XCTAssertEqual(args, ["Command1", "--kkc", "but", "this", "is", #"\\a"#, "command", #"swift"#, "rocks!" ,"compiler", "-Xlinker", "@loader_path", "mkdir", "Quoted Dir", "cd", "Unquoted Dir", #"-flag=quoted string with a "quote" inside"#, "-another-flag", "this", "line", "has", "lots", "of", "whitespace"])
638640
let escapingArgs = try Driver.expandResponseFiles(["@" + escapingPath.pathString], diagnosticsEngine: diags)
639641
XCTAssertEqual(escapingArgs, ["swift", "--driver-mode=swiftc", "-v","the end"])
640642
}
@@ -685,6 +687,67 @@ final class SwiftDriverTests: XCTestCase {
685687
}
686688
}
687689

690+
func testResponseFileExpansionIgnoresForwarded() throws {
691+
try withTemporaryDirectory { path in
692+
try assertNoDiagnostics { diags in
693+
let forwardedRsp = path.appending(component: "foo.rsp")
694+
let barPath = path.appending(component: "bar.rsp")
695+
let nonexisting = path.appending(component: "nonexiting.rsp")
696+
try localFileSystem.writeFileContents(forwardedRsp) {
697+
$0 <<< "should_not_appear_in_args"
698+
}
699+
try localFileSystem.writeFileContents(barPath) {
700+
$0 <<< """
701+
-Xcc @\(forwardedRsp.pathString)
702+
-Xclang-linker @\(forwardedRsp.pathString)
703+
-Xcc @\(nonexisting.pathString)
704+
-Xclang-linker @\(nonexisting.pathString)
705+
"""
706+
}
707+
let args = try Driver.expandResponseFiles([
708+
"swift", "compiler",
709+
"-Xlinker", "@\(nonexisting.pathString)",
710+
"-Xfrontend", "@\(forwardedRsp.pathString)",
711+
"@\(barPath.pathString)",
712+
], diagnosticsEngine: diags)
713+
XCTAssertEqual(args, [
714+
"swift", "compiler",
715+
"-Xlinker", "@\(nonexisting.pathString)",
716+
"-Xfrontend", "@\(forwardedRsp.pathString)",
717+
"-Xcc", "@\(forwardedRsp.pathString)",
718+
"-Xclang-linker", "@\(forwardedRsp.pathString)",
719+
"-Xcc", "@\(nonexisting.pathString)",
720+
"-Xclang-linker", "@\(nonexisting.pathString)",
721+
])
722+
}
723+
}
724+
}
725+
726+
func testResponseFile() throws {
727+
try withTemporaryDirectory { path in
728+
guard let cwd = localFileSystem
729+
.currentWorkingDirectory else { fatalError() }
730+
let responseFile1 = path.appending(component: "fileList1.rsp")
731+
let responseFile2 = path.appending(component: "fileList2.rsp")
732+
try localFileSystem.writeFileContents(responseFile1) {
733+
$0 <<< "from1stList.swift"
734+
}
735+
try localFileSystem.writeFileContents(responseFile2) {
736+
$0 <<< "from2ndList.swift"
737+
}
738+
let responseFile2Relative = responseFile2.relative(to: cwd)
739+
let driver = try Driver(args: [
740+
"swiftc",
741+
"@\(responseFile1.pathString)",
742+
"@\(responseFile2Relative)",
743+
])
744+
XCTAssertEqual(driver.inputFiles, [
745+
.init(file: .relative(.init("from1stList.swift")), type: .swift),
746+
.init(file: .relative(.init("from2ndList.swift")), type: .swift),
747+
])
748+
}
749+
}
750+
688751
func testLinking() throws {
689752
var env = ProcessEnv.vars
690753
env["SWIFT_DRIVER_TESTS_ENABLE_EXEC_PATH_FALLBACK"] = "1"

0 commit comments

Comments
 (0)