]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Share cache for different object file names with -MD/-MMD (#592)
authorDeepak Yadav <yadavd@gmail.com>
Sat, 25 Jul 2020 14:49:33 +0000 (20:19 +0530)
committerGitHub <noreply@github.com>
Sat, 25 Jul 2020 14:49:33 +0000 (16:49 +0200)
src/ArgsInfo.hpp
src/ResultRetriever.cpp
src/ResultRetriever.hpp
src/argprocessing.cpp
src/ccache.cpp
test/suites/base.bash
test/suites/direct.bash

index 497ba2afd37358a5cf550da2a96ebc181beacb1d..54f7a31c51ba5b772f6c14d7c95c37baefd877d4 100644 (file)
@@ -58,6 +58,15 @@ struct ArgsInfo
   // Is the compiler being asked to output dependencies?
   bool generating_dependencies = false;
 
+  // Option MD/MMD
+  bool seen_MD_MMD = false;
+
+  // Change target of dependency file
+  bool change_dep_file = false;
+
+  // Is the dependency makefile target name specified with -MT or -MQ?
+  bool dependency_target_specified = false;
+
   // Is the compiler being asked to output coverage?
   bool generating_coverage = false;
 
index 81386c60e0e450cf3836b75ea97615a9b10fb170..c13074aca84824843b99bfbd838bb6155df609ea 100644 (file)
@@ -44,6 +44,7 @@ ResultRetriever::on_entry_start(uint32_t entry_number,
   std::string dest_path;
 
   m_dest_file_type = file_type;
+  m_first = true;
 
   switch (file_type) {
   case FileType::object:
@@ -123,9 +124,28 @@ ResultRetriever::on_entry_data(const uint8_t* data, size_t size)
 
   if (m_dest_file_type == FileType::stderr_output) {
     m_stderr_text.append(reinterpret_cast<const char*>(data), size);
+  } else if (m_dest_file_type == FileType::dependency && m_first
+             && m_ctx.args_info.change_dep_file) {
+    // Write the object file name
+    if (!write_fd(*m_dest_fd,
+                  m_ctx.args_info.output_obj.data(),
+                  m_ctx.args_info.output_obj.length())) {
+      throw Error(fmt::format("Failed to write to {}", m_dest_path));
+    }
+
+    for (size_t i = 0; i < size; i++) {
+      if (data[i] == ':') {
+        // Write the rest line
+        if (!write_fd(*m_dest_fd, &data[i], size - i)) {
+          throw Error(fmt::format("Failed to write to {}", m_dest_path));
+        }
+        break;
+      }
+    }
   } else if (!write_fd(*m_dest_fd, data, size)) {
     throw Error(fmt::format("Failed to write to {}", m_dest_path));
   }
+  m_first = false;
 }
 
 void
index d15d9350629f96f1c4c08fcfeb1b064630b874b5..45b3d4d8ccfaaafd56ca7129556fc04ec5ba6c7b 100644 (file)
@@ -45,4 +45,5 @@ private:
   Fd m_dest_fd;
   std::string m_dest_path;
   std::string m_stderr_text;
+  bool m_first;
 };
index e072017eab0099383df25eab74430a8157e7b3a3..5ac3391fa40cf34703dc3c0009198a94c8ee6216 100644 (file)
@@ -52,9 +52,6 @@ struct ArgumentProcessingState
   // Is the dependency makefile name overridden with -MF?
   bool dependency_filename_specified = false;
 
-  // Is the dependency makefile target name specified with -MT or -MQ?
-  bool dependency_target_specified = false;
-
   // Is the dependency target name implicitly specified using
   // DEPENDENCIES_OUTPUT or SUNPRO_DEPENDENCIES?
   bool dependency_implicit_target_specified = false;
@@ -468,6 +465,7 @@ process_arg(Context& ctx,
   // with gcc -E, when the output file is not specified.
   if (args[i] == "-MD" || args[i] == "-MMD") {
     args_info.generating_dependencies = true;
+    args_info.seen_MD_MMD = true;
     state.dep_args.push_back(args[i]);
     return nullopt;
   }
@@ -501,7 +499,7 @@ process_arg(Context& ctx,
   }
 
   if (Util::starts_with(args[i], "-MQ") || Util::starts_with(args[i], "-MT")) {
-    state.dependency_target_specified = true;
+    ctx.args_info.dependency_target_specified = true;
 
     if (args[i].size() == 3) {
       // -MQ arg or -MT arg
@@ -864,7 +862,7 @@ handle_dependency_environment_variables(Context& ctx,
   // Specifying target object is optional.
   if (dependencies.size() > 1) {
     // It's the "file target" form.
-    state.dependency_target_specified = true;
+    ctx.args_info.dependency_target_specified = true;
     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.
@@ -915,6 +913,10 @@ process_args(Context& ctx,
     }
   }
 
+  if (!ctx.args_info.dependency_target_specified && ctx.args_info.seen_MD_MMD) {
+    ctx.args_info.change_dep_file = true;
+  }
+
   if (state.generating_debuginfo_level_3 && !config.run_second_cpp()) {
     cc_log("Generating debug info level 3; not compiling preprocessed code");
     config.set_run_second_cpp(true);
@@ -1101,7 +1103,7 @@ process_args(Context& ctx,
       }
     }
 
-    if (!state.dependency_target_specified
+    if (!ctx.args_info.dependency_target_specified
         && !state.dependency_implicit_target_specified
         && !config.run_second_cpp()) {
       // If we're compiling preprocessed code we're sending dep_args to the
index 70d0eaa51df817ddc5997ecabb69e1ac3ea2c671..baf0da66c8c3a2b5aac813637fdc2392feef6abf 100644 (file)
@@ -1257,7 +1257,8 @@ hash_common_info(const Context& ctx,
     hash.hash(dir_to_hash);
   }
 
-  if (ctx.args_info.generating_dependencies || ctx.args_info.seen_split_dwarf) {
+  if ((!ctx.args_info.change_dep_file && ctx.args_info.generating_dependencies)
+      || ctx.args_info.seen_split_dwarf) {
     // The output object file name is part of the .d file, so include the path
     // in the hash if generating dependencies.
     //
index 0c680eb2b3d09be6a6bbcd16dd71e69e881e0309..53afdca2c0ea2050b2e908d18cfe9287c18b2d80 100644 (file)
@@ -1110,14 +1110,11 @@ EOF
     mkdir build
     cp test1.c build
 
-    i=0
     for src in test1.c build/test1.c; do
         for obj in test1.o build/test1.o; do
-            i=$((i + 1))
             $CCACHE_COMPILE -c -MMD $src -o $obj
             dep=$(echo $obj | sed 's/\.o$/.d/')
             expect_file_content $dep "$obj: $src"
-            expect_stat 'cache miss' $i
         done
     done
 
index ad601791c21290c0e47ee7d40e57c9431da39328..68804825926d65d574b663c8871dfecf837848fe 100644 (file)
@@ -131,6 +131,8 @@ EOF
     TEST "Calculation of dependency file names"
 
     i=0
+    hit=-1
+    miss=1
     for ext in .o .obj "" . .foo.bar; do
         rm -rf testdir
         mkdir testdir
@@ -138,13 +140,15 @@ EOF
         dep_file=testdir/`echo test$ext | sed 's/\.[^.]*\$//'`.d
 
         $CCACHE_COMPILE -MD -c test.c -o testdir/test$ext
-        expect_stat 'cache hit (direct)' $((2 * i))
-        expect_stat 'cache miss' $((2 * i + 1))
+        hit=$((hit + 1))
+        expect_stat 'cache hit (direct)' $hit
+        expect_stat 'cache miss' $miss
         rm -f $dep_file
 
         $CCACHE_COMPILE -MD -c test.c -o testdir/test$ext
-        expect_stat 'cache hit (direct)' $((2 * i + 1))
-        expect_stat 'cache miss' $((2 * i + 1))
+        hit=$((hit + 1))
+        expect_stat 'cache hit (direct)' $hit
+        expect_stat 'cache miss' $miss
         expect_file_exists $dep_file
         if ! grep "test$ext:" $dep_file >/dev/null 2>&1; then
             test_failed "$dep_file does not contain \"test$ext:\""
@@ -152,13 +156,15 @@ EOF
 
         dep_target=foo.bar
         $CCACHE_COMPILE -MD -MQ $dep_target -c test.c -o testdir/test$ext
-        expect_stat 'cache hit (direct)' $((2 * i + 1))
-        expect_stat 'cache miss' $((2 * i + 2))
+        miss=$((miss + 1))
+        expect_stat 'cache hit (direct)' $hit
+        expect_stat 'cache miss' $miss
         rm -f $dep_target
 
         $CCACHE_COMPILE -MD -MQ $dep_target -c test.c -o testdir/test$ext
-        expect_stat 'cache hit (direct)' $((2 * i + 2))
-        expect_stat 'cache miss' $((2 * i + 2))
+        hit=$((hit + 1))
+        expect_stat 'cache hit (direct)' $hit
+        expect_stat 'cache miss' $miss
         expect_file_exists $dep_file
         if ! grep $dep_target $dep_file >/dev/null 2>&1; then
             test_failed "$dep_file does not contain $dep_target"
@@ -166,7 +172,7 @@ EOF
 
         i=$((i + 1))
     done
-    expect_stat 'files in cache' $((4 * i))
+    expect_stat 'files in cache' $((2*i + 2))
 
     # -------------------------------------------------------------------------
     TEST "-MMD for different source files"
@@ -224,6 +230,61 @@ EOF
         done
     done
 
+    # -------------------------------------------------------------------------
+    TEST "-MD: cache hits and miss and dependency"
+
+    hit=0
+    src=test1.c
+    touch $src
+    orig_dep=orig.d
+    for dir1 in build1 build2 dir1/dir2/dir3; do 
+        mkdir -p $dir1
+        for name in test1 obj1 random2; do
+            obj=$dir1/$name.o
+            dep=$(echo $obj | sed 's/\.o$/.d/')
+            $REAL_COMPILER -MD -c $src -o $obj
+            mv $dep $orig_dep
+            rm $obj
+
+            $CCACHE_COMPILE -MD -c $src -o $obj
+            expect_equal_files $dep $orig_dep
+            expect_stat 'cache hit (direct)' $hit
+            expect_stat 'cache miss' 1
+            hit=$((hit + 1))
+
+            rm $orig_dep
+        done
+        rm -rf $dir1
+    done
+
+    # -------------------------------------------------------------------------
+    TEST "-MMD: cache hits and miss and dependency"
+
+    hit=0
+    src=test2.c
+    touch $src
+    orig_dep=orig.d
+    for dir1 in build1 build2 dir1/dir2/dir3; do 
+        mkdir -p $dir1
+        for name in test2 obj1 obj2; do
+            obj=$dir1/$name.o
+            dep=$(echo $obj | sed 's/\.o$/.d/')
+            $REAL_COMPILER -MMD -c $src -o $obj
+            mv $dep $orig_dep
+            rm $obj
+
+            $CCACHE_COMPILE -MMD -c $src -o $obj
+            dep=$(echo $obj | sed 's/\.o$/.d/')
+            expect_file_content $dep "$obj: $src"
+            expect_stat 'cache hit (direct)' $hit
+            expect_stat 'cache miss' 1
+            hit=$((hit + 1))
+
+            rm $orig_dep
+        done
+        rm -rf $dir1
+    done
+
     # -------------------------------------------------------------------------
     TEST "Dependency file content"