diff --git a/src/compiler/clang.rs b/src/compiler/clang.rs index b7199812da..9696f75e5c 100644 --- a/src/compiler/clang.rs +++ b/src/compiler/clang.rs @@ -50,7 +50,7 @@ pub fn argument_takes_value(arg: &str) -> bool { pub fn compile(creator: &T, compiler: &Compiler, - preprocessor_output: Vec, + preprocessor_result: process::Output, parsed_args: &ParsedArguments, cwd: &str, pool: &CpuPool) @@ -65,7 +65,7 @@ pub 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") { @@ -133,36 +133,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: _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: _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] @@ -177,6 +194,7 @@ mod test { outputs: vec![("obj", "foo.o".to_owned())].into_iter().collect::>(), preprocessor_args: vec!(), common_args: vec!(), + msvc_show_includes: false, }; let compiler = Compiler::new(f.bins[0].to_str().unwrap(), CompilerKind::Clang).unwrap(); @@ -184,7 +202,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(); @@ -205,6 +223,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 = Compiler::new(f.bins[0].to_str().unwrap(), CompilerKind::Clang).unwrap(); @@ -214,7 +233,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/compiler.rs b/src/compiler/compiler.rs index bb8c4ac7d5..d14ddfdec9 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -104,7 +104,7 @@ impl CompilerKind { pub fn compile(&self, creator: &T, compiler: &Compiler, - preprocessor_output: Vec, + preprocessor_result: process::Output, parsed_args: &ParsedArguments, cwd: &str, pool: &CpuPool) @@ -112,9 +112,9 @@ impl CompilerKind { where T: CommandCreatorSync, { match *self { - CompilerKind::Gcc => gcc::compile(creator, compiler, preprocessor_output, parsed_args, cwd, pool), - CompilerKind::Clang => clang::compile(creator, compiler, preprocessor_output, parsed_args, cwd, pool), - CompilerKind::Msvc { .. } => msvc::compile(creator, compiler, preprocessor_output, parsed_args, cwd, pool), + CompilerKind::Gcc => gcc::compile(creator, compiler, preprocessor_result, parsed_args, cwd, pool), + CompilerKind::Clang => clang::compile(creator, compiler, preprocessor_result, parsed_args, cwd, pool), + CompilerKind::Msvc { .. } => msvc::compile(creator, compiler, preprocessor_result, parsed_args, cwd, pool), } } } @@ -135,6 +135,8 @@ pub struct ParsedArguments { pub preprocessor_args: Vec, /// Commandline arguments for the preprocessor or the compiler. pub common_args: Vec, + /// Whether, for MSVC, the `-showIncludes` flag is passed. + pub msvc_show_includes: bool, } impl ParsedArguments { @@ -421,11 +423,15 @@ impl Compiler { -> SFuture<(CompileResult, process::Output)> where T: CommandCreatorSync, { - let process::Output { stdout, .. } = preprocessor_result; let start = Instant::now(); let out_file = parsed_args.output_file().into_owned(); - let compile = self.kind.compile(creator, self, stdout, &parsed_args, cwd, &pool); + let compile = self.kind.compile(creator, + self, + preprocessor_result, + &parsed_args, + cwd, + &pool); Box::new(compile.and_then(move |(cacheable, compiler_result)| { let duration = start.elapsed(); if !compiler_result.status.success() { diff --git a/src/compiler/gcc.rs b/src/compiler/gcc.rs index f9456121c7..942c4de112 100644 --- a/src/compiler/gcc.rs +++ b/src/compiler/gcc.rs @@ -188,6 +188,7 @@ fn _parse_arguments(arguments: &[String], outputs: outputs, preprocessor_args: preprocessor_args, common_args: common_args, + msvc_show_includes: false, }) } @@ -214,7 +215,7 @@ pub fn preprocess(creator: &T, pub fn compile(creator: &T, compiler: &Compiler, - preprocessor_output: Vec, + preprocessor_result: process::Output, parsed_args: &ParsedArguments, cwd: &str, _pool: &CpuPool) @@ -243,7 +244,7 @@ pub 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) })) } @@ -326,138 +327,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: _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: _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: _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: _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: _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: _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: _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: _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] @@ -505,18 +578,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: _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 9b09b8e55f..be7e143964 100644 --- a/src/compiler/msvc.rs +++ b/src/compiler/msvc.rs @@ -35,6 +35,7 @@ use std::io::{ self, Write, }; +use std::mem; use std::path::Path; use std::process::{self,Stdio}; @@ -108,6 +109,7 @@ pub fn parse_arguments(arguments: &[String]) -> CompilerArguments { let mut debug_info = false; let mut pdb = None; let mut depfile = None; + let mut show_includes = false; //TODO: support arguments that start with / as well. let mut it = arguments.iter().map(|i| { @@ -134,7 +136,7 @@ pub fn parse_arguments(arguments: &[String]) -> CompilerArguments { depfile = Some(v[5..].to_owned()); } // Arguments we can't handle. - "-showIncludes" => return CompilerArguments::CannotCache, + "-showIncludes" => show_includes = true, a if a.starts_with('@') => return CompilerArguments::CannotCache, // Arguments we can't handle because they output more files. // TODO: support more multi-file outputs. @@ -205,6 +207,7 @@ pub fn parse_arguments(arguments: &[String]) -> CompilerArguments { outputs: outputs, preprocessor_args: vec!(), common_args: common_args, + msvc_show_includes: show_includes, }) } @@ -317,7 +320,7 @@ pub fn preprocess(creator: &T, pub fn compile(creator: &T, compiler: &Compiler, - preprocessor_output: Vec, + preprocessor_result: process::Output, parsed_args: &ParsedArguments, cwd: &str, pool: &CpuPool) @@ -351,7 +354,7 @@ pub 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 mut cmd = creator.clone().new_command_sync(&compiler.executable); @@ -379,7 +382,7 @@ pub 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() { future::ok((cacheable, output)).boxed() } else { @@ -388,6 +391,19 @@ pub 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) })) } @@ -422,70 +438,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: _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: _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: _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: _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: _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] @@ -542,6 +620,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 = Compiler::new(f.bins[0].to_str().unwrap(), CompilerKind::Msvc { includes_prefix: String::new() }).unwrap(); @@ -550,7 +629,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(); @@ -573,6 +652,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 = Compiler::new(f.bins[0].to_str().unwrap(), CompilerKind::Msvc { includes_prefix: String::new() }).unwrap(); @@ -581,7 +661,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(); @@ -602,6 +682,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 = Compiler::new(f.bins[0].to_str().unwrap(), CompilerKind::Msvc { includes_prefix: String::new() }).unwrap(); @@ -611,7 +692,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(); @@ -619,4 +700,35 @@ 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 = Compiler::new(f.bins[0].to_str().unwrap(), + CompilerKind::Msvc { includes_prefix: String::new() }).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 b200b50e6c..e46f9c6242 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; @@ -178,6 +179,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;