Skip to content

Commit

Permalink
Support -showIncludes on MSVC
Browse files Browse the repository at this point in the history
Track the `-showIncludes` flag being passed down to the compilation itself, and
then also be sure to thread the entire output of the preprocessor down to
compilations instead of just stdout. Once that was done support was implemented
by simply prepending the preprocessor stderr to the compiler stderr if the
`-showIncludes` flag was passed.
  • Loading branch information
alexcrichton committed Mar 25, 2017
1 parent a77d143 commit e927bc8
Show file tree
Hide file tree
Showing 5 changed files with 441 additions and 220 deletions.
12 changes: 7 additions & 5 deletions src/compiler/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ pub struct ParsedArguments {
pub preprocessor_args: Vec<String>,
/// Commandline arguments for the preprocessor or the compiler.
pub common_args: Vec<String>,
/// Whether or not the `-showIncludes` argument is passed on MSVC
pub msvc_show_includes: bool,
}

impl ParsedArguments {
Expand All @@ -77,7 +79,7 @@ struct CCompilation<I: CCompilerImpl> {
parsed_args: ParsedArguments,
executable: String,
/// The output from running the preprocessor.
preprocessor_output: Vec<u8>,
preprocessor_result: process::Output,
compiler: I,
}

Expand Down Expand Up @@ -113,7 +115,7 @@ pub trait CCompilerImpl: Clone + fmt::Debug + Send + 'static {
fn compile<T>(&self,
creator: &T,
executable: &str,
preprocessor_output: Vec<u8>,
preprocessor_result: process::Output,
parsed_args: &ParsedArguments,
cwd: &str,
pool: &CpuPool)
Expand Down Expand Up @@ -209,7 +211,7 @@ impl<T, I> CompilerHasher<T> for CCompilerHasher<I>
compilation: Box::new(CCompilation {
parsed_args: parsed_args,
executable: executable,
preprocessor_output: preprocessor_result.stdout,
preprocessor_result: preprocessor_result,
compiler: compiler,
}),
}
Expand All @@ -235,8 +237,8 @@ impl<T: CommandCreatorSync, I: CCompilerImpl> Compilation<T> for CCompilation<I>
-> SFuture<(Cacheable, process::Output)>
{
let me = *self;
let CCompilation { parsed_args, executable, preprocessor_output, compiler } = me;
compiler.compile(creator, &executable, preprocessor_output, &parsed_args, cwd, pool)
let CCompilation { parsed_args, executable, preprocessor_result, compiler } = me;
compiler.compile(creator, &executable, preprocessor_result, &parsed_args, cwd, pool)
}

fn outputs<'a>(&'a self) -> Box<Iterator<Item=(&'a str, &'a String)> + 'a>
Expand Down
83 changes: 51 additions & 32 deletions src/compiler/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ impl CCompilerImpl for Clang {
fn compile<T>(&self,
creator: &T,
executable: &str,
preprocessor_output: Vec<u8>,
preprocessor_result: process::Output,
parsed_args: &ParsedArguments,
cwd: &str,
pool: &CpuPool)
-> SFuture<(Cacheable, process::Output)>
where T: CommandCreatorSync
{
compile(creator, executable, preprocessor_output, parsed_args, cwd, pool)
compile(creator, executable, preprocessor_result, parsed_args, cwd, pool)
}
}

Expand All @@ -87,7 +87,7 @@ pub fn argument_takes_value(arg: &str) -> bool {

fn compile<T>(creator: &T,
executable: &str,
preprocessor_output: Vec<u8>,
preprocessor_result: process::Output,
parsed_args: &ParsedArguments,
cwd: &str,
pool: &CpuPool)
Expand All @@ -102,7 +102,7 @@ fn compile<T>(creator: &T,
Some(name) => name,
None => return future::err("missing input filename".into()).boxed(),
};
write_temp_file(pool, filename.as_ref(), preprocessor_output)
write_temp_file(pool, filename.as_ref(), preprocessor_result.stdout)
};
let input = parsed_args.input.clone();
let out_file = match parsed_args.outputs.get("obj") {
Expand Down Expand Up @@ -170,36 +170,53 @@ mod test {

#[test]
fn test_parse_arguments_simple() {
match _parse_arguments(&stringvec!["-c", "foo.c", "-o", "foo.o"]) {
CompilerArguments::Ok(ParsedArguments { input, extension, depfile: _depfile, outputs, preprocessor_args, common_args }) => {
assert!(true, "Parsed ok");
assert_eq!("foo.c", input);
assert_eq!("c", extension);
assert_map_contains!(outputs, ("obj", "foo.o"));
//TODO: fix assert_map_contains to assert no extra keys!
assert_eq!(1, outputs.len());
assert!(preprocessor_args.is_empty());
assert!(common_args.is_empty());
}
o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)),
}
let args = stringvec!["-c", "foo.c", "-o", "foo.o"];
let ParsedArguments {
input,
extension,
depfile: _,
outputs,
preprocessor_args,
msvc_show_includes,
common_args,
} = match _parse_arguments(&args) {
CompilerArguments::Ok(args) => args,
o @ _ => panic!("Got unexpected parse result: {:?}", o),
};
assert!(true, "Parsed ok");
assert_eq!("foo.c", input);
assert_eq!("c", extension);
assert_map_contains!(outputs, ("obj", "foo.o"));
//TODO: fix assert_map_contains to assert no extra keys!
assert_eq!(1, outputs.len());
assert!(preprocessor_args.is_empty());
assert!(common_args.is_empty());
assert!(!msvc_show_includes);
}

#[test]
fn test_parse_arguments_values() {
match _parse_arguments(&stringvec!["-c", "foo.cxx", "-arch", "xyz", "-fabc","-I", "include", "-o", "foo.o", "-include", "file"]) {
CompilerArguments::Ok(ParsedArguments { input, extension, depfile: _depfile, outputs, preprocessor_args, common_args }) => {
assert!(true, "Parsed ok");
assert_eq!("foo.cxx", input);
assert_eq!("cxx", extension);
assert_map_contains!(outputs, ("obj", "foo.o"));
//TODO: fix assert_map_contains to assert no extra keys!
assert_eq!(1, outputs.len());
assert!(preprocessor_args.is_empty());
assert_eq!(stringvec!["-arch", "xyz", "-fabc", "-I", "include", "-include", "file"], common_args);
}
o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)),
}
let args = stringvec!["-c", "foo.cxx", "-arch", "xyz", "-fabc", "-I", "include", "-o", "foo.o", "-include", "file"];
let ParsedArguments {
input,
extension,
depfile: _,
outputs,
preprocessor_args,
msvc_show_includes,
common_args,
} = match _parse_arguments(&args) {
CompilerArguments::Ok(args) => args,
o @ _ => panic!("Got unexpected parse result: {:?}", o),
};
assert!(true, "Parsed ok");
assert_eq!("foo.cxx", input);
assert_eq!("cxx", extension);
assert_map_contains!(outputs, ("obj", "foo.o"));
//TODO: fix assert_map_contains to assert no extra keys!
assert_eq!(1, outputs.len());
assert!(preprocessor_args.is_empty());
assert_eq!(stringvec!["-arch", "xyz", "-fabc", "-I", "include", "-include", "file"], common_args);
}

#[test]
Expand All @@ -214,13 +231,14 @@ mod test {
outputs: vec![("obj", "foo.o".to_owned())].into_iter().collect::<HashMap<&'static str, String>>(),
preprocessor_args: vec!(),
common_args: vec!(),
msvc_show_includes: false,
};
let compiler = f.bins[0].to_str().unwrap();
// Compiler invocation.
next_command(&creator, Ok(MockChild::new(exit_status(0), "", "")));
let (cacheable, _) = compile(&creator,
&compiler,
vec!(),
empty_output(),
&parsed_args,
f.tempdir.path().to_str().unwrap(),
&pool).wait().unwrap();
Expand All @@ -241,6 +259,7 @@ mod test {
outputs: vec![("obj", "foo.o".to_owned())].into_iter().collect::<HashMap<&'static str, String>>(),
preprocessor_args: vec!(),
common_args: stringvec!("-c", "-o", "foo.o", "-Werror=blah", "foo.c"),
msvc_show_includes: false,
};
let compiler = f.bins[0].to_str().unwrap();
// First compiler invocation fails.
Expand All @@ -249,7 +268,7 @@ mod test {
next_command(&creator, Ok(MockChild::new(exit_status(0), "", "")));
let (cacheable, output) = compile(&creator,
&compiler,
vec!(),
empty_output(),
&parsed_args,
f.tempdir.path().to_str().unwrap(),
&pool).wait().unwrap();
Expand Down
Loading

0 comments on commit e927bc8

Please sign in to comment.