Skip to content

Commit

Permalink
Modify response file module to work with gcc/clang
Browse files Browse the repository at this point in the history
* Remove anything specific about MSVC from the response file code (which is just the name and a comment)
* Add unit tests to the module
* Enable use of the response file code in gcc/clang (via the gcc module, clang defaults to this behaviour)
  • Loading branch information
Alexei-Barnes committed Aug 16, 2023
1 parent 133fddf commit 1562001
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 13 deletions.
11 changes: 6 additions & 5 deletions src/compiler/gcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::compiler::args::*;
use crate::compiler::c::{
ArtifactDescriptor, CCompilerImpl, CCompilerKind, Language, ParsedArguments,
};
use crate::compiler::response_file::SplitResponseFileArgs;
use crate::compiler::{clang, Cacheable, ColorMode, CompileCommand, CompilerArguments};
use crate::mock_command::{CommandCreatorSync, RunCommand};
use crate::util::{run_input_output, OsStrExt};
Expand Down Expand Up @@ -887,11 +888,11 @@ impl<'a> Iterator for ExpandIncludeFile<'a> {
debug!("failed to read @-file `{}`: {}", file.display(), e);
return Some(arg);
}
if contents.contains('"') || contents.contains('\'') {
return Some(arg);
}
let new_args = contents.split_whitespace().collect::<Vec<_>>();
self.stack.extend(new_args.iter().rev().map(|s| s.into()));
// Parse the response file contents, taking into account quote-wrapped strings and new-line separators.
let resp_file_args = SplitResponseFileArgs::from(&contents).collect::<Vec<_>>();
// Pump arguments back to the stack, in reverse order so we can `Vec::pop` and visit in original front-to-back order.
let rev_args = resp_file_args.iter().rev().map(|s| s.into());
self.stack.extend(rev_args);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/msvc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::compiler::args::*;
use crate::compiler::c::{
ArtifactDescriptor, CCompilerImpl, CCompilerKind, Language, ParsedArguments,
};
use crate::compiler::response_file::SplitMsvcResponseFileArgs;
use crate::compiler::response_file::SplitResponseFileArgs;
use crate::compiler::{
clang, gcc, write_temp_file, Cacheable, ColorMode, CompileCommand, CompilerArguments,
};
Expand Down Expand Up @@ -1222,7 +1222,7 @@ impl<'a> Iterator for ExpandIncludeFile<'a> {
trace!("Expanded response file {:?} to {:?}", file_path, content);

// Parse the response file contents, taking into account quote-wrapped strings and new-line separators.
let resp_file_args = SplitMsvcResponseFileArgs::from(&content).collect::<Vec<_>>();
let resp_file_args = SplitResponseFileArgs::from(&content).collect::<Vec<_>>();
// Pump arguments back to the stack, in reverse order so we can `Vec::pop` and visit in original front-to-back order.
let rev_args = resp_file_args.iter().rev().map(|s| s.into());
self.stack.extend(rev_args);
Expand Down
54 changes: 48 additions & 6 deletions src/compiler/response_file.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

/// An iterator over the arguments in a Windows command line.
/// An iterator over the arguments in a response file.
///
/// This produces results identical to `CommandLineToArgvW` except in the
/// following cases:
Expand All @@ -24,13 +23,13 @@
/// - https://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx
/// - https://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft(v=vs.85).aspx
#[derive(Clone, Debug)]
pub struct SplitMsvcResponseFileArgs<'a> {
pub struct SplitResponseFileArgs<'a> {
/// String slice of the file content that is being parsed.
/// Slice is mutated as this iterator is executed.
file_content: &'a str,
}

impl<'a, T> From<&'a T> for SplitMsvcResponseFileArgs<'a>
impl<'a, T> From<&'a T> for SplitResponseFileArgs<'a>
where
T: AsRef<str> + 'static,
{
Expand All @@ -41,7 +40,7 @@ where
}
}

impl<'a> SplitMsvcResponseFileArgs<'a> {
impl<'a> SplitResponseFileArgs<'a> {
/// Appends backslashes to `target` by decrementing `count`.
/// If `step` is >1, then `count` is decremented by `step`, resulting in 1 backslash appended for every `step`.
fn append_backslashes_to(target: &mut String, count: &mut usize, step: usize) {
Expand All @@ -52,7 +51,7 @@ impl<'a> SplitMsvcResponseFileArgs<'a> {
}
}

impl<'a> Iterator for SplitMsvcResponseFileArgs<'a> {
impl<'a> Iterator for SplitResponseFileArgs<'a> {
type Item = String;

fn next(&mut self) -> Option<String> {
Expand Down Expand Up @@ -121,3 +120,46 @@ impl<'a> Iterator for SplitMsvcResponseFileArgs<'a> {
Some(arg)
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn parse_simple_args() {
let content = "-A1 -A2 -A3 -I ../includes";
let args = SplitResponseFileArgs::from(&content).collect::<Vec<_>>();
assert_eq!(args[0], "-A1");
assert_eq!(args[1], "-A2");
assert_eq!(args[2], "-A3");
assert_eq!(args[3], "-I");
assert_eq!(args[4], "../includes");
}

#[test]
fn parse_quoted_path_arg() {
let content = "-I \"../included headers\"";
let args = SplitResponseFileArgs::from(&content).collect::<Vec<_>>();
assert_eq!(args[0], "-I");
assert_eq!(args[1], "../included headers");
}

#[test]
fn parse_escaped_quoted_path_arg() {
let content = "-I \"../included \\\"headers\\\"\"";
let args = SplitResponseFileArgs::from(&content).collect::<Vec<_>>();
assert_eq!(args[0], "-I");
assert_eq!(args[1], "../included \"headers\"");
}

#[test]
fn parse_various_whitespace_characters() {
let content = "-A1 -A2\n-A3\n\r-A4\r-A5\n ";
let args = SplitResponseFileArgs::from(&content).collect::<Vec<_>>();
assert_eq!(args[0], "-A1");
assert_eq!(args[1], "-A2");
assert_eq!(args[2], "-A3");
assert_eq!(args[3], "-A4");
assert_eq!(args[4], "-A5");
}
}

0 comments on commit 1562001

Please sign in to comment.