// Clang's -include-pch or -include-pth).
bool using_precompiled_header = false;
+ // Whether Clang is instructed not to include timestamps in the precompiled
+ // header it generates.
+ bool fno_pch_timestamp = false;
+
// Files referenced by -fsanitize-blacklist options.
std::vector<std::string> sanitize_blacklists;
detect_pch(Context& ctx,
const std::string& option,
const std::string& arg,
+ bool is_cc1_option,
bool* found_pch)
{
assert(found_pch);
// Try to be smart about detecting precompiled headers.
+ // If the option is an option for Clang (is_cc1_option), don't accept
+ // anything just because it has a corresponding precompiled header,
+ // because Clang doesn't behave that way either.
std::string pch_file;
if (option == "-include-pch" || option == "-include-pth") {
if (Stat::stat(arg)) {
cc_log("Detected use of precompiled header: %s", arg.c_str());
pch_file = arg;
}
- } else {
+ } else if (!is_cc1_option) {
for (const auto& extension : {".gch", ".pch", ".pth"}) {
std::string path = arg + extension;
if (Stat::stat(path)) {
return nullopt;
}
+ // Some arguments that clang passes directly to cc1 (related to precompiled
+ // headers) need the usual ccache handling. In those cases, the -Xclang
+ // prefix is skipped and the cc1 argument is handled instead.
+ if (args[i] == "-Xclang" && i < args.size() - 1
+ && (args[i + 1] == "-emit-pch" || args[i + 1] == "-emit-pth"
+ || args[i + 1] == "-include-pch" || args[i + 1] == "-include-pth"
+ || args[i + 1] == "-fno-pch-timestamp")) {
+ if (compopt_affects_comp(args[i + 1])) {
+ state.compiler_only_args.push_back(args[i]);
+ } else if (compopt_affects_cpp(args[i + 1])) {
+ state.cpp_args.push_back(args[i]);
+ } else {
+ state.common_args.push_back(args[i]);
+ }
+ ++i;
+ }
+
// Handle options that should not be passed to the preprocessor.
if (compopt_affects_comp(args[i])) {
state.compiler_only_args.push_back(args[i]);
return nullopt;
}
- if (args[i] == "-fpch-preprocess" || args[i] == "-emit-pch"
- || args[i] == "-emit-pth") {
- state.found_fpch_preprocess = true;
- }
-
// Modules are handled on demand as necessary in the background, so there is
// no need to cache them, they can in practice be ignored. All that is needed
// is to correctly depend also on module.modulemap files, and those are
return nullopt;
}
+ if (args[i] == "-fno-pch-timestamp") {
+ args_info.fno_pch_timestamp = true;
+ state.common_args.push_back(args[i]);
+ return nullopt;
+ }
+
+ if (args[i] == "-fpch-preprocess") {
+ state.found_fpch_preprocess = true;
+ state.common_args.push_back(args[i]);
+ return nullopt;
+ }
+
if (config.sloppiness() & SLOPPY_CLANG_INDEX_STORE
&& args[i] == "-index-store-path") {
// Xcode 9 or later calls Clang with this option. The given path includes a
return STATS_ARGS;
}
- if (!detect_pch(ctx, args[i], args[i + 1], &state.found_pch)) {
+ // In the -Xclang -include-(pch/pth) -Xclang <path> case, the path is one
+ // index further behind.
+ int next = 1;
+ if (args[i + 1] == "-Xclang" && i + 2 < args.size()) {
+ next = 2;
+ }
+
+ if (!detect_pch(
+ ctx, args[i], args[i + next], next == 2, &state.found_pch)) {
return STATS_ARGS;
}
- std::string relpath = Util::make_relative_path(ctx, args[i + 1]);
- if (compopt_affects_cpp(args[i])) {
- state.cpp_args.push_back(args[i]);
- state.cpp_args.push_back(relpath);
- } else {
- state.common_args.push_back(args[i]);
- state.common_args.push_back(relpath);
+ std::string relpath = Util::make_relative_path(ctx, args[i + next]);
+ auto& dest_args =
+ compopt_affects_cpp(args[i]) ? state.cpp_args : state.common_args;
+ dest_args.push_back(args[i]);
+ if (next == 2) {
+ dest_args.push_back(args[i + 1]);
}
+ dest_args.push_back(relpath);
- i++;
+ i += next;
return nullopt;
}
}
args_info.output_is_precompiled_header =
- args_info.actual_language.find("-header") != std::string::npos;
+ args_info.actual_language.find("-header") != std::string::npos
+ || is_precompiled_header(args_info.output_obj.c_str());
if (args_info.output_is_precompiled_header
&& !(config.sloppiness() & SLOPPY_PCH_DEFINES)) {
if ((ctx.guessed_compiler == GuessedCompiler::clang
|| ctx.guessed_compiler == GuessedCompiler::unknown)
&& ctx.args_info.output_is_precompiled_header
- && mode == FROMCACHE_CPP_MODE) {
+ && !ctx.args_info.fno_pch_timestamp && mode == FROMCACHE_CPP_MODE) {
cc_log("Not considering cached precompiled header in preprocessor mode");
return nullopt;
}
{"-bind_at_load", AFFECTS_COMP},
{"-bundle", AFFECTS_COMP},
{"-ccbin", AFFECTS_CPP | TAKES_ARG}, // nvcc
+ {"-emit-pch", AFFECTS_COMP}, // Clang
+ {"-emit-pth", AFFECTS_COMP}, // Clang
{"-fno-working-directory", AFFECTS_CPP},
{"-fplugin=libcc1plugin", TOO_HARD}, // interaction with GDB
{"-frepo", TOO_HARD},
{"-imultilib", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
{"-include", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
{"-include-pch", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-include-pth", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
{"-install_name", TAKES_ARG}, // Darwin linker option
{"-iprefix", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
{"-iquote", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
// and will error out if that header is later used without rebuilding.
if ((ctx.guessed_compiler == GuessedCompiler::clang
|| ctx.guessed_compiler == GuessedCompiler::unknown)
- && ctx.args_info.output_is_precompiled_header && fi.mtime != fs.mtime) {
+ && ctx.args_info.output_is_precompiled_header
+ && !ctx.args_info.fno_pch_timestamp && fi.mtime != fs.mtime) {
cc_log("Precompiled header includes %s, which has a new mtime",
path.c_str());
return false;
pch_suite_clang() {
# -------------------------------------------------------------------------
- TEST "Create .gch, include file mtime changed"
+ TEST "Create .pch, include file mtime changed"
backdate test.h
cat <<EOF >pch2.h
expect_stat 'cache hit (direct)' 0
expect_stat 'cache hit (preprocessed)' 2
expect_stat 'cache miss' 2
+
+ # -------------------------------------------------------------------------
+ TEST "Create .pch with -Xclang options"
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines" $CCACHE_COMPILE $SYSROOT -Xclang -emit-pch -o pch.h.pch -c pch.h
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ rm pch.h.pch
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines" $CCACHE_COMPILE $SYSROOT -Xclang -emit-pch -o pch.h.pch -c pch.h
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+ expect_file_exists pch.h.pch
+
+ echo '#include <string.h> /*change pch*/' >>pch.h
+ backdate pch.h
+ rm pch.h.pch
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines" $CCACHE_COMPILE $SYSROOT -Xclang -emit-pch -o pch.h.pch -c pch.h
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+ expect_file_exists pch.h.pch
+
+ # -------------------------------------------------------------------------
+ TEST "Use .pch the with -Xclang options"
+
+ $REAL_COMPILER $SYSROOT -Xclang -emit-pch -o pch.h.pch -c pch.h
+ backdate pch.h.pch
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -Xclang -include-pch -Xclang pch.h.pch -Xclang -include -Xclang pch.h -c pch.c
+ expect_stat 'cache hit (direct)' 0
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -Xclang -include-pch -Xclang pch.h.pch -Xclang -include -Xclang pch.h -c pch.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 1
+
+ echo '#include <string.h> /*change pch*/' >>pch.h
+ backdate pch.h
+ $REAL_COMPILER $SYSROOT -Xclang -emit-pch -o pch.h.pch -c pch.h
+ backdate pch.h.pch
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -Xclang -include-pch -Xclang pch.h.pch -Xclang -include -Xclang pch.h -c pch.c
+ expect_stat 'cache hit (direct)' 1
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
+
+ CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS time_macros" $CCACHE_COMPILE $SYSROOT -Xclang -include-pch -Xclang pch.h.pch -Xclang -include -Xclang pch.h -c pch.c
+ expect_stat 'cache hit (direct)' 2
+ expect_stat 'cache hit (preprocessed)' 0
+ expect_stat 'cache miss' 2
}