diff --git a/src/compiler/c.rs b/src/compiler/c.rs index 8328203163..55b75230cc 100644 --- a/src/compiler/c.rs +++ b/src/compiler/c.rs @@ -64,6 +64,8 @@ pub struct ParsedArguments { pub preprocessor_args: Vec, /// Commandline arguments for the preprocessor or the compiler. pub common_args: Vec, + /// Whether or not the `-showIncludes` argument is passed on MSVC + pub msvc_show_includes: bool, } impl ParsedArguments { @@ -77,7 +79,7 @@ struct CCompilation { parsed_args: ParsedArguments, executable: String, /// The output from running the preprocessor. - preprocessor_output: Vec, + preprocessor_result: process::Output, compiler: I, } @@ -113,7 +115,7 @@ pub trait CCompilerImpl: Clone + fmt::Debug + Send + 'static { fn compile(&self, creator: &T, executable: &str, - preprocessor_output: Vec, + preprocessor_result: process::Output, parsed_args: &ParsedArguments, cwd: &str, pool: &CpuPool) @@ -209,7 +211,7 @@ impl CompilerHasher for CCompilerHasher compilation: Box::new(CCompilation { parsed_args: parsed_args, executable: executable, - preprocessor_output: preprocessor_result.stdout, + preprocessor_result: preprocessor_result, compiler: compiler, }), } @@ -235,8 +237,8 @@ impl Compilation for CCompilation -> 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 + 'a> diff --git a/src/compiler/clang.rs b/src/compiler/clang.rs index b1b7878dcc..e206dcfd71 100644 --- a/src/compiler/clang.rs +++ b/src/compiler/clang.rs @@ -66,14 +66,14 @@ impl CCompilerImpl for Clang { fn compile(&self, creator: &T, executable: &str, - preprocessor_output: Vec, + 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) } } @@ -87,7 +87,7 @@ pub fn argument_takes_value(arg: &str) -> bool { fn compile(creator: &T, executable: &str, - preprocessor_output: Vec, + preprocessor_result: process::Output, parsed_args: &ParsedArguments, cwd: &str, pool: &CpuPool) @@ -102,7 +102,7 @@ fn compile(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") { @@ -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] @@ -214,13 +231,14 @@ mod test { outputs: vec![("obj", "foo.o".to_owned())].into_iter().collect::>(), 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(); @@ -241,6 +259,7 @@ mod test { outputs: vec![("obj", "foo.o".to_owned())].into_iter().collect::>(), 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. @@ -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(); diff --git a/src/compiler/gcc.rs b/src/compiler/gcc.rs index ec08f154b8..3acb01b8e3 100644 --- a/src/compiler/gcc.rs +++ b/src/compiler/gcc.rs @@ -60,14 +60,14 @@ impl CCompilerImpl for GCC { fn compile(&self, creator: &T, executable: &str, - preprocessor_output: Vec, + 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) } } @@ -225,6 +225,7 @@ fn _parse_arguments(arguments: &[String], outputs: outputs, preprocessor_args: preprocessor_args, common_args: common_args, + msvc_show_includes: false, }) } @@ -251,7 +252,7 @@ pub fn preprocess(creator: &T, fn compile(creator: &T, executable: &str, - preprocessor_output: Vec, + preprocessor_result: process::Output, parsed_args: &ParsedArguments, cwd: &str, _pool: &CpuPool) @@ -280,7 +281,7 @@ fn compile(creator: &T, .args(&["-", "-o", &output.clone()]) .args(&parsed_args.common_args) .current_dir(cwd); - Box::new(run_input_output(cmd, Some(preprocessor_output)).map(|output| { + Box::new(run_input_output(cmd, Some(preprocessor_result.stdout)).map(|output| { (Cacheable::Yes, output) })) } @@ -363,138 +364,210 @@ 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_split_dwarf() { - match _parse_arguments(&stringvec!["-gsplit-dwarf", "-c", "foo.cpp", "-o", "foo.o"]) { - CompilerArguments::Ok(ParsedArguments { input, extension, depfile: _depfile, outputs, preprocessor_args, common_args }) => { - assert!(true, "Parsed ok"); - assert_eq!("foo.cpp", input); - assert_eq!("cpp", extension); - assert_map_contains!(outputs, ("obj", "foo.o"), ("dwo", "foo.dwo")); - //TODO: fix assert_map_contains to assert no extra keys! - assert_eq!(2, outputs.len()); - assert!(preprocessor_args.is_empty()); - assert_eq!(stringvec!["-gsplit-dwarf"], common_args); - } - o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)), - } + let args = stringvec!["-gsplit-dwarf", "-c", "foo.cpp", "-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.cpp", input); + assert_eq!("cpp", extension); + assert_map_contains!(outputs, ("obj", "foo.o"), ("dwo", "foo.dwo")); + //TODO: fix assert_map_contains to assert no extra keys! + assert_eq!(2, outputs.len()); + assert!(preprocessor_args.is_empty()); + assert_eq!(stringvec!["-gsplit-dwarf"], common_args); + assert!(!msvc_show_includes); } #[test] fn test_parse_arguments_extra() { - match _parse_arguments(&stringvec!["-c", "foo.cc", "-fabc", "-o", "foo.o", "-mxyz"]) { - CompilerArguments::Ok(ParsedArguments { input, extension, depfile: _depfile, outputs, preprocessor_args, common_args }) => { - assert!(true, "Parsed ok"); - assert_eq!("foo.cc", input); - assert_eq!("cc", 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!["-fabc", "-mxyz"], common_args); - } - o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)), - } + let args = stringvec!["-c", "foo.cc", "-fabc", "-o", "foo.o", "-mxyz"]; + 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.cc", input); + assert_eq!("cc", 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!["-fabc", "-mxyz"], common_args); + assert!(!msvc_show_includes); } #[test] fn test_parse_arguments_values() { - match _parse_arguments(&stringvec!["-c", "foo.cxx", "-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!["-fabc", "-I", "include", "-include", "file"], common_args); - } - o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)), - } + let args = stringvec!["-c", "foo.cxx", "-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!["-fabc", "-I", "include", "-include", "file"], common_args); + assert!(!msvc_show_includes); } #[test] fn test_parse_arguments_preprocessor_args() { - match _parse_arguments(&stringvec!["-c", "foo.c", "-fabc", "-MF", "file", "-o", "foo.o", "-MQ", "abc"]) { - 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_eq!(stringvec!["-MF", "file", "-MQ", "abc"], preprocessor_args); - assert_eq!(stringvec!["-fabc"], common_args); - } - o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)), - } + let args = stringvec!["-c", "foo.c", "-fabc", "-MF", "file", "-o", "foo.o", "-MQ", "abc"]; + 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_eq!(stringvec!["-MF", "file", "-MQ", "abc"], preprocessor_args); + assert_eq!(stringvec!["-fabc"], common_args); + assert!(!msvc_show_includes); } #[test] fn test_parse_arguments_explicit_dep_target() { - match _parse_arguments(&stringvec!["-c", "foo.c", "-MT", "depfile", "-fabc", "-MF", "file", "-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_eq!(stringvec!["-MF", "file"], preprocessor_args); - assert_eq!(stringvec!["-fabc"], common_args); - } - o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)), - } + let args = stringvec!["-c", "foo.c", "-MT", "depfile", "-fabc", "-MF", "file", "-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_eq!(stringvec!["-MF", "file"], preprocessor_args); + assert_eq!(stringvec!["-fabc"], common_args); + assert!(!msvc_show_includes); } #[test] fn test_parse_arguments_explicit_dep_target_needed() { - match _parse_arguments(&stringvec!["-c", "foo.c", "-MT", "depfile", "-fabc", "-MF", "file", "-o", "foo.o", "-MD"]) { - 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_eq!(stringvec!["-MF", "file", "-MD", "-MT", "depfile"], preprocessor_args); - assert_eq!(stringvec!["-fabc"], common_args); - } - o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)), - } + let args = stringvec!["-c", "foo.c", "-MT", "depfile", "-fabc", "-MF", "file", "-o", "foo.o", "-MD"]; + 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_eq!(stringvec!["-MF", "file", "-MD", "-MT", "depfile"], preprocessor_args); + assert_eq!(stringvec!["-fabc"], common_args); + assert!(!msvc_show_includes); } #[test] fn test_parse_arguments_dep_target_needed() { - match _parse_arguments(&stringvec!["-c", "foo.c", "-fabc", "-MF", "file", "-o", "foo.o", "-MD"]) { - 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_eq!(stringvec!["-MF", "file", "-MD", "-MT", "foo.o"], preprocessor_args); - assert_eq!(stringvec!["-fabc"], common_args); - } - o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)), - } + let args = stringvec!["-c", "foo.c", "-fabc", "-MF", "file", "-o", "foo.o", "-MD"]; + 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_eq!(stringvec!["-MF", "file", "-MD", "-MT", "foo.o"], preprocessor_args); + assert_eq!(stringvec!["-fabc"], common_args); + assert!(!msvc_show_includes); } #[test] @@ -542,18 +615,26 @@ mod test { -c foo.c -o foo.o\ ").unwrap(); let arg = format!("@{}", td.path().join("foo").display()); - match _parse_arguments(&[arg]) { - 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 ParsedArguments { + input, + extension, + depfile: _, + outputs, + preprocessor_args, + msvc_show_includes, + common_args, + } = match _parse_arguments(&[arg]) { + 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); } } diff --git a/src/compiler/msvc.rs b/src/compiler/msvc.rs index 145aff9805..85e852bd36 100644 --- a/src/compiler/msvc.rs +++ b/src/compiler/msvc.rs @@ -34,6 +34,7 @@ use std::io::{ self, Write, }; +use std::mem; use std::path::Path; use std::process::{self,Stdio}; @@ -71,14 +72,14 @@ impl CCompilerImpl for MSVC { fn compile(&self, creator: &T, executable: &str, - preprocessor_output: Vec, + 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) } } @@ -150,8 +151,8 @@ pub fn parse_arguments(arguments: &[String]) -> CompilerArguments CompilerArguments { depfile = Some(v[5..].to_owned()); } + "-showIncludes" => show_includes = true, // Arguments we can't handle. - "-showIncludes" => return CompilerArguments::CannotCache, a if a.starts_with('@') => return CompilerArguments::CannotCache, // Arguments we can't handle because they output more files. // TODO: support more multi-file outputs. @@ -247,6 +248,7 @@ pub fn parse_arguments(arguments: &[String]) -> CompilerArguments(creator: &T, fn compile(creator: &T, executable: &str, - preprocessor_output: Vec, + preprocessor_result: process::Output, parsed_args: &ParsedArguments, cwd: &str, pool: &CpuPool) @@ -393,7 +395,7 @@ fn compile(creator: &T, Some(name) => name, None => return f_err("missing input filename"), }; - write_temp_file(pool, filename.as_ref(), preprocessor_output) + write_temp_file(pool, filename.as_ref(), preprocessor_result.stdout) }; let mut cmd = creator.clone().new_command_sync(executable); @@ -421,7 +423,7 @@ fn compile(creator: &T, .arg(&format!("-Fo{}", out_file)) .args(&parsed_args.common_args) .current_dir(cwd); - Box::new(output.and_then(move |output| -> SFuture<_> { + let ret = output.and_then(move |output| -> SFuture<_> { if output.status.success() { f_ok((cacheable, output)) } else { @@ -430,6 +432,19 @@ fn compile(creator: &T, (cacheable, output) })) } + }); + + // If the `-showIncludes` command line option was originally passed we need + // to be sure to ship the output from the preprocessor as the actual + // result of this compilation. + let mut extra_stderr = Vec::new(); + if parsed_args.msvc_show_includes { + extra_stderr = preprocessor_result.stderr; + } + Box::new(ret.map(|(cacheable, mut output)| { + let prev = mem::replace(&mut output.stderr, extra_stderr); + output.stderr.extend(prev); + (cacheable, output) })) } @@ -464,70 +479,132 @@ mod test { #[test] fn test_parse_arguments_simple() { - match parse_arguments(&stringvec!["-c", "foo.c", "-Fofoo.obj"]) { - 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.obj")); - //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", "-Fofoo.obj"]; + 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.obj")); + //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 parse_argument_slashes() { + let args = stringvec!["-c", "foo.c", "/Fofoo.obj"]; + 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.obj")); + //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_extra() { - match parse_arguments(&stringvec!["-c", "foo.c", "-foo", "-Fofoo.obj", "-bar"]) { - 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.obj")); - //TODO: fix assert_map_contains to assert no extra keys! - assert_eq!(1, outputs.len()); - assert!(preprocessor_args.is_empty()); - assert_eq!(common_args, &["-foo", "-bar"]); - } - o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)), - } + let args = stringvec!["-c", "foo.c", "-foo", "-Fofoo.obj", "-bar"]; + 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.obj")); + //TODO: fix assert_map_contains to assert no extra keys! + assert_eq!(1, outputs.len()); + assert!(preprocessor_args.is_empty()); + assert_eq!(common_args, &["-foo", "-bar"]); + assert!(!msvc_show_includes); } #[test] fn test_parse_arguments_values() { - match parse_arguments(&stringvec!["-c", "foo.c", "-FI", "file", "-Fofoo.obj"]) { - 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.obj")); - //TODO: fix assert_map_contains to assert no extra keys! - assert_eq!(1, outputs.len()); - assert!(preprocessor_args.is_empty()); - assert_eq!(common_args, &["-FI", "file"]); - } - o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)), - } + let args = stringvec!["-c", "foo.c", "-FI", "file", "-Fofoo.obj", "/showIncludes"]; + 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.obj")); + //TODO: fix assert_map_contains to assert no extra keys! + assert_eq!(1, outputs.len()); + assert!(preprocessor_args.is_empty()); + assert_eq!(common_args, &["-FI", "file"]); + assert!(msvc_show_includes); } #[test] fn test_parse_arguments_pdb() { - match parse_arguments(&stringvec!["-c", "foo.c", "-Zi", "-Fdfoo.pdb", "-Fofoo.obj"]) { - 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.obj"), ("pdb", "foo.pdb")); - //TODO: fix assert_map_contains to assert no extra keys! - assert_eq!(2, outputs.len()); - assert!(preprocessor_args.is_empty()); - assert_eq!(common_args, &["-Zi", "-Fdfoo.pdb"]); - } - o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)), - } + let args = stringvec!["-c", "foo.c", "-Zi", "-Fdfoo.pdb", "-Fofoo.obj"]; + 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.obj"), ("pdb", "foo.pdb")); + //TODO: fix assert_map_contains to assert no extra keys! + assert_eq!(2, outputs.len()); + assert!(preprocessor_args.is_empty()); + assert_eq!(common_args, &["-Zi", "-Fdfoo.pdb"]); + assert!(!msvc_show_includes); } #[test] @@ -584,6 +661,7 @@ mod test { outputs: vec![("obj", "foo.obj".to_owned())].into_iter().collect::>(), preprocessor_args: vec!(), common_args: vec!(), + msvc_show_includes: false, }; let compiler = f.bins[0].to_str().unwrap(); // Compiler invocation. @@ -591,7 +669,7 @@ mod test { next_command(&creator, Ok(MockChild::new(exit_status(1), "", ""))); let (cacheable, _) = compile(&creator, &compiler, - vec!(), + empty_output(), &parsed_args, f.tempdir.path().to_str().unwrap(), &pool).wait().unwrap(); @@ -614,6 +692,7 @@ mod test { ("pdb", pdb.to_str().unwrap().to_owned())].into_iter().collect::>(), preprocessor_args: vec!(), common_args: vec!(), + msvc_show_includes: false, }; let compiler = f.bins[0].to_str().unwrap(); // Compiler invocation. @@ -621,7 +700,7 @@ mod test { next_command(&creator, Ok(MockChild::new(exit_status(1), "", ""))); let (cacheable, _) = compile(&creator, &compiler, - vec!(), + empty_output(), &parsed_args, f.tempdir.path().to_str().unwrap(), &pool).wait().unwrap(); @@ -642,6 +721,7 @@ mod test { outputs: vec![("obj", "foo.obj".to_owned())].into_iter().collect::>(), preprocessor_args: vec!(), common_args: vec!(), + msvc_show_includes: false, }; let compiler = f.bins[0].to_str().unwrap(); // First compiler invocation fails. @@ -650,7 +730,7 @@ mod test { 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(); @@ -658,4 +738,34 @@ mod test { // Ensure that we ran all processes. assert_eq!(0, creator.lock().unwrap().children.len()); } + + #[test] + fn preprocess_output_appended() { + let creator = new_creator(); + let pool = CpuPool::new(1); + let f = TestFixture::new(); + let parsed_args = ParsedArguments { + input: "foo.c".to_owned(), + extension: "c".to_owned(), + depfile: None, + outputs: vec![("obj", "foo.obj".to_owned())].into_iter().collect::>(), + preprocessor_args: vec!(), + common_args: vec!(), + msvc_show_includes: true, + }; + let compiler = f.bins[0].to_str().unwrap(); + // Compiler invocation. + next_command(&creator, Ok(MockChild::new(exit_status(0), "", "bar"))); + next_command(&creator, Ok(MockChild::new(exit_status(1), "", ""))); + let mut output = empty_output(); + output.stderr.extend(b"foo"); + let (_, output) = compile(&creator, + &compiler, + output, + &parsed_args, + f.tempdir.path().to_str().unwrap(), + &pool).wait().unwrap(); + assert_eq!(0, creator.lock().unwrap().children.len()); + assert_eq!(output.stderr, b"foobar"); + } } diff --git a/src/test/utils.rs b/src/test/utils.rs index 5191718c1f..08bae1dd0f 100644 --- a/src/test/utils.rs +++ b/src/test/utils.rs @@ -22,6 +22,7 @@ use std::ffi::OsString; use std::fs::{self,File}; use std::io; use std::path::{Path,PathBuf}; +use std::process; use std::sync::{Arc,Mutex}; use tempdir::TempDir; @@ -186,6 +187,14 @@ pub fn cache_stats_map(mut stats: CacheStats) -> HashMap { stats.take_stats().into_iter().map(|mut s| (s.take_name(), if s.has_count() { CacheStat::Count(s.get_count()) } else if s.has_size() { CacheStat::Size(s.get_size()) } else { CacheStat::String(s.take_str()) })).collect() } +pub fn empty_output() -> process::Output { + process::Output { + stdout: Vec::new(), + stderr: Vec::new(), + status: exit_status(0), + } +} + #[test] fn test_map_contains_ok() { use std::collections::HashMap;