Skip to content

Commit a736d79

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

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
@@ -502,13 +502,22 @@ extension Driver {
502502
private static func expandResponseFiles(
503503
_ args: [String],
504504
diagnosticsEngine: DiagnosticsEngine,
505-
visitedResponseFiles: inout Set<AbsolutePath>
505+
visitedResponseFiles: inout Set<VirtualPath>
506506
) throws -> [String] {
507507
var result: [String] = []
508-
508+
var skipNext = false
509+
// FIXME: This is very fragile
510+
let forwardingOptions: Set<String> = Set([
511+
Option.Xcc, .XclangLinker, .Xfrontend, .Xlinker, .Xllvm,
512+
].map { $0.spelling })
509513
// Go through each arg and add arguments from response files.
510514
for arg in args {
511-
if arg.first == "@", let responseFile = try? AbsolutePath(validating: String(arg.dropFirst())) {
515+
defer { skipNext = forwardingOptions.contains(arg) }
516+
if !skipNext, arg.first == "@" {
517+
guard let responseFile = diagnosticsEngine
518+
.wrap({ try VirtualPath(path: String(arg.dropFirst())) }) else {
519+
continue
520+
}
512521
// Guard against infinite parsing loop.
513522
guard visitedResponseFiles.insert(responseFile).inserted else {
514523
diagnosticsEngine.emit(.warn_recursive_response_file(responseFile))
@@ -518,7 +527,11 @@ extension Driver {
518527
visitedResponseFiles.remove(responseFile)
519528
}
520529

521-
let contents = try localFileSystem.readFileContents(responseFile).cString
530+
guard let contents = diagnosticsEngine.wrap({
531+
try localFileSystem.readFileContents(responseFile).cString
532+
}) else {
533+
continue
534+
}
522535
let lines = tokenizeResponseFile(contents)
523536
result.append(contentsOf: try expandResponseFiles(lines, diagnosticsEngine: diagnosticsEngine, visitedResponseFiles: &visitedResponseFiles))
524537
} else {
@@ -534,7 +547,7 @@ extension Driver {
534547
_ args: [String],
535548
diagnosticsEngine: DiagnosticsEngine
536549
) throws -> [String] {
537-
var visitedResponseFiles = Set<AbsolutePath>()
550+
var visitedResponseFiles = Set<VirtualPath>()
538551
return try expandResponseFiles(args, diagnosticsEngine: diagnosticsEngine, visitedResponseFiles: &visitedResponseFiles)
539552
}
540553
}
@@ -692,7 +705,7 @@ extension Driver {
692705
}
693706

694707
extension Diagnostic.Message {
695-
static func warn_recursive_response_file(_ path: AbsolutePath) -> Diagnostic.Message {
708+
static func warn_recursive_response_file(_ path: VirtualPath) -> Diagnostic.Message {
696709
.warning("response file '\(path)' is recursively expanded")
697710
}
698711

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -591,16 +591,19 @@ final class SwiftDriverTests: XCTestCase {
591591
let diags = DiagnosticsEngine()
592592
let fooPath = path.appending(component: "foo.rsp")
593593
let barPath = path.appending(component: "bar.rsp")
594+
let notAFilePath = path.appending(component: "nonexistent.rsp")
594595
try localFileSystem.writeFileContents(fooPath) {
595596
$0 <<< "hello\nbye\nbye\\ to\\ you\n@\(barPath.pathString)"
596597
}
597598
try localFileSystem.writeFileContents(barPath) {
598-
$0 <<< "from\nbar\n@\(fooPath.pathString)"
599+
$0 <<< "from\nbar\n@\(fooPath.pathString)\n@\(notAFilePath.pathString)"
599600
}
600601
let args = try Driver.expandResponseFiles(["swift", "compiler", "-Xlinker", "@loader_path", "@" + fooPath.pathString, "something"], diagnosticsEngine: diags)
601602
XCTAssertEqual(args, ["swift", "compiler", "-Xlinker", "@loader_path", "hello", "bye", "bye to you", "from", "bar", "something"])
602-
XCTAssertEqual(diags.diagnostics.count, 1)
603+
XCTAssertEqual(diags.diagnostics.count, 2)
603604
XCTAssert(diags.diagnostics.first!.description.contains("is recursively expanded"))
605+
// FIXME: Error message about nonexistent response file could be improved
606+
XCTAssertEqual(diags.diagnostics[1].description, "noEntry")
604607
}
605608
}
606609

@@ -619,7 +622,6 @@ final class SwiftDriverTests: XCTestCase {
619622
// this is another comment
620623
but this is \\\\\a command
621624
@\#(barPath.pathString)
622-
@NotAFile
623625
-flag="quoted string with a \"quote\" inside" -another-flag
624626
"""#
625627
<<< "\nthis line\thas lots \t of whitespace"
@@ -643,7 +645,7 @@ final class SwiftDriverTests: XCTestCase {
643645
$0 <<< "swift\n--driver-mode=swiftc\n-v\r\n//comment\n\"the end\""
644646
}
645647
let args = try Driver.expandResponseFiles(["@" + fooPath.pathString], diagnosticsEngine: diags)
646-
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"])
648+
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"])
647649
let escapingArgs = try Driver.expandResponseFiles(["@" + escapingPath.pathString], diagnosticsEngine: diags)
648650
XCTAssertEqual(escapingArgs, ["swift", "--driver-mode=swiftc", "-v","the end"])
649651
}
@@ -694,6 +696,67 @@ final class SwiftDriverTests: XCTestCase {
694696
}
695697
}
696698

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

0 commit comments

Comments
 (0)