]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
feat: Improve handling of dependency files
authorJoel Rosdahl <joel@rosdahl.net>
Thu, 28 Jul 2022 08:58:05 +0000 (10:58 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Thu, 28 Jul 2022 08:58:05 +0000 (10:58 +0200)
- Cache entries are now shared for different -MT/-MQ options. This is
  implemented by (on a cache hit) rewriting the stored dependency file
  data to have the correct dependency target before writing it to the
  destination. Closes #359.
- An intentional side effect of the above is that the correct dependency
  target will be produced even when base_dir/CCACHE_BASEDIR is used -
  the dependency target will still be an absolute path. Fixes #1042.
- Buggy support for GCC-specific environment variables
  DEPENDENCIES_OUTPUT and SUNPRO_DEPENDENCIES has been removed. When one
  of those variables was set, ccache used to store and fetch the content
  just as if -MMD or -MD were used. This is however incorrect since GCC
  *appends* to the destination file instead of (like -MMD/-MD)
  *rewriting* it. Since there is no way for ccache to know what the
  compiler appended to the dependency file, we simply can't support it.
  Reverts #349.

15 files changed:
src/ArgsInfo.hpp
src/Depfile.cpp
src/Depfile.hpp
src/ResultRetriever.cpp
src/ResultRetriever.hpp
src/argprocessing.cpp
src/ccache.cpp
test/CMakeLists.txt
test/run
test/suites/base.bash
test/suites/basedir.bash
test/suites/direct.bash
test/suites/direct_gcc.bash [deleted file]
unittest/test_Depfile.cpp
unittest/test_argprocessing.cpp

index 343fedc6effe7ca30b9a722bf1a4a030b25d3ea1..94a7fe428ebc86eb6a401ddffc7cf6da774acf16 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2020-2021 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2022 Joel Rosdahl and other contributors
 //
 // See doc/AUTHORS.adoc for a complete list of contributors.
 //
@@ -20,6 +20,7 @@
 
 #include "Args.hpp"
 
+#include <optional>
 #include <string>
 #include <vector>
 
@@ -27,6 +28,9 @@
 struct ArgsInfo
 {
   // The source file path.
+  std::string orig_input_file;
+
+  // The source file path, potentially rewritten into relative.
   std::string input_file;
 
   // The source file path run through Util::normalize_concrete_absolute_path.
@@ -38,9 +42,13 @@ struct ArgsInfo
   bool expect_output_obj = true;
 
   // The output file being compiled to.
+  std::string orig_output_obj;
+
+  // The output file being compiled to, potentially rewritten into relative.
   std::string output_obj;
 
-  // The path to the dependency file (implicit or specified with -MF).
+  // The path to the dependency file (implicit or specified with -MFdepfile,
+  // -Wp,-MD,depfile or -Wp,-MMD,depfile).
   std::string output_dep;
 
   // The path to the stack usage (implicit when using -fstack-usage).
@@ -64,11 +72,9 @@ struct ArgsInfo
   // Is the compiler being asked to output dependencies?
   bool generating_dependencies = false;
 
-  // Seen -MD or -MMD?
-  bool seen_MD_MMD = false;
-
-  // Is the dependency makefile target name specified with -MT or -MQ?
-  bool dependency_target_specified = false;
+  // The dependency target in the dependency file (the object file unless
+  // overridden via e.g. -MT or -MQ).
+  std::optional<std::string> dependency_target;
 
   // Is the compiler being asked to output coverage?
   bool generating_coverage = false;
index 7ceccc7e77dcaa5ca4ce3c3a171b01a190f0fde4..14ce863087cd5558b4db1d5fdb9c1fd26d56daae 100644 (file)
@@ -60,7 +60,7 @@ escape_filename(std::string_view filename)
 }
 
 std::optional<std::string>
-rewrite_paths(const Context& ctx, const std::string& file_content)
+rewrite_source_paths(const Context& ctx, const std::string& file_content)
 {
   ASSERT(!ctx.config.base_dir().empty());
   ASSERT(ctx.has_absolute_include_headers);
@@ -74,6 +74,8 @@ rewrite_paths(const Context& ctx, const std::string& file_content)
   adjusted_file_content.reserve(file_content.size());
 
   bool content_rewritten = false;
+  bool seen_target_token = false;
+
   using util::Tokenizer;
   for (const auto line : Tokenizer(file_content,
                                    "\n",
@@ -82,13 +84,15 @@ rewrite_paths(const Context& ctx, const std::string& file_content)
     const auto tokens = Util::split_into_views(line, " \t");
     for (size_t i = 0; i < tokens.size(); ++i) {
       DEBUG_ASSERT(!line.empty()); // line.empty() -> no tokens
+      DEBUG_ASSERT(!tokens[i].empty());
+
       if (i > 0 || line[0] == ' ' || line[0] == '\t') {
         adjusted_file_content.push_back(' ');
       }
 
       const auto& token = tokens[i];
       bool token_rewritten = false;
-      if (util::is_absolute_path(token)) {
+      if (seen_target_token && util::is_absolute_path(token)) {
         const auto new_path = Util::make_relative_path(ctx, token);
         if (new_path != token) {
           adjusted_file_content.append(new_path);
@@ -100,6 +104,10 @@ rewrite_paths(const Context& ctx, const std::string& file_content)
       } else {
         adjusted_file_content.append(token.begin(), token.end());
       }
+
+      if (tokens[i].back() == ':') {
+        seen_target_token = true;
+      }
     }
   }
 
@@ -132,7 +140,7 @@ make_paths_relative_in_output_dep(const Context& ctx)
     LOG("Cannot open dependency file {}: {}", output_dep, e.what());
     return;
   }
-  const auto new_content = rewrite_paths(ctx, file_content);
+  const auto new_content = rewrite_source_paths(ctx, file_content);
   if (new_content) {
     Util::write_file(output_dep, *new_content);
   } else {
index fc453c310f1656777a9bae7fb82552990ad6fc0c..1257462646096a2f0b6c79721216f28aa3c23c69 100644 (file)
@@ -31,9 +31,12 @@ class Hash;
 namespace Depfile {
 
 std::string escape_filename(std::string_view filename);
-std::optional<std::string> rewrite_paths(const Context& ctx,
-                                         const std::string& file_content);
+
+std::optional<std::string>
+rewrite_source_paths(const Context& ctx, const std::string& file_content);
+
 void make_paths_relative_in_output_dep(const Context& ctx);
+
 std::vector<std::string> tokenize(std::string_view file_content);
 
 } // namespace Depfile
index 6e84c82bc6746024a16e9f04a11e6a48d4225fed..c3f0f51cf76c2c3b0279c2311014e63cdb9d36a8 100644 (file)
@@ -37,9 +37,7 @@
 
 using Result::FileType;
 
-ResultRetriever::ResultRetriever(Context& ctx, bool rewrite_dependency_target)
-  : m_ctx(ctx),
-    m_rewrite_dependency_target(rewrite_dependency_target)
+ResultRetriever::ResultRetriever(Context& ctx) : m_ctx(ctx)
 {
 }
 
@@ -179,15 +177,17 @@ ResultRetriever::on_entry_end()
 void
 ResultRetriever::write_dependency_file()
 {
+  ASSERT(m_ctx.args_info.dependency_target);
+  const auto& dep_target = *m_ctx.args_info.dependency_target;
+
   try {
     size_t start_pos = 0;
-    if (m_rewrite_dependency_target) {
-      size_t colon_pos = m_dest_data.find(':');
-      if (colon_pos != std::string::npos) {
-        const auto escaped_output_obj =
-          Depfile::escape_filename(m_ctx.args_info.output_obj);
-        Util::write_fd(
-          *m_dest_fd, escaped_output_obj.data(), escaped_output_obj.length());
+    const size_t colon_pos = m_dest_data.find(": ");
+    if (colon_pos != std::string::npos) {
+      const auto obj_in_dep_file =
+        std::string_view(m_dest_data).substr(0, colon_pos);
+      if (obj_in_dep_file != dep_target) {
+        Util::write_fd(*m_dest_fd, dep_target.data(), dep_target.length());
         start_pos = colon_pos;
       }
     }
index bdd4f893bb5b462cd4c2180a9d7a9e63450de183..a114698eb8e52cac5be03b0a7b203b8eb99f16eb 100644 (file)
@@ -34,7 +34,7 @@ public:
     using core::Error::Error;
   };
 
-  ResultRetriever(Context& ctx, bool rewrite_dependency_target);
+  ResultRetriever(Context& ctx);
 
   void on_entry_start(uint8_t entry_number,
                       Result::FileType file_type,
@@ -55,9 +55,5 @@ private:
   // a chunk boundary).
   std::string m_dest_data;
 
-  // Whether to rewrite the first part of the dependency file data to the
-  // destination object file.
-  const bool m_rewrite_dependency_target;
-
   void write_dependency_file();
 };
index 08c41e91f3f8b9d98ef238f99bddad5e0da426cd..daf3b5ff023e4595d9999357edc4077547093f66 100644 (file)
@@ -25,6 +25,7 @@
 #include "fmtmacros.hpp"
 #include "language.hpp"
 
+#include <Depfile.hpp>
 #include <core/wincompat.hpp>
 #include <util/string.hpp>
 
@@ -40,6 +41,17 @@ namespace {
 
 enum class ColorDiagnostics : int8_t { never, automatic, always };
 
+// The dependency target in the dependency file is taken from the highest
+// priority source.
+enum class OutputDepOrigin : uint8_t {
+  // Not set
+  none = 0,
+  // From -MF target
+  mf = 1,
+  // From -Wp,-MD,target or -Wp,-MMD,target
+  wp = 2
+};
+
 struct ArgumentProcessingState
 {
   bool found_c_opt = false;
@@ -54,16 +66,15 @@ struct ArgumentProcessingState
   bool found_directives_only = false;
   bool found_rewrite_includes = false;
   std::optional<std::string> found_xarch_arch;
+  bool found_mf_opt = false;
+  bool found_wp_md_or_mmd_opt = false;
+  bool found_md_or_mmd_opt = false;
 
   std::string explicit_language;    // As specified with -x.
   std::string input_charset_option; // -finput-charset=...
 
-  // Is the dependency makefile name overridden with -MF?
-  bool dependency_filename_specified = false;
-
-  // Is the dependency target name implicitly specified using
-  // DEPENDENCIES_OUTPUT or SUNPRO_DEPENDENCIES?
-  bool dependency_implicit_target_specified = false;
+  // Is the dependency file set via -Wp,-M[M]D,target or -MFtarget?
+  OutputDepOrigin output_dep_origin = OutputDepOrigin::none;
 
   // Is the compiler being asked to output debug info on level 3?
   bool generating_debuginfo_level_3 = false;
@@ -461,8 +472,7 @@ process_option_arg(const Context& ctx,
 
   // MSVC -Fo with no space.
   if (util::starts_with(args[i], "-Fo") && config.is_compiler_group_msvc()) {
-    args_info.output_obj =
-      Util::make_relative_path(ctx, std::string_view(args[i]).substr(3));
+    args_info.output_obj = args[i].substr(3);
     return Statistic::none;
   }
 
@@ -517,7 +527,7 @@ process_option_arg(const Context& ctx,
       LOG("Missing argument to {}", args[i]);
       return Statistic::bad_compiler_arguments;
     }
-    args_info.output_obj = Util::make_relative_path(ctx, args[i + 1]);
+    args_info.output_obj = args[i + 1];
     i++;
     return Statistic::none;
   }
@@ -529,8 +539,7 @@ process_option_arg(const Context& ctx,
   if (util::starts_with(args[i], "-o")
       && config.compiler_type() != CompilerType::nvcc
       && config.compiler_type() != CompilerType::msvc) {
-    args_info.output_obj =
-      Util::make_relative_path(ctx, std::string_view(args[i]).substr(2));
+    args_info.output_obj = args[i].substr(2);
     return Statistic::none;
   }
 
@@ -580,14 +589,14 @@ process_option_arg(const Context& ctx,
   // with gcc -E, when the output file is not specified.
   if ((args[i] == "-MD" || args[i] == "-MMD")
       && !config.is_compiler_group_msvc()) {
+    state.found_md_or_mmd_opt = true;
     args_info.generating_dependencies = true;
-    args_info.seen_MD_MMD = true;
     state.dep_args.push_back(args[i]);
     return Statistic::none;
   }
 
   if (util::starts_with(args[i], "-MF")) {
-    state.dependency_filename_specified = true;
+    state.found_mf_opt = true;
 
     std::string dep_file;
     bool separate_argument = (args[i].size() == 3);
@@ -603,7 +612,11 @@ process_option_arg(const Context& ctx,
       // -MFarg or -MF=arg (EDG-based compilers)
       dep_file = args[i].substr(args[i][3] == '=' ? 4 : 3);
     }
-    args_info.output_dep = Util::make_relative_path(ctx, dep_file);
+
+    if (state.output_dep_origin <= OutputDepOrigin::mf) {
+      state.output_dep_origin = OutputDepOrigin::mf;
+      args_info.output_dep = Util::make_relative_path(ctx, dep_file);
+    }
     // Keep the format of the args the same.
     if (separate_argument) {
       state.dep_args.push_back("-MF");
@@ -616,8 +629,9 @@ process_option_arg(const Context& ctx,
 
   if ((util::starts_with(args[i], "-MQ") || util::starts_with(args[i], "-MT"))
       && !config.is_compiler_group_msvc()) {
-    args_info.dependency_target_specified = true;
+    const bool is_mq = args[i][2] == 'Q';
 
+    std::string_view dep_target;
     if (args[i].size() == 3) {
       // -MQ arg or -MT arg
       if (i == args.size() - 1) {
@@ -625,15 +639,25 @@ process_option_arg(const Context& ctx,
         return Statistic::bad_compiler_arguments;
       }
       state.dep_args.push_back(args[i]);
-      std::string relpath = Util::make_relative_path(ctx, args[i + 1]);
-      state.dep_args.push_back(relpath);
+      state.dep_args.push_back(args[i + 1]);
+      dep_target = args[i + 1];
       i++;
     } else {
-      auto arg_opt = std::string_view(args[i]).substr(0, 3);
-      auto option = std::string_view(args[i]).substr(3);
-      auto relpath = Util::make_relative_path(ctx, option);
-      state.dep_args.push_back(FMT("{}{}", arg_opt, relpath));
+      // -MQarg or -MTarg
+      const std::string_view arg_view(args[i]);
+      const auto arg_opt = arg_view.substr(0, 3);
+      dep_target = arg_view.substr(3);
+      state.dep_args.push_back(FMT("{}{}", arg_opt, dep_target));
     }
+
+    if (args_info.dependency_target) {
+      args_info.dependency_target->push_back(' ');
+    } else {
+      args_info.dependency_target = "";
+    }
+    *args_info.dependency_target +=
+      is_mq ? Depfile::escape_filename(dep_target) : dep_target;
+
     return Statistic::none;
   }
 
@@ -757,18 +781,22 @@ process_option_arg(const Context& ctx,
       return Statistic::unsupported_compiler_option;
     } else if (util::starts_with(args[i], "-Wp,-MD,")
                && args[i].find(',', 8) == std::string::npos) {
+      state.found_wp_md_or_mmd_opt = true;
       args_info.generating_dependencies = true;
-      state.dependency_filename_specified = true;
-      args_info.output_dep =
-        Util::make_relative_path(ctx, std::string_view(args[i]).substr(8));
+      if (state.output_dep_origin <= OutputDepOrigin::wp) {
+        state.output_dep_origin = OutputDepOrigin::wp;
+        args_info.output_dep = args[i].substr(8);
+      }
       state.dep_args.push_back(args[i]);
       return Statistic::none;
     } else if (util::starts_with(args[i], "-Wp,-MMD,")
                && args[i].find(',', 9) == std::string::npos) {
+      state.found_wp_md_or_mmd_opt = true;
       args_info.generating_dependencies = true;
-      state.dependency_filename_specified = true;
-      args_info.output_dep =
-        Util::make_relative_path(ctx, std::string_view(args[i]).substr(9));
+      if (state.output_dep_origin <= OutputDepOrigin::wp) {
+        state.output_dep_origin = OutputDepOrigin::wp;
+        args_info.output_dep = args[i].substr(9);
+      }
       state.dep_args.push_back(args[i]);
       return Statistic::none;
     } else if (util::starts_with(args[i], "-Wp,-D")
@@ -782,7 +810,6 @@ process_option_arg(const Context& ctx,
                    && (args[i][6] == 'F' || args[i][6] == 'Q'
                        || args[i][6] == 'T')
                    && args[i].find(',', 8) == std::string::npos)) {
-      // TODO: Make argument to MF/MQ/MT relative.
       state.dep_args.push_back(args[i]);
       return Statistic::none;
     } else if (config.direct_mode()) {
@@ -1054,6 +1081,7 @@ process_arg(const Context& ctx,
   }
 
   // Rewrite to relative to increase hit rate.
+  args_info.orig_input_file = args[i];
   args_info.input_file = Util::make_relative_path(ctx, args[i]);
   args_info.normalized_input_file =
     Util::normalize_concrete_absolute_path(args_info.input_file);
@@ -1061,60 +1089,10 @@ process_arg(const Context& ctx,
   return Statistic::none;
 }
 
-void
-handle_dependency_environment_variables(Context& ctx,
-                                        ArgumentProcessingState& state)
+const char*
+get_default_object_file_extension(const Config& config)
 {
-  ArgsInfo& args_info = ctx.args_info;
-
-  // See <http://gcc.gnu.org/onlinedocs/cpp/Environment-Variables.html>.
-  // Contrary to what the documentation seems to imply the compiler still
-  // creates object files with these defined (confirmed with GCC 8.2.1), i.e.
-  // they work as -MMD/-MD, not -MM/-M. These environment variables do nothing
-  // on Clang.
-  const char* dependencies_env = getenv("DEPENDENCIES_OUTPUT");
-  bool using_sunpro_dependencies = false;
-  if (!dependencies_env) {
-    dependencies_env = getenv("SUNPRO_DEPENDENCIES");
-    using_sunpro_dependencies = true;
-  }
-  if (!dependencies_env) {
-    return;
-  }
-
-  args_info.generating_dependencies = true;
-  state.dependency_filename_specified = true;
-
-  auto dependencies = Util::split_into_views(dependencies_env, " ");
-
-  if (!dependencies.empty()) {
-    auto abspath_file = dependencies[0];
-    args_info.output_dep = Util::make_relative_path(ctx, abspath_file);
-  }
-
-  // Specifying target object is optional.
-  if (dependencies.size() > 1) {
-    // It's the "file target" form.
-    ctx.args_info.dependency_target_specified = true;
-    std::string_view abspath_obj = dependencies[1];
-    std::string relpath_obj = Util::make_relative_path(ctx, abspath_obj);
-    // Ensure that the compiler gets a relative path.
-    std::string relpath_both = FMT("{} {}", args_info.output_dep, relpath_obj);
-    if (using_sunpro_dependencies) {
-      Util::setenv("SUNPRO_DEPENDENCIES", relpath_both);
-    } else {
-      Util::setenv("DEPENDENCIES_OUTPUT", relpath_both);
-    }
-  } else {
-    // It's the "file" form.
-    state.dependency_implicit_target_specified = true;
-    // Ensure that the compiler gets a relative path.
-    if (using_sunpro_dependencies) {
-      Util::setenv("SUNPRO_DEPENDENCIES", args_info.output_dep);
-    } else {
-      Util::setenv("DEPENDENCIES_OUTPUT", args_info.output_dep);
-    }
-  }
+  return config.is_compiler_group_msvc() ? ".obj" : ".o";
 }
 
 } // namespace
@@ -1144,6 +1122,26 @@ process_args(Context& ctx)
     }
   }
 
+  // Bail out on too hard combinations of options.
+  if (state.found_mf_opt && state.found_wp_md_or_mmd_opt) {
+    // GCC and Clang behave differently when "-Wp,-M[M]D,wp.d" and "-MF mf.d"
+    // are used: GCC writes to wp.d but Clang writes to mf.d. We could
+    // potentially support this by behaving differently depending on the
+    // compiler type, but let's just bail out for now.
+    LOG_RAW("-Wp,-M[M]D in combination with -MF is not supported");
+    return Statistic::unsupported_compiler_option;
+  }
+  if (state.found_wp_md_or_mmd_opt && !args_info.output_obj.empty()
+      && !state.found_md_or_mmd_opt && !args_info.dependency_target) {
+    // GCC and Clang behave differently when "-Wp,-M[M]D,wp.d" is used with "-o"
+    // but with neither "-MMD" nor "-MT"/"-MQ": GCC uses a dependency target
+    // based on the source filename but Clang bases it on the output filename.
+    // We could potentially support by behaving differently depending on the
+    // compiler type, but let's just bail out for now.
+    LOG_RAW("-Wp,-M[M]D with -o without -MMD, -MQ or -MT is not supported");
+    return Statistic::unsupported_compiler_option;
+  }
+
   // Don't try to second guess the compiler's heuristics for stdout handling.
   if (args_info.output_obj == "-") {
     LOG_RAW("Output file is -");
@@ -1165,18 +1163,17 @@ process_args(Context& ctx)
   }
 
   if (output_obj_by_source && !args_info.input_file.empty()) {
-    std::string_view extension;
-    if (state.found_S_opt) {
-      extension = ".s";
-    } else if (!ctx.config.is_compiler_group_msvc()) {
-      extension = ".o";
-    } else {
-      extension = ".obj";
-    }
+    std::string_view extension =
+      state.found_S_opt ? ".s" : get_default_object_file_extension(ctx.config);
     args_info.output_obj +=
       Util::change_extension(Util::base_name(args_info.input_file), extension);
   }
 
+  args_info.orig_output_obj = args_info.output_obj;
+  args_info.output_obj = Util::make_relative_path(ctx, args_info.output_obj);
+
+  // Determine output dependency file.
+
   // On argument processing error, return now since we have determined
   // args_info.output_obj which is needed to determine the log filename in
   // CCACHE_DEBUG mode.
@@ -1200,8 +1197,6 @@ process_args(Context& ctx)
   }
 #endif
 
-  handle_dependency_environment_variables(ctx, state);
-
   if (args_info.input_file.empty()) {
     LOG_RAW("No input file found");
     return Statistic::no_input_file;
@@ -1241,7 +1236,9 @@ process_args(Context& ctx)
     || Util::is_precompiled_header(args_info.output_obj);
 
   if (args_info.output_is_precompiled_header && output_obj_by_source) {
-    args_info.output_obj = args_info.input_file + ".gch";
+    args_info.orig_output_obj = args_info.orig_input_file + ".gch";
+    args_info.output_obj =
+      Util::make_relative_path(ctx, args_info.orig_output_obj);
   }
 
   if (args_info.output_is_precompiled_header
@@ -1358,29 +1355,29 @@ process_args(Context& ctx)
   }
 
   if (args_info.generating_dependencies) {
-    if (!state.dependency_filename_specified) {
-      auto default_depfile_name =
-        Util::change_extension(args_info.output_obj, ".d");
-      args_info.output_dep =
-        Util::make_relative_path(ctx, default_depfile_name);
+    if (state.output_dep_origin == OutputDepOrigin::none) {
+      args_info.output_dep = Util::change_extension(args_info.output_obj, ".d");
       if (!config.run_second_cpp()) {
         // If we're compiling preprocessed code we're sending dep_args to the
         // preprocessor so we need to use -MF to write to the correct .d file
         // location since the preprocessor doesn't know the final object path.
         state.dep_args.push_back("-MF");
-        state.dep_args.push_back(default_depfile_name);
+        state.dep_args.push_back(args_info.output_dep);
       }
     }
 
-    if (!ctx.args_info.dependency_target_specified
-        && !state.dependency_implicit_target_specified
-        && !config.run_second_cpp()) {
+    if (!args_info.dependency_target && !config.run_second_cpp()) {
       // If we're compiling preprocessed code we're sending dep_args to the
       // preprocessor so we need to use -MQ to get the correct target object
       // file in the .d file.
       state.dep_args.push_back("-MQ");
       state.dep_args.push_back(args_info.output_obj);
     }
+
+    if (!args_info.dependency_target) {
+      args_info.dependency_target =
+        Depfile::escape_filename(args_info.orig_output_obj);
+    }
   }
 
   if (args_info.generating_stackusage) {
index f436da6c4d69be24b2f515cdaf34ba4680a788f0..17c0ed0ca3a74ef7e510b3b8a0a476057e27dad6 100644 (file)
@@ -1004,13 +1004,6 @@ to_cache(Context& ctx,
     args.push_back(ctx.args_info.output_dia);
   }
 
-  // Turn off DEPENDENCIES_OUTPUT when running cc1, because otherwise it will
-  // emit a line like this:
-  //
-  //   tmp.stdout.vexed.732.o: /home/mbp/.ccache/tmp.stdout.vexed.732.i
-  Util::unsetenv("DEPENDENCIES_OUTPUT");
-  Util::unsetenv("SUNPRO_DEPENDENCIES");
-
   if (ctx.config.run_second_cpp()) {
     args.push_back(ctx.args_info.input_file);
   } else {
@@ -1288,12 +1281,6 @@ hash_nvcc_host_compiler(const Context& ctx,
   return {};
 }
 
-static bool
-should_rewrite_dependency_target(const ArgsInfo& args_info)
-{
-  return !args_info.dependency_target_specified && args_info.seen_MD_MMD;
-}
-
 // update a hash with information common for the direct and preprocessor modes.
 static nonstd::expected<void, Failure>
 hash_common_info(const Context& ctx,
@@ -1397,12 +1384,7 @@ hash_common_info(const Context& ctx,
     hash.hash(output_obj_dir);
   }
 
-  if ((!should_rewrite_dependency_target(ctx.args_info)
-       && ctx.args_info.generating_dependencies)
-      || ctx.args_info.seen_split_dwarf || ctx.args_info.profile_arcs) {
-    // If generating dependencies: The output object file name is part of the .d
-    // file, so include the path in the hash.
-    //
+  if (ctx.args_info.seen_split_dwarf || ctx.args_info.profile_arcs) {
     // When using -gsplit-dwarf: Object files include a link to the
     // corresponding .dwo file based on the target object filename, so hashing
     // the object file path will do it, although just hashing the object file
@@ -1524,6 +1506,24 @@ option_should_be_ignored(const std::string& arg,
     });
 }
 
+static std::tuple<std::optional<std::string_view>,
+                  std::optional<std::string_view>>
+get_option_and_value(std::string_view option, const Args& args, size_t& i)
+{
+  if (args[i] == option) {
+    if (i + 1 < args.size()) {
+      ++i;
+      return {option, args[i]};
+    } else {
+      return {std::nullopt, std::nullopt};
+    }
+  } else if (util::starts_with(args[i], option)) {
+    return {option, std::string_view(args[i]).substr(option.length())};
+  } else {
+    return {std::nullopt, std::nullopt};
+  }
+}
+
 // Update a hash sum with information specific to the direct and preprocessor
 // modes and calculate the result key. Returns the result key on success, and
 // if direct_mode is true also the manifest key.
@@ -1613,10 +1613,12 @@ calculate_result_and_manifest_key(Context& ctx,
       }
     }
 
-    // If we're generating dependencies, we make sure to skip the filename of
-    // the dependency file, since it doesn't impact the output.
     if (ctx.args_info.generating_dependencies) {
+      std::optional<std::string_view> option;
+      std::optional<std::string_view> value;
+
       if (util::starts_with(args[i], "-Wp,")) {
+        // Skip the dependency filename since it doesn't impact the output.
         if (util::starts_with(args[i], "-Wp,-MD,")
             && args[i].find(',', 8) == std::string::npos) {
           hash.hash(args[i].data(), 8);
@@ -1626,18 +1628,22 @@ calculate_result_and_manifest_key(Context& ctx,
           hash.hash(args[i].data(), 9);
           continue;
         }
-      } else if (util::starts_with(args[i], "-MF")) {
-        // In either case, hash the "-MF" part.
-        hash.hash_delimiter("arg");
-        hash.hash(args[i].data(), 3);
-
-        if (ctx.args_info.output_dep != "/dev/null") {
-          bool separate_argument = (args[i].size() == 3);
-          if (separate_argument) {
-            // Next argument is dependency name, so skip it.
-            i++;
-          }
-        }
+      } else if (std::tie(option, value) = get_option_and_value("-MF", args, i);
+                 option) {
+        // Skip the dependency filename since it doesn't impact the output.
+        hash.hash(*option);
+        continue;
+      } else if (std::tie(option, value) = get_option_and_value("-MQ", args, i);
+                 option) {
+        hash.hash(*option);
+        // No need to hash the dependency target since we always calculate it on
+        // a cache hit.
+        continue;
+      } else if (std::tie(option, value) = get_option_and_value("-MT", args, i);
+                 option) {
+        hash.hash(*option);
+        // No need to hash the dependency target since we always calculate it on
+        // a cache hit.
         continue;
       }
     }
@@ -1921,8 +1927,7 @@ from_cache(Context& ctx, FromCacheCallMode mode, const Digest& result_key)
     core::FileReader file_reader(file.get());
     core::CacheEntryReader cache_entry_reader(file_reader);
     Result::Reader result_reader(cache_entry_reader, *result_path);
-    ResultRetriever result_retriever(
-      ctx, should_rewrite_dependency_target(ctx.args_info));
+    ResultRetriever result_retriever(ctx);
 
     result_reader.read(result_retriever);
   } catch (ResultRetriever::WriteError& e) {
@@ -2199,6 +2204,13 @@ do_cache_compilation(Context& ctx, const char* const* argv)
 
   TRY(set_up_uncached_err());
 
+  for (const auto& name : {"DEPENDENCIES_OUTPUT", "SUNPRO_DEPENDENCIES"}) {
+    if (getenv(name)) {
+      LOG("Unsupported environment variable: {}", name);
+      return Statistic::unsupported_environment_variable;
+    }
+  }
+
   if (ctx.config.is_compiler_group_msvc()) {
     for (const auto& name : {"CL", "_CL_"}) {
       if (getenv(name)) {
@@ -2255,7 +2267,7 @@ do_cache_compilation(Context& ctx, const char* const* argv)
   if (ctx.config.debug()) {
     const auto path = prepare_debug_path(ctx.config.debug_dir(),
                                          ctx.time_of_invocation,
-                                         ctx.args_info.output_obj,
+                                         ctx.args_info.orig_output_obj,
                                          "input-text");
     File debug_text_file(path, "w");
     if (debug_text_file) {
index 8f80e20cdb4b19d9b96408d7683c1f1785d2738d..1cacb26d45ef20f04780226cd1187f7b0444aed4 100644 (file)
@@ -30,7 +30,6 @@ addtest(cpp1)
 addtest(debug_prefix_map)
 addtest(depend)
 addtest(direct)
-addtest(direct_gcc)
 addtest(fileclone)
 addtest(hardlink)
 addtest(inode_cache)
index d5b338957aacd94f9c8478f5f50baf1d325518ff..bc13b0ef3603da1e688dda0722caee144f68ef6c 100755 (executable)
--- a/test/run
+++ b/test/run
@@ -370,7 +370,9 @@ reset_environment() {
         fi
     done < <(compgen -e)
 
+    unset DEPENDENCIES_OUTPUT
     unset GCC_COLORS
+    unset SUNPRO_DEPENDENCIES
     unset TERM
     unset XDG_CACHE_HOME
     unset XDG_CONFIG_HOME
index c7b6da88ab636428e16d106b3f600ccb73f59ed1..c7cf998bbdb04a2aabbbc4964762bae4b93d4c21 100644 (file)
@@ -174,6 +174,15 @@ base_tests() {
     $CCACHE_COMPILE -M foo -c test1.c >/dev/null 2>&1
     expect_stat unsupported_compiler_option 1
 
+    # -------------------------------------------------------------------------
+    for variable in DEPENDENCIES_OUTPUT SUNPRO_DEPENDENCIES; do
+        TEST "Unsupported environment variable ${variable}"
+
+        eval "export ${variable}=1"
+        $CCACHE_COMPILE -c test1.c
+        expect_stat unsupported_environment_variable 1
+    done
+
     # -------------------------------------------------------------------------
     TEST "Output to directory"
 
@@ -1451,13 +1460,12 @@ EOF
     rm compiler.args
 
     # -------------------------------------------------------------------------
-    TEST "Dependency file content"
-
-    mkdir build
-    cp test1.c build
 
     for src in test1.c build/test1.c; do
         for obj in test1.o build/test1.o; do
+            TEST "Dependency file content, $src -o $obj"
+            mkdir build
+            cp test1.c build
             $CCACHE_COMPILE -c -MMD $src -o $obj
             dep=$(echo $obj | sed 's/\.o$/.d/')
             expect_content $dep "$obj: $src"
index b02fcb6a81b023a66982a96a4138d5f3df63c15b..5486b1e50cf1998e04f2bf62ce3749c8ed36b8a8 100644 (file)
@@ -219,22 +219,44 @@ EOF
     fi
 
     # -------------------------------------------------------------------------
-    TEST "-MF/-MQ/-MT with absolute paths"
+    for option in MF "MF "; do
+        TEST "-${option}/absolute/path"
+
+        cd dir1
+        CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -I"$(pwd)/include" -MMD -${option}"$(pwd)/foo.d" -c src/test.c
+        expect_stat direct_cache_hit 0
+        expect_stat preprocessed_cache_hit 0
+        expect_stat cache_miss 1
+        expect_content_pattern foo.d "test.o:*"
+        cd ..
+
+        cd dir2
+        CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -I"$(pwd)/include" -MMD -${option}"$(pwd)/foo.d" -c src/test.c
+        expect_stat direct_cache_hit 1
+        expect_stat preprocessed_cache_hit 0
+        expect_stat cache_miss 1
+        expect_content_pattern foo.d "test.o:*"
+        cd ..
+    done
+
+    # -------------------------------------------------------------------------
+    for option in MQ "MQ " MT "MT "; do
+        TEST "-${option}/absolute/path"
 
-    for option in MF "MF " MQ "MQ " MT "MT "; do
-        clear_cache
         cd dir1
-        CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -MD -${option}`pwd`/test.d -c src/test.c
+        CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -I"$(pwd)/include" -MMD -${option}"$(pwd)/foo.o" -c src/test.c
         expect_stat direct_cache_hit 0
         expect_stat preprocessed_cache_hit 0
         expect_stat cache_miss 1
+        expect_content_pattern test.d "$(pwd)/foo.o:*"
         cd ..
 
         cd dir2
-        CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -MD -${option}`pwd`/test.d -c src/test.c
+        CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -I"$(pwd)/include" -MMD -${option}"$(pwd)/foo.o" -c src/test.c
         expect_stat direct_cache_hit 1
         expect_stat preprocessed_cache_hit 0
         expect_stat cache_miss 1
+        expect_content_pattern test.d "$(pwd)/foo.o:*"
         cd ..
     done
 
@@ -253,10 +275,10 @@ EOF
         expect_stat cache_miss 1
         # Check that there is no absolute path in the dependency file:
         while read line; do
-            for file in $line; do
-                case $file in /*)
-                    test_failed "Absolute file path '$file' found in dependency file '`pwd`/test.d'"
-                esac
+            for token in $line; do
+                if [[ $token == /* && $token != *: ]]; then
+                    test_failed "Absolute file path '$token' found in dependency file '$(pwd)/test.d'"
+                fi
             done
         done <test.d
         cd ..
@@ -343,4 +365,36 @@ EOF
     expect_stat direct_cache_hit 1
     expect_stat preprocessed_cache_hit 0
     expect_stat cache_miss 1
+
+    # -------------------------------------------------------------------------
+    TEST "Object token path in dependency file"
+
+    cd dir1
+
+    CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -MMD -I$(pwd)/include -c src/test.c
+    expect_stat direct_cache_hit 0
+    expect_stat preprocessed_cache_hit 0
+    expect_stat cache_miss 1
+    expect_content_pattern test.d "test.o:*"
+
+    CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -MMD -I$(pwd)/include -c src/test.c -o test.o
+    expect_stat direct_cache_hit 1
+    expect_stat preprocessed_cache_hit 0
+    expect_stat cache_miss 1
+    expect_contains test.d test.o:
+    expect_content_pattern test.d "test.o:*"
+
+    CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -MMD -I$(pwd)/include -c src/test.c -o $(pwd)/test.o
+    expect_stat direct_cache_hit 2
+    expect_stat preprocessed_cache_hit 0
+    expect_stat cache_miss 1
+    expect_contains test.d test.o:
+    expect_content_pattern test.d "$(pwd)/test.o:*"
+
+    CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -MMD -I$(pwd)/include -c $(pwd)/src/test.c
+    expect_stat direct_cache_hit 3
+    expect_stat preprocessed_cache_hit 0
+    expect_stat cache_miss 1
+    expect_contains test.d test.o:
+    expect_content_pattern test.d "test.o:*"
 }
index deadb2a98ecd9ebf22c6f6f99f0eae686ec4f4e6..a0cecf376fbec1eb77c23e2ea5234f01204dd25f 100644 (file)
@@ -140,45 +140,43 @@ EOF
     expect_stat cache_miss 2
 
     # -------------------------------------------------------------------------
-    TEST "Calculation of dependency file names"
-
-    i=0
     for ext in .o .obj "" . .foo.bar; do
-        rm -rf testdir
-        mkdir testdir
+        TEST "Calculation of dependency file names, ext=\"${ext}\""
 
+        mkdir testdir
         dep_file=testdir/`echo test$ext | sed 's/\.[^.]*\$//'`.d
 
-        $CCACHE_COMPILE -MD -c test.c -o testdir/test$ext
-        expect_stat direct_cache_hit $((3 * i))
-        expect_stat cache_miss $((i + 1))
+        # No -MQ/-MT:
+        $CCACHE_COMPILE -MMD -c test.c -o testdir/test$ext
+        expect_stat direct_cache_hit 0
+        expect_stat cache_miss 1
+        expect_content_pattern "${dep_file}" "testdir/test${ext}:*"
         rm -f $dep_file
 
-        $CCACHE_COMPILE -MD -c test.c -o testdir/test$ext
-        expect_stat direct_cache_hit $((3 * i + 1))
-        expect_stat cache_miss $((i + 1))
-        expect_exists $dep_file
-        if ! grep "test$ext:" $dep_file >/dev/null 2>&1; then
-            test_failed "$dep_file does not contain \"test$ext:\""
-        fi
+        $CCACHE_COMPILE -MMD -c test.c -o testdir/test$ext
+        expect_stat direct_cache_hit 1
+        expect_stat cache_miss 1
+        expect_content_pattern "${dep_file}" "testdir/test${ext}:*"
 
+        # -MQ:
         dep_target=foo.bar
-        $CCACHE_COMPILE -MD -MQ $dep_target -c test.c -o testdir/test$ext
-        expect_stat direct_cache_hit $((3 * i + 1))
-        expect_stat cache_miss $((i + 2))
+        $CCACHE_COMPILE -MMD -MQ $dep_target -c test.c -o testdir/test$ext
+        expect_stat direct_cache_hit 1
+        expect_stat cache_miss 2
+        expect_content_pattern "${dep_file}" "${dep_target}:*"
         rm -f $dep_target
 
-        $CCACHE_COMPILE -MD -MQ $dep_target -c test.c -o testdir/test$ext
-        expect_stat direct_cache_hit $((3 * i + 2))
-        expect_stat cache_miss $((i + 2))
-        expect_exists $dep_file
-        if ! grep $dep_target $dep_file >/dev/null 2>&1; then
-            test_failed "$dep_file does not contain $dep_target"
-        fi
+        $CCACHE_COMPILE -MMD -MQ $dep_target -c test.c -o testdir/test$ext
+        expect_stat direct_cache_hit 2
+        expect_stat cache_miss 2
+        expect_content_pattern "${dep_file}" "${dep_target}:*"
 
-        i=$((i + 1))
+        dep_target=foo.bar
+        $CCACHE_COMPILE -MMD -MQ $dep_target -c test.c -o testdir/test$ext
+        expect_stat direct_cache_hit 3
+        expect_stat cache_miss 2
+        expect_content_pattern "${dep_file}" "${dep_target}:*"
     done
-    expect_stat files_in_cache $((2 * i + 2))
 
     # -------------------------------------------------------------------------
     TEST "-MMD for different source files"
@@ -196,16 +194,28 @@ EOF
     expect_content a/source.d "a/source.o: a/source.c"
 
     # -------------------------------------------------------------------------
-    for dep_args in "-MMD" "-MMD -MF foo.d" "-Wp,-MMD,foo.d"; do
-        for obj_args in "" "-o bar.o"; do
-            if [ "$dep_args" != "-MMD" ]; then
-                dep_file=foo.d
-                another_dep_file=foo.d
-            elif [ -z "$obj_args" ]; then
-                dep_file=test.d
+    dep_args_combinations=(
+        "-MMD"
+        "-MMD -MF a.d -MF mf.d"
+        "-MFmf.d -MMD"
+        "-MMD -Wp,-MMD,wp.d"
+        "-Wp,-MMD,wp.d -MMD"
+        "-MT foo.o -Wp,-MMD,wp.d"
+        "-MQ foo.o -Wp,-MMD,wp.d"
+    )
+    for dep_args in "${dep_args_combinations[@]}"; do
+        for obj_args in "" "-o obj.o"; do
+            if [[ ${dep_args} == *-Wp,* ]]; then
+                dep_file=wp.d
+                another_dep_file=wp.d
+            elif [[ ${dep_args} == *-MF* ]]; then
+                dep_file=mf.d
+                another_dep_file=mf.d
+            elif [[ -n ${obj_args} ]]; then
+                dep_file=obj.d
                 another_dep_file=another.d
             else
-                dep_file=bar.d
+                dep_file=test.d
                 another_dep_file=another.d
             fi
 
@@ -213,29 +223,43 @@ EOF
             # -----------------------------------------------------------------
 
             $COMPILER -c test.c $dep_args $obj_args
-            mv $dep_file $dep_file.real
+            mv $dep_file $dep_file.reference
 
             $COMPILER -c test.c $dep_args -o another.o
-            mv $another_dep_file another.d.real
+            mv $another_dep_file another.d.reference
 
             # cache miss
             $CCACHE_COMPILE -c test.c $dep_args $obj_args
             expect_stat direct_cache_hit 0
             expect_stat cache_miss 1
-            expect_equal_content $dep_file.real $dep_file
+            expect_equal_content $dep_file.reference $dep_file
 
             # cache hit
             $CCACHE_COMPILE -c test.c $dep_args $obj_args
             expect_stat direct_cache_hit 1
             expect_stat cache_miss 1
-            expect_equal_content $dep_file.real $dep_file
+            expect_equal_content $dep_file.reference $dep_file
 
             # change object file name
             $CCACHE_COMPILE -c test.c $dep_args -o another.o
-            expect_equal_content another.d.real $another_dep_file
+            expect_stat direct_cache_hit 2
+            expect_stat cache_miss 1
+            expect_equal_content another.d.reference $another_dep_file
         done
     done
 
+    # -----------------------------------------------------------------
+    TEST "Unsupported -Wp,-MMD with -o without -MMD/-MT/-MQ"
+
+    $CCACHE_COMPILE -c test.c -Wp,-MMD,wp.d -o object.o
+    expect_stat unsupported_compiler_option 1
+
+    # -----------------------------------------------------------------
+    TEST "Unsupported -Wp,-MMD with -MF"
+
+    $CCACHE_COMPILE -c test.c -Wp,-MMD,wp.d -MF mf.d -o object.o
+    expect_stat unsupported_compiler_option 1
+
     # -------------------------------------------------------------------------
     TEST "-MD/-MMD dependency target rewriting"
 
@@ -609,6 +633,89 @@ EOF
     expect_stat files_in_cache 4
     expect_equal_content test.d expected.d
 
+    # -------------------------------------------------------------------------
+    TEST "Handling of -MT/-MQ"
+
+    echo '#include "test3.h"' >test.c
+
+    $CCACHE_COMPILE -MMD -c test.c
+    expect_stat direct_cache_hit 0
+    expect_stat cache_miss 1
+    expect_content test.d "test.o: test.c test3.h"
+
+    $CCACHE_COMPILE -MMD -c test.c
+    expect_stat direct_cache_hit 1
+    expect_stat cache_miss 1
+    expect_content test.d "test.o: test.c test3.h"
+
+    # -MQ
+
+    $CCACHE_COMPILE -MMD -MQ '$mq1' -c test.c
+    expect_stat direct_cache_hit 1
+    expect_stat cache_miss 2
+    expect_content test.d '$$mq1: test.c test3.h'
+
+    $CCACHE_COMPILE -MMD -MQ '$mq2' -c test.c
+    expect_stat direct_cache_hit 2 # New dependency target but still a cache hit
+    expect_stat cache_miss 2
+    expect_content test.d '$$mq2: test.c test3.h'
+
+    # -MT
+
+    $CCACHE_COMPILE -MMD -MT '$mt1' -c test.c
+    expect_stat direct_cache_hit 2
+    expect_stat cache_miss 3
+    expect_content test.d '$mt1: test.c test3.h'
+
+    $CCACHE_COMPILE -MMD -MT '$mt2' -c test.c
+    expect_stat direct_cache_hit 3 # New dependency target but still a cache hit
+    expect_stat cache_miss 3
+    expect_content test.d '$mt2: test.c test3.h'
+
+    # -MQ -MT
+
+    $CCACHE_COMPILE -MMD -MQ '$mq1' -MT '$mt1' -c test.c
+    expect_stat direct_cache_hit 3
+    expect_stat cache_miss 4
+    content=$(<test.d)
+    expected_1='$$mq1 $mt1: test.c test3.h'
+    expected_2='$mt1 $$mq1: test.c test3.h'
+    if [[ $content != "${expected_1}" && $content != "${expected_2}" ]]; then
+        test_failed "Bad content of test.d\nExpected: ${expected_1} or ${expected_2}\nActual: ${content}"
+    fi
+
+    $CCACHE_COMPILE -MMD -MQ '$mq2' -MT '$mt2' -c test.c
+    expect_stat direct_cache_hit 4 # New dependency targets but still a cache hit
+    expect_stat cache_miss 4
+    content=$(<test.d)
+    expected_1='$$mq2 $mt2: test.c test3.h'
+    expected_2='$mt2 $$mq2: test.c test3.h'
+    if [[ $content != "${expected_1}" && $content != "${expected_2}" ]]; then
+        test_failed "Bad content of test.d\nExpected: ${expected_1} or ${expected_2}\nActual: ${content}"
+    fi
+
+    # -MQ -MT -Wp,-MMD,
+
+    $CCACHE_COMPILE -MMD -MQ '$mq1' -MT '$mt1' -Wp,-MMD,foo.d -c test.c
+    expect_stat direct_cache_hit 4
+    expect_stat cache_miss 5
+    content=$(<foo.d)
+    expected_1='$$mq1 $mt1: test.c test3.h'
+    expected_2='$mt1 $$mq1: test.c test3.h'
+    if [[ $content != "${expected_1}" && $content != "${expected_2}" ]]; then
+        test_failed "Bad content of foo.d\nExpected: ${expected_1} or ${expected_2}\nActual: ${content}"
+    fi
+
+    $CCACHE_COMPILE -MMD -MQ '$mq2' -MT '$mt2' -Wp,-MMD,foo.d -c test.c
+    expect_stat direct_cache_hit 5 # New dependency targets but still a cache hit
+    expect_stat cache_miss 5
+    content=$(<foo.d)
+    expected_1='$$mq2 $mt2: test.c test3.h'
+    expected_2='$mt2 $$mq2: test.c test3.h'
+    if [[ $content != "${expected_1}" && $content != "${expected_2}" ]]; then
+        test_failed "Bad content of test.d\nExpected: ${expected_1} or ${expected_2}\nActual: ${content}"
+    fi
+
     # -------------------------------------------------------------------------
     TEST "stderr from both preprocessor and compiler"
 
diff --git a/test/suites/direct_gcc.bash b/test/suites/direct_gcc.bash
deleted file mode 100644 (file)
index 3cfb0c0..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-SUITE_direct_gcc_PROBE() {
-    if [[ "${COMPILER_TYPE_GCC}" != "true" ]]; then
-        echo "Skipping GCC only test cases"
-    fi
-}
-
-SUITE_direct_gcc_SETUP() {
-    unset CCACHE_NODIRECT
-
-    cat <<EOF >test.c
-// test.c
-#include "test1.h"
-#include "test2.h"
-EOF
-    cat <<EOF >test1.h
-#include "test3.h"
-int test1;
-EOF
-    cat <<EOF >test2.h
-int test2;
-EOF
-    cat <<EOF >test3.h
-int test3;
-EOF
-    backdate test1.h test2.h test3.h
-
-    DEPENDENCIES_OUTPUT="expected_dependencies_output.d" $COMPILER -c test.c
-    DEPENDENCIES_OUTPUT="expected_dependencies_output_target.d target.o" $COMPILER -c test.c
-    SUNPRO_DEPENDENCIES="expected_sunpro_dependencies.d" $COMPILER -c test.c
-    SUNPRO_DEPENDENCIES="expected_sunpro_dependencies_target.d target.o" $COMPILER -c test.c
-    rm test.o
-}
-
-SUITE_direct_gcc() {
-    # -------------------------------------------------------------------------
-    TEST "DEPENDENCIES_OUTPUT environment variable"
-
-    DEPENDENCIES_OUTPUT="other.d" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 0
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-    expect_equal_content other.d expected_dependencies_output.d
-
-    DEPENDENCIES_OUTPUT="other.d" $COMPILER -c test.c -o reference_test.o
-    expect_equal_object_files reference_test.o test.o
-
-    rm -f other.d
-    DEPENDENCIES_OUTPUT="other.d" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 1
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-    expect_equal_content other.d expected_dependencies_output.d
-    expect_equal_object_files reference_test.o test.o
-
-    DEPENDENCIES_OUTPUT="different_name.d" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 2
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-    expect_equal_content different_name.d expected_dependencies_output.d
-    expect_equal_object_files reference_test.o test.o
-
-    # -------------------------------------------------------------------------
-    TEST "DEPENDENCIES_OUTPUT environment variable with target"
-
-    DEPENDENCIES_OUTPUT="other.d target.o" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 0
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-    expect_equal_content other.d expected_dependencies_output_target.d
-
-    DEPENDENCIES_OUTPUT="other.d target.o" $COMPILER -c test.c -o reference_test.o
-    expect_equal_object_files reference_test.o test.o
-
-    rm -f other.d
-    DEPENDENCIES_OUTPUT="other.d target.o" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 1
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-    expect_equal_content other.d expected_dependencies_output_target.d
-    expect_equal_object_files reference_test.o test.o
-
-    DEPENDENCIES_OUTPUT="different_name.d target.o" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 2
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-    expect_equal_content different_name.d expected_dependencies_output_target.d
-    expect_equal_object_files reference_test.o test.o
-
-    # -------------------------------------------------------------------------
-    TEST "SUNPRO_DEPENDENCIES environment variable"
-
-    SUNPRO_DEPENDENCIES="other.d" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 0
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-    expect_equal_content other.d expected_sunpro_dependencies.d
-
-    SUNPRO_DEPENDENCIES="other.d" $COMPILER -c test.c -o reference_test.o
-    expect_equal_object_files reference_test.o test.o
-
-    rm -f other.d
-    SUNPRO_DEPENDENCIES="other.d" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 1
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-    expect_equal_content other.d expected_sunpro_dependencies.d
-    expect_equal_object_files reference_test.o test.o
-
-    SUNPRO_DEPENDENCIES="different_name.d" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 2
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-    expect_equal_content different_name.d expected_sunpro_dependencies.d
-    expect_equal_object_files reference_test.o test.o
-
-    # -------------------------------------------------------------------------
-    TEST "SUNPRO_DEPENDENCIES environment variable with target"
-
-    SUNPRO_DEPENDENCIES="other.d target.o" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 0
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-    expect_equal_content other.d expected_sunpro_dependencies_target.d
-
-    SUNPRO_DEPENDENCIES="other.d target.o" $COMPILER -c test.c -o reference_test.o
-    expect_equal_object_files reference_test.o test.o
-
-    rm -f other.d
-    SUNPRO_DEPENDENCIES="other.d target.o" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 1
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-    expect_equal_content other.d expected_sunpro_dependencies_target.d
-    expect_equal_object_files reference_test.o test.o
-
-    SUNPRO_DEPENDENCIES="different_name.d target.o" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 2
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-    expect_equal_content different_name.d expected_sunpro_dependencies_target.d
-    expect_equal_object_files reference_test.o test.o
-
-    # -------------------------------------------------------------------------
-    TEST "DEPENDENCIES_OUTPUT environment variable set to /dev/null"
-
-    DEPENDENCIES_OUTPUT="/dev/null" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 0
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 1
-
-    DEPENDENCIES_OUTPUT="other.d" $CCACHE_COMPILE -c test.c
-    expect_stat direct_cache_hit 0
-    expect_stat preprocessed_cache_hit 0
-    expect_stat cache_miss 2
-}
index c4f7e3530291151699a4d2b56010cd09925a3380..3bbb1415b325801016adb1f3a17cd8e3fb2881e3 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2020-2021 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2022 Joel Rosdahl and other contributors
 //
 // See doc/AUTHORS.adoc for a complete list of contributors.
 //
@@ -38,7 +38,7 @@ TEST_CASE("Depfile::escape_filename")
   CHECK(Depfile::escape_filename("foo$bar") == "foo$$bar");
 }
 
-TEST_CASE("Depfile::rewrite_paths")
+TEST_CASE("Depfile::rewrite_source_paths")
 {
   Context ctx;
 
@@ -46,30 +46,32 @@ TEST_CASE("Depfile::rewrite_paths")
   ctx.has_absolute_include_headers = true;
 
   const auto content =
-    FMT("foo.o: bar.c {0}/bar.h \\\n\n {1}/fie.h {0}/fum.h\n",
+    FMT("{0}/foo.o {0}/foo.o: bar.c {0}/bar.h \\\n\n {1}/fie.h {0}/fum.h\n",
         cwd,
         Util::dir_name(cwd));
 
   SUBCASE("Base directory not in dep file content")
   {
     ctx.config.set_base_dir("/foo/bar");
-    CHECK(!Depfile::rewrite_paths(ctx, ""));
-    CHECK(!Depfile::rewrite_paths(ctx, content));
+    CHECK(!Depfile::rewrite_source_paths(ctx, ""));
+    CHECK(!Depfile::rewrite_source_paths(ctx, content));
   }
 
   SUBCASE("Base directory in dep file content but not matching")
   {
     ctx.config.set_base_dir(FMT("{}/other", Util::dir_name(cwd)));
-    CHECK(!Depfile::rewrite_paths(ctx, ""));
-    CHECK(!Depfile::rewrite_paths(ctx, content));
+    CHECK(!Depfile::rewrite_source_paths(ctx, ""));
+    CHECK(!Depfile::rewrite_source_paths(ctx, content));
   }
 
   SUBCASE("Absolute paths under base directory rewritten")
   {
     ctx.config.set_base_dir(cwd);
-    const auto actual = Depfile::rewrite_paths(ctx, content);
-    const auto expected = FMT("foo.o: bar.c ./bar.h \\\n\n {}/fie.h ./fum.h\n",
-                              Util::dir_name(cwd));
+    const auto actual = Depfile::rewrite_source_paths(ctx, content);
+    const auto expected =
+      FMT("{0}/foo.o {0}/foo.o: bar.c ./bar.h \\\n\n {1}/fie.h ./fum.h\n",
+          cwd,
+          Util::dir_name(cwd));
     REQUIRE(actual);
     CHECK(*actual == expected);
   }
index f5e8619309b0f3ac5b9f22d03e692dacb70fdf87..5de5eb2b03b7e2a2fa3d51be9b7b98abbe158c98 100644 (file)
@@ -115,8 +115,8 @@ TEST_CASE("dependency_args_to_preprocessor_if_run_second_cpp_is_false")
 {
   TestContext test_context;
   const std::string dep_args =
-    "-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MD,wpmd"
-    " -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf";
+    "-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MP"
+    " -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf";
   Context ctx;
   ctx.orig_args = Args::from_string("cc " + dep_args + " -c foo.c -o foo.o");
   Util::write_file("foo.c", "");
@@ -134,8 +134,8 @@ TEST_CASE("dependency_args_to_compiler_if_run_second_cpp_is_true")
 {
   TestContext test_context;
   const std::string dep_args =
-    "-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MD,wpmd"
-    " -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf";
+    "-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MP"
+    " -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf";
   Context ctx;
   ctx.orig_args = Args::from_string("cc " + dep_args + " -c foo.c -o foo.o");
   Util::write_file("foo.c", "");
@@ -157,8 +157,8 @@ TEST_CASE("cpp_only_args_to_preprocessor_if_run_second_cpp_is_false")
     " -iwithprefix . -iwithprefixbefore . -DTEST_MACRO -DTEST_MACRO2=1 -F."
     " -trigraphs -fworking-directory -fno-working-directory";
   const std::string dep_args =
-    "-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MD,wpmd"
-    " -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf";
+    "-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MP"
+    " -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf";
   Context ctx;
   ctx.orig_args =
     Args::from_string("cc " + cpp_args + " " + dep_args + " -c foo.c -o foo.o");
@@ -184,8 +184,7 @@ TEST_CASE(
     " -iwithprefix . -iwithprefixbefore . -DTEST_MACRO -DTEST_MACRO2=1 -F."
     " -trigraphs -fworking-directory -fno-working-directory";
   const std::string dep_args =
-    "-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MD,wpmd"
-    " -Wp,-MMD,wpmmd";
+    "-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2";
   Context ctx;
   ctx.orig_args =
     Args::from_string("cc " + cpp_args + " " + dep_args + " -c foo.c -o foo.o");