diff --git a/src/compiler/c.rs b/src/compiler/c.rs index 4193b1c613..02ff83186f 100644 --- a/src/compiler/c.rs +++ b/src/compiler/c.rs @@ -166,6 +166,8 @@ pub enum CCompilerKind { pub trait CCompilerImpl: Clone + fmt::Debug + Send + 'static { /// Return the kind of compiler. fn kind(&self) -> CCompilerKind; + /// Return true iff this is g++ or clang++. + fn plusplus(&self) -> bool; /// Determine whether `arguments` are supported by this compiler. fn parse_arguments( &self, @@ -344,6 +346,7 @@ where &extra_hashes, &env_vars, &preprocessor_result.stdout, + compiler.plusplus(), ) }; // A compiler binary may be a symlink to another and so has the same digest, but that means @@ -621,7 +624,7 @@ impl pkg::ToolchainPackager for CToolchainPackager { } /// The cache is versioned by the inputs to `hash_key`. -pub const CACHE_VERSION: &[u8] = b"9"; +pub const CACHE_VERSION: &[u8] = b"10"; lazy_static! { /// Environment variables that are factored into the cache key. @@ -639,6 +642,7 @@ pub fn hash_key( extra_hashes: &[String], env_vars: &[(OsString, OsString)], preprocessor_output: &[u8], + plusplus: bool, ) -> String { // If you change any of the inputs to the hash, you should change `CACHE_VERSION`. let mut m = Digest::new(); @@ -660,6 +664,9 @@ pub fn hash_key( } } m.update(preprocessor_output); + // clang and clang++ have different behavior despite being byte-for-byte identical binaries, so + // we have to incorporate that into the hash as well. + m.update(&[plusplus as u8]); m.finish() } @@ -667,13 +674,33 @@ pub fn hash_key( mod test { use super::*; + #[test] + fn test_same_content() { + let args = ovec!["a", "b", "c"]; + const PREPROCESSED: &[u8] = b"hello world"; + assert_eq!( + hash_key("abcd", Language::C, &args, &[], &[], &PREPROCESSED, false), + hash_key("abcd", Language::C, &args, &[], &[], &PREPROCESSED, false) + ); + } + + #[test] + fn test_plusplus_differs() { + let args = ovec!["a", "b", "c"]; + const PREPROCESSED: &[u8] = b"hello world"; + assert_neq!( + hash_key("abcd", Language::C, &args, &[], &[], &PREPROCESSED, false), + hash_key("abcd", Language::C, &args, &[], &[], &PREPROCESSED, true) + ); + } + #[test] fn test_hash_key_executable_contents_differs() { let args = ovec!["a", "b", "c"]; const PREPROCESSED: &[u8] = b"hello world"; assert_neq!( - hash_key("abcd", Language::C, &args, &[], &[], &PREPROCESSED), - hash_key("wxyz", Language::C, &args, &[], &[], &PREPROCESSED) + hash_key("abcd", Language::C, &args, &[], &[], &PREPROCESSED, false), + hash_key("wxyz", Language::C, &args, &[], &[], &PREPROCESSED, false) ); } @@ -686,18 +713,18 @@ mod test { let a = ovec!["a"]; const PREPROCESSED: &[u8] = b"hello world"; assert_neq!( - hash_key(digest, Language::C, &abc, &[], &[], &PREPROCESSED), - hash_key(digest, Language::C, &xyz, &[], &[], &PREPROCESSED) + hash_key(digest, Language::C, &abc, &[], &[], &PREPROCESSED, false), + hash_key(digest, Language::C, &xyz, &[], &[], &PREPROCESSED, false) ); assert_neq!( - hash_key(digest, Language::C, &abc, &[], &[], &PREPROCESSED), - hash_key(digest, Language::C, &ab, &[], &[], &PREPROCESSED) + hash_key(digest, Language::C, &abc, &[], &[], &PREPROCESSED, false), + hash_key(digest, Language::C, &ab, &[], &[], &PREPROCESSED, false) ); assert_neq!( - hash_key(digest, Language::C, &abc, &[], &[], &PREPROCESSED), - hash_key(digest, Language::C, &a, &[], &[], &PREPROCESSED) + hash_key(digest, Language::C, &abc, &[], &[], &PREPROCESSED, false), + hash_key(digest, Language::C, &a, &[], &[], &PREPROCESSED, false) ); } @@ -705,8 +732,16 @@ mod test { fn test_hash_key_preprocessed_content_differs() { let args = ovec!["a", "b", "c"]; assert_neq!( - hash_key("abcd", Language::C, &args, &[], &[], &b"hello world"[..]), - hash_key("abcd", Language::C, &args, &[], &[], &b"goodbye"[..]) + hash_key( + "abcd", + Language::C, + &args, + &[], + &[], + &b"hello world"[..], + false + ), + hash_key("abcd", Language::C, &args, &[], &[], &b"goodbye"[..], false) ); } @@ -716,11 +751,11 @@ mod test { let digest = "abcd"; const PREPROCESSED: &[u8] = b"hello world"; for var in CACHED_ENV_VARS.iter() { - let h1 = hash_key(digest, Language::C, &args, &[], &[], &PREPROCESSED); + let h1 = hash_key(digest, Language::C, &args, &[], &[], &PREPROCESSED, false); let vars = vec![(OsString::from(var), OsString::from("something"))]; - let h2 = hash_key(digest, Language::C, &args, &[], &vars, &PREPROCESSED); + let h2 = hash_key(digest, Language::C, &args, &[], &vars, &PREPROCESSED, false); let vars = vec![(OsString::from(var), OsString::from("something else"))]; - let h3 = hash_key(digest, Language::C, &args, &[], &vars, &PREPROCESSED); + let h3 = hash_key(digest, Language::C, &args, &[], &vars, &PREPROCESSED, false); assert_neq!(h1, h2); assert_neq!(h2, h3); } @@ -734,8 +769,16 @@ mod test { let extra_data = stringvec!["hello", "world"]; assert_neq!( - hash_key(digest, Language::C, &args, &extra_data, &[], &PREPROCESSED), - hash_key(digest, Language::C, &args, &[], &[], &PREPROCESSED) + hash_key( + digest, + Language::C, + &args, + &extra_data, + &[], + &PREPROCESSED, + false + ), + hash_key(digest, Language::C, &args, &[], &[], &PREPROCESSED, false) ); } } diff --git a/src/compiler/clang.rs b/src/compiler/clang.rs index 6331b6f3aa..550e9c9e9a 100644 --- a/src/compiler/clang.rs +++ b/src/compiler/clang.rs @@ -30,14 +30,20 @@ use std::process; use crate::errors::*; -/// A unit struct on which to implement `CCompilerImpl`. +/// A struct on which to implement `CCompilerImpl`. #[derive(Clone, Debug)] -pub struct Clang; +pub struct Clang { + /// true iff this is clang++. + pub clangplusplus: bool, +} impl CCompilerImpl for Clang { fn kind(&self) -> CCompilerKind { CCompilerKind::Clang } + fn plusplus(&self) -> bool { + self.clangplusplus + } fn parse_arguments( &self, arguments: &[OsString], @@ -130,7 +136,10 @@ mod test { fn parse_arguments_(arguments: Vec) -> CompilerArguments { let arguments = arguments.iter().map(OsString::from).collect::>(); - Clang.parse_arguments(&arguments, ".".as_ref()) + Clang { + clangplusplus: false, + } + .parse_arguments(&arguments, ".".as_ref()) } macro_rules! parses { diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 383d0cffe5..13f3d5c5c2 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -970,8 +970,12 @@ nvcc msvc-clang #elif defined(_MSC_VER) msvc +#elif defined(__clang__) && defined(__cplusplus) +clang++ #elif defined(__clang__) clang +#elif defined(__GNUC__) && defined(__cplusplus) +g++ #elif defined(__GNUC__) gcc #elif defined(__DCC__) @@ -1008,11 +1012,30 @@ diab for line in stdout.lines() { //TODO: do something smarter here. match line { + "clang++" => { + debug!("Found clang++"); + return Box::new( + CCompiler::new( + Clang { + clangplusplus: true, + }, + executable, + &pool, + ) + .map(|c| Box::new(c) as Box>), + ); + } "clang" => { debug!("Found clang"); return Box::new( - CCompiler::new(Clang, executable, &pool) - .map(|c| Box::new(c) as Box>), + CCompiler::new( + Clang { + clangplusplus: false, + }, + executable, + &pool, + ) + .map(|c| Box::new(c) as Box>), ); } "diab" => { @@ -1022,10 +1045,17 @@ diab .map(|c| Box::new(c) as Box>), ); } + "g++" => { + debug!("Found G++"); + return Box::new( + CCompiler::new(GCC { gplusplus: true }, executable, &pool) + .map(|c| Box::new(c) as Box>), + ); + } "gcc" => { debug!("Found GCC"); return Box::new( - CCompiler::new(GCC, executable, &pool) + CCompiler::new(GCC { gplusplus: false }, executable, &pool) .map(|c| Box::new(c) as Box>), ); } diff --git a/src/compiler/diab.rs b/src/compiler/diab.rs index 00c30198c9..ae02bd522e 100644 --- a/src/compiler/diab.rs +++ b/src/compiler/diab.rs @@ -38,6 +38,9 @@ impl CCompilerImpl for Diab { fn kind(&self) -> CCompilerKind { CCompilerKind::Diab } + fn plusplus(&self) -> bool { + false + } fn parse_arguments( &self, arguments: &[OsString], diff --git a/src/compiler/gcc.rs b/src/compiler/gcc.rs index eec1f9a9ec..32c66c9970 100644 --- a/src/compiler/gcc.rs +++ b/src/compiler/gcc.rs @@ -28,14 +28,19 @@ use std::process; use crate::errors::*; -/// A unit struct on which to implement `CCompilerImpl`. +/// A struct on which to implement `CCompilerImpl`. #[derive(Clone, Debug)] -pub struct GCC; +pub struct GCC { + pub gplusplus: bool, +} impl CCompilerImpl for GCC { fn kind(&self) -> CCompilerKind { CCompilerKind::GCC } + fn plusplus(&self) -> bool { + self.gplusplus + } fn parse_arguments( &self, arguments: &[OsString], diff --git a/src/compiler/msvc.rs b/src/compiler/msvc.rs index b822cf4690..89dcb2f0b7 100644 --- a/src/compiler/msvc.rs +++ b/src/compiler/msvc.rs @@ -47,6 +47,9 @@ impl CCompilerImpl for MSVC { fn kind(&self) -> CCompilerKind { CCompilerKind::MSVC } + fn plusplus(&self) -> bool { + false + } fn parse_arguments( &self, arguments: &[OsString], diff --git a/src/compiler/nvcc.rs b/src/compiler/nvcc.rs index b6b64567c8..dc0a7cf15d 100644 --- a/src/compiler/nvcc.rs +++ b/src/compiler/nvcc.rs @@ -39,6 +39,9 @@ impl CCompilerImpl for NVCC { fn kind(&self) -> CCompilerKind { CCompilerKind::NVCC } + fn plusplus(&self) -> bool { + false + } fn parse_arguments( &self, arguments: &[OsString],