diff --git a/src/compiler/c.rs b/src/compiler/c.rs index f3fb295ba..530270b46 100644 --- a/src/compiler/c.rs +++ b/src/compiler/c.rs @@ -98,6 +98,15 @@ impl Language { } } } + + pub fn as_str(&self) -> &'static str { + match *self { + Language::C => "c", + Language::Cxx => "c++", + Language::ObjectiveC => "objc", + Language::ObjectiveCxx => "objc++", + } + } } /// A generic implementation of the `Compilation` trait for C/C++ compilers. @@ -233,6 +242,7 @@ impl CompilerHasher for CCompilerHasher let key = { hash_key(&executable_digest, + parsed_args.language, &parsed_args.common_args, &env_vars, &preprocessor_result.stdout) @@ -281,7 +291,7 @@ impl Compilation for CCompilation } /// The cache is versioned by the inputs to `hash_key`. -pub const CACHE_VERSION : &'static [u8] = b"4"; +pub const CACHE_VERSION : &'static [u8] = b"5"; /// Environment variables that are factored into the cache key. pub const CACHED_ENV_VARS : &'static [&'static str] = &[ @@ -291,6 +301,7 @@ pub const CACHED_ENV_VARS : &'static [&'static str] = &[ /// Compute the hash key of `compiler` compiling `preprocessor_output` with `args`. pub fn hash_key(compiler_digest: &str, + language: Language, arguments: &[OsString], env_vars: &[(OsString, OsString)], preprocessor_output: &[u8]) -> String @@ -299,6 +310,7 @@ pub fn hash_key(compiler_digest: &str, let mut m = Digest::new(); m.update(compiler_digest.as_bytes()); m.update(CACHE_VERSION); + m.update(language.as_str().as_bytes()); for arg in arguments { arg.hash(&mut HashToDigest { digest: &mut m }); } @@ -323,8 +335,8 @@ mod test { fn test_hash_key_executable_contents_differs() { let args = ovec!["a", "b", "c"]; const PREPROCESSED : &'static [u8] = b"hello world"; - assert_neq!(hash_key("abcd",&args, &[], &PREPROCESSED), - hash_key("wxyz",&args, &[], &PREPROCESSED)); + assert_neq!(hash_key("abcd", Language::C, &args, &[], &PREPROCESSED), + hash_key("wxyz", Language::C, &args, &[], &PREPROCESSED)); } #[test] @@ -335,21 +347,21 @@ mod test { let ab = ovec!["a", "b"]; let a = ovec!["a"]; const PREPROCESSED: &'static [u8] = b"hello world"; - assert_neq!(hash_key(digest, &abc, &[], &PREPROCESSED), - hash_key(digest, &xyz, &[], &PREPROCESSED)); + assert_neq!(hash_key(digest, Language::C, &abc, &[], &PREPROCESSED), + hash_key(digest, Language::C, &xyz, &[], &PREPROCESSED)); - assert_neq!(hash_key(digest, &abc, &[], &PREPROCESSED), - hash_key(digest, &ab, &[], &PREPROCESSED)); + assert_neq!(hash_key(digest, Language::C, &abc, &[], &PREPROCESSED), + hash_key(digest, Language::C, &ab, &[], &PREPROCESSED)); - assert_neq!(hash_key(digest, &abc, &[], &PREPROCESSED), - hash_key(digest, &a, &[], &PREPROCESSED)); + assert_neq!(hash_key(digest, Language::C, &abc, &[], &PREPROCESSED), + hash_key(digest, Language::C, &a, &[], &PREPROCESSED)); } #[test] fn test_hash_key_preprocessed_content_differs() { let args = ovec!["a", "b", "c"]; - assert_neq!(hash_key("abcd", &args, &[], &b"hello world"[..]), - hash_key("abcd", &args, &[], &b"goodbye"[..])); + assert_neq!(hash_key("abcd", Language::C, &args, &[], &b"hello world"[..]), + hash_key("abcd", Language::C, &args, &[], &b"goodbye"[..])); } #[test] @@ -358,11 +370,11 @@ mod test { let digest = "abcd"; const PREPROCESSED: &'static [u8] = b"hello world"; for var in CACHED_ENV_VARS.iter() { - let h1 = hash_key(digest, &args, &[], &PREPROCESSED); + let h1 = hash_key(digest, Language::C, &args, &[], &PREPROCESSED); let vars = vec![(OsString::from(var), OsString::from("something"))]; - let h2 = hash_key(digest, &args, &vars, &PREPROCESSED); + let h2 = hash_key(digest, Language::C, &args, &vars, &PREPROCESSED); let vars = vec![(OsString::from(var), OsString::from("something else"))]; - let h3 = hash_key(digest, &args, &vars, &PREPROCESSED); + let h3 = hash_key(digest, Language::C, &args, &vars, &PREPROCESSED); assert_neq!(h1, h2); assert_neq!(h2, h3); } diff --git a/src/compiler/gcc.rs b/src/compiler/gcc.rs index 95cbb9646..385ed214d 100644 --- a/src/compiler/gcc.rs +++ b/src/compiler/gcc.rs @@ -181,6 +181,7 @@ where let mut multiple_input = false; let mut split_dwarf = false; let mut need_explicit_dep_target = false; + let mut language = None; // Custom iterator to expand `@` arguments which stand for reading a file // and interpreting it as a list of more arguments. @@ -209,8 +210,18 @@ where Some(NeedDepTarget) => need_explicit_dep_target = true, Some(DepTarget) => dep_target = item.arg.get_value().map(OsString::from), Some(PreprocessorArgument) | - Some(PassThrough) | - Some(Language) => {} + Some(PassThrough) => {} + Some(Language) => { + let lang = item.arg.get_value().map(OsString::from); + let lang = lang.as_ref().map(|a| a.to_string_lossy()); + language = match lang.as_ref().map(|a| a.as_ref()) { + Some("c") => Some(Language::C), + Some("c++") => Some(Language::Cxx), + Some("objective-c") => Some(Language::ObjectiveC), + Some("objective-c++") => Some(Language::ObjectiveCxx), + _ => return CompilerArguments::CannotCache("-x"), + }; + } None => { match item.arg { Argument::Raw(ref val) => { @@ -226,11 +237,11 @@ where } let args = match item.data { Some(SplitDwarf) | - Some(PassThrough) | - Some(Language) => Some(&mut common_args), + Some(PassThrough) => Some(&mut common_args), Some(PreprocessorArgument) | Some(NeedDepTarget) => Some(&mut preprocessor_args), Some(DoCompilation) | + Some(Language) | Some(Output) | Some(DepTarget) => None, Some(TooHard) => unreachable!(), @@ -262,18 +273,18 @@ where if multiple_input { return CompilerArguments::CannotCache("multiple input files"); } - let (input, language) = match input_arg { - Some(i) => { - // When compiling from the preprocessed output given as stdin, we need - // to explicitly pass its file type. - match Language::from_file_name(Path::new(&i)) { - Some(l) => (i.to_owned(), l), - None => return CompilerArguments::CannotCache("unknown source language"), - } - } + let input = match input_arg { + Some(i) => i.to_owned(), // We can't cache compilation without an input. None => return CompilerArguments::CannotCache("no input file"), }; + if language == None { + language = Language::from_file_name(Path::new(&input)); + } + let language = match language { + Some(l) => l, + None => return CompilerArguments::CannotCache("unknown source language"), + }; let mut outputs = HashMap::new(); let output = match output_arg { // We can't cache compilation that doesn't go to a file @@ -311,14 +322,22 @@ pub fn preprocess(creator: &T, where T: CommandCreatorSync { trace!("preprocess"); + let language = match parsed_args.language { + Language::C => "c", + Language::Cxx => "c++", + Language::ObjectiveC => "objective-c", + Language::ObjectiveCxx => "objective-c++", + }; let mut cmd = creator.clone().new_command_sync(executable); - cmd.arg("-E") + cmd.arg("-x").arg(language) + .arg("-E") .arg(&parsed_args.input) .args(&parsed_args.preprocessor_args) .args(&parsed_args.common_args) .env_clear() .envs(env_vars.iter().map(|&(ref k, ref v)| (k, v))) .current_dir(cwd); + if log_enabled!(Trace) { trace!("preprocess: {:?}", cmd); } @@ -345,24 +364,24 @@ pub fn compile(creator: &T, } }; + // When reading from stdin the language argument is needed + let language = match parsed_args.language { + Language::C => "cpp-output", + Language::Cxx => "c++-cpp-output", + Language::ObjectiveC => "objective-c-cpp-output", + Language::ObjectiveCxx => "objective-c++-cpp-output", + }; let mut attempt = creator.clone().new_command_sync(executable); - attempt.arg("-c") + attempt.arg("-x").arg(language) + .arg("-c") .arg("-o").arg(&out_file) .args(&parsed_args.common_args) .env_clear() .envs(env_vars.iter().map(|&(ref k, ref v)| (k, v))) .current_dir(&cwd); - // When reading from stdin the language argument is needed - let language = parsed_args.language; let pre = pre.unwrap_or(Box::new(pool.spawn_fn(move || { - let language = match language { - Language::C => "cpp-output", - Language::Cxx => "c++-cpp-output", - Language::ObjectiveC => "objective-c-cpp-output", - Language::ObjectiveCxx => "objective-c++-cpp-output", - }; - let args = vec!("-x".to_owned(), language.to_owned(), "-".to_owned()); + let args = vec!("-".to_owned()); Ok((Some(preprocessor_result.stdout), args, None)) })));