#![allow(unused_imports,dead_code,unused_variables)]
use ::compiler::{
gcc,
Cacheable,
Compiler,
CompilerArguments,
ParsedArguments,
run_input_output,
};
use mock_command::{
CommandCreator,
CommandCreatorSync,
RunCommand,
};
use std::fs::File;
use std::io::{
self,
Error,
ErrorKind,
Write,
};
use std::path::Path;
use std::process;
use tempdir::TempDir;
const ARGS_WITH_VALUE: &'static [&'static str] = &["-arch"];
pub fn argument_takes_value(arg: &str) -> bool {
gcc::ARGS_WITH_VALUE.contains(&arg) || ARGS_WITH_VALUE.contains(&arg)
}
pub fn compile<T : CommandCreatorSync>(mut creator: T, compiler: &Compiler, preprocessor_output: Vec<u8>, parsed_args: &ParsedArguments, cwd: &str) -> io::Result<(Cacheable, process::Output)> {
trace!("compile");
let tempdir = try!(TempDir::new("sccache"));
let filename = try!(Path::new(&parsed_args.input).file_name().ok_or(Error::new(ErrorKind::Other, "Missing input filename")));
let input = tempdir.path().join(filename);
{
try!(File::create(&input)
.and_then(|mut f| f.write_all(&preprocessor_output)))
}
let out_file = try!(parsed_args.outputs.get("obj").ok_or(Error::new(ErrorKind::Other, "Missing object file output")));
let mut cmd = creator.new_command_sync(&compiler.executable);
cmd.arg("-c")
.arg(&input)
.arg("-o")
.arg(&out_file)
.args(&parsed_args.common_args)
.current_dir(cwd);
let output = try!(run_input_output(cmd, None));
if !output.status.success() && parsed_args.common_args.iter().any(|a| a.starts_with("-Werror")) {
let mut cmd = creator.new_command_sync(&compiler.executable);
cmd.arg("-c")
.arg(&parsed_args.input)
.arg("-o")
.arg(&out_file)
.args(&parsed_args.common_args)
.current_dir(cwd);
let output = try!(run_input_output(cmd, None));
Ok((Cacheable::Yes, output))
} else {
Ok((Cacheable::Yes, output))
}
}
#[cfg(test)]
mod test {
use super::*;
use std::collections::HashMap;
use mock_command::*;
use compiler::*;
use compiler::gcc;
use test::utils::*;
fn _parse_arguments(arguments: &[String]) -> CompilerArguments {
gcc::parse_arguments(arguments, argument_takes_value)
}
#[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"));
assert_eq!(1, outputs.len());
assert!(preprocessor_args.is_empty());
assert!(common_args.is_empty());
}
o @ _ => assert!(false, format!("Got unexpected parse result: {:?}", o)),
}
}
#[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"));
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)),
}
}
#[test]
fn test_compile_simple() {
let creator = new_creator();
let f = TestFixture::new();
let parsed_args = ParsedArguments {
input: "foo.c".to_owned(),
extension: "c".to_owned(),
depfile: None,
outputs: vec![("obj", "foo.o".to_owned())].into_iter().collect::<HashMap<&'static str, String>>(),
preprocessor_args: vec!(),
common_args: vec!(),
};
let compiler = Compiler::new(f.bins[0].to_str().unwrap(),
CompilerKind::Clang).unwrap();
next_command(&creator, Ok(MockChild::new(exit_status(0), "", "")));
let (cacheable, _) = compile(creator.clone(), &compiler, vec!(), &parsed_args, f.tempdir.path().to_str().unwrap()).unwrap();
assert_eq!(Cacheable::Yes, cacheable);
assert_eq!(0, creator.lock().unwrap().children.len());
}
#[test]
fn test_compile_werror_fails() {
let creator = new_creator();
let f = TestFixture::new();
let parsed_args = ParsedArguments {
input: "foo.c".to_owned(),
extension: "c".to_owned(),
depfile: None,
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"),
};
let compiler = Compiler::new(f.bins[0].to_str().unwrap(),
CompilerKind::Clang).unwrap();
next_command(&creator, Ok(MockChild::new(exit_status(1), "", "")));
next_command(&creator, Ok(MockChild::new(exit_status(0), "", "")));
let (cacheable, output) = compile(creator.clone(), &compiler, vec!(), &parsed_args, f.tempdir.path().to_str().unwrap()).unwrap();
assert_eq!(Cacheable::Yes, cacheable);
assert_eq!(exit_status(0), output.status);
assert_eq!(0, creator.lock().unwrap().children.len());
}
}