From b881869902690240bd97872d4df2395c436f2806 Mon Sep 17 00:00:00 2001 From: Dimitrios Apostolou Date: Fri, 4 Oct 2024 12:52:40 +0200 Subject: [PATCH] Fix cache collision between object file and precompiled headers When compiling with PCH enabled, it happens that some times object files end up with PCH content, or that .gch files end up with object code. Simplest way to reproduce the problem: $ touch empty.c $ gcc -c -o out1 empty.c $ gcc -x c-header -c -o out2 empty.c $ file out1 out2 out1: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped out2: GCC precompiled header (version 014) for C The two files are different. But if we feed these compilations to sccache, they lead to the same result: $ sccache gcc -c -o out3 empty.c $ sccache gcc -x c-header -c -o out4 empty.c $ file out3 out4 out3: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped out4: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped Same thing is reproducible with c++ compiler and -x c++-header argument. The reason is that the hash string that identifies each command line is the same. With this patch, compilation of C files is always differentiated from compilations of same C-Header files. And compilation of C++ files is always differentiated from compilations of same C++-Header files. Fixes #1851. --- src/compiler/c.rs | 36 ++++++++++++++++++++++++++++++++++++ src/compiler/compiler.rs | 6 ++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/compiler/c.rs b/src/compiler/c.rs index 2badc6f71..be335d9a6 100644 --- a/src/compiler/c.rs +++ b/src/compiler/c.rs @@ -1448,6 +1448,42 @@ mod test { ); } + #[test] + fn test_header_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::CHeader, + &args, + &[], + &[], + PREPROCESSED, + false + ) + ); + } + + #[test] + fn test_plusplus_header_differs() { + let args = ovec!["a", "b", "c"]; + const PREPROCESSED: &[u8] = b"hello world"; + assert_neq!( + hash_key("abcd", Language::Cxx, &args, &[], &[], PREPROCESSED, true), + hash_key( + "abcd", + Language::CxxHeader, + &args, + &[], + &[], + PREPROCESSED, + true + ) + ); + } + #[test] fn test_hash_key_executable_contents_differs() { let args = ovec!["a", "b", "c"]; diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index a37d20775..812d34087 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -146,8 +146,10 @@ impl Language { pub fn as_str(self) -> &'static str { match self { - Language::C | Language::CHeader => "c", - Language::Cxx | Language::CxxHeader => "c++", + Language::C => "c", + Language::CHeader => "cHeader", + Language::Cxx => "c++", + Language::CxxHeader => "c++Header", Language::GenericHeader => "c/c++", Language::ObjectiveC => "objc", Language::ObjectiveCxx => "objc++",