From: Tor Arne Vestbø Date: Thu, 15 Jun 2017 12:40:16 +0000 (+0200) Subject: Don't use cache when building precompiled header with changed deps X-Git-Tag: v3.3.5~21 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d7712b3d22ac5f6e76784bbfe8e6c08d281c7bcd;p=thirdparty%2Fccache.git Don't use cache when building precompiled header with changed deps If one of the included files in a precompiled header is touched, changing only its mtime, clang will produce a fatal error when the precompiled header is then used: file 'foo.h' has been modified since the precompiled header 'foo.pch' was built We need to take this into account when producing precompiled headers, so that we don't pick out stale objects from the cache. This works fine for direct mode, but in preprocess mode we don't have enough information to decide if the object is still valid, so we skip the cache entirely in that mode. --- diff --git a/ccache.c b/ccache.c index 42935e7a8..fd1b4ce1c 100644 --- a/ccache.c +++ b/ccache.c @@ -197,7 +197,7 @@ static char *cpp_stderr; char *stats_file = NULL; // Whether the output is a precompiled header. -static bool output_is_precompiled_header = false; +bool output_is_precompiled_header = false; // Profile generation / usage information. static char *profile_dir = NULL; @@ -1870,6 +1870,16 @@ from_cache(enum fromcache_call_mode mode, bool put_object_in_manifest) return; } + // We can't trust the objects based on running the preprocessor + // when the output is precompiled headers, as the hash does not + // include the mtime of each included header, breaking compilation + // with clang when the precompiled header is used after touching + // one of the included files. + if (output_is_precompiled_header && mode == FROMCACHE_CPP_MODE) { + cc_log("Not using preprocessed cached object for precompiled header"); + return; + } + struct stat st; if (stat(cached_obj, &st) != 0) { cc_log("Object file %s not in cache", cached_obj); diff --git a/ccache.h b/ccache.h index 6dfaa2426..2c5d64ddd 100644 --- a/ccache.h +++ b/ccache.h @@ -238,6 +238,7 @@ void lockfile_release(const char *path); // ccache.c extern time_t time_of_compilation; +extern bool output_is_precompiled_header; void block_signals(void); void unblock_signals(void); bool cc_process_args(struct args *args, struct args **preprocessor_args, diff --git a/manifest.c b/manifest.c index f84bef44b..5cd3ead2a 100644 --- a/manifest.c +++ b/manifest.c @@ -381,6 +381,13 @@ verify_object(struct conf *conf, struct manifest *mf, struct object *obj, return 0; } + // Clang stores the mtime of the included files in the precompiled header, + // and will error out if that header is later used without rebuilding. + if (output_is_precompiled_header && fi->mtime != st->mtime) { + cc_log("Precompiled header includes %s, which has a new mtime", path); + return 0; + } + if (conf->sloppiness & SLOPPY_FILE_STAT_MATCHES) { if (fi->mtime == st->mtime && fi->ctime == st->ctime) { cc_log("mtime/ctime hit for %s", path); diff --git a/test.sh b/test.sh index cda538f67..ce4f9760d 100755 --- a/test.sh +++ b/test.sh @@ -3115,6 +3115,42 @@ pch_suite_clang() { test_failed "pch.gch missing" fi + # ------------------------------------------------------------------------- + TEST "Create .gch, include file mtime changed" + + backdate test.h + cat <pch2.h + #include + #include "test.h" +EOF + + # Make sure time_of_compilation is at least one second larger than the ctime + # of the test.h include, otherwise we might not cache its ctime/mtime. + sleep 1 + + CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c pch2.h + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache hit (preprocessed)' 0 + expect_stat 'cache miss' 1 + + touch test.h + sleep 1 + + CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c pch2.h + expect_stat 'cache hit (direct)' 0 + expect_stat 'cache hit (preprocessed)' 0 + expect_stat 'cache miss' 2 + + $UNCACHED_COMPILE $SYSROOT -c -include pch2.h pch2.c + if [ ! -f pch2.o ]; then + test_failed "pch.o missing" + fi + + CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c pch2.h + expect_stat 'cache hit (direct)' 1 + expect_stat 'cache hit (preprocessed)' 0 + expect_stat 'cache miss' 2 + # ------------------------------------------------------------------------- TEST "Use .gch, no -fpch-preprocess, -include, no sloppiness"