]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
feat: Support auto depend mode for MSVC without /showIncludes (#1176)
authorOrgad Shaneh <orgad.shaneh@audiocodes.com>
Sat, 15 Oct 2022 18:09:36 +0000 (21:09 +0300)
committerGitHub <noreply@github.com>
Sat, 15 Oct 2022 18:09:36 +0000 (20:09 +0200)
If MSVC is executed *without* /showIncludes, and ccache is configured with
depend mode, add /showIncludes and strip the extra output from stdout.

doc/MANUAL.adoc
src/Config.hpp
src/Context.hpp
src/argprocessing.cpp
src/ccache.cpp
src/core/ResultRetriever.cpp
src/core/ShowIncludesParser.cpp
src/core/ShowIncludesParser.hpp
unittest/test_core_ShowIncludesParser.cpp

index 37e0226a1ccf64ecfc5b48ac131c3b308b45370f..e2ebf4084e224a8a5b2475fc95690aec3425eeaa 100644 (file)
@@ -1583,7 +1583,7 @@ The depend mode will be disabled if any of the following holds:
 * <<config_depend_mode,*depend_mode*>> is false.
 * <<config_run_second_cpp,*run_second_cpp*>> is false.
 * The compiler is not generating dependencies using `-MD` or `-MMD` (for MSVC,
-  /showIncludes).
+  /showIncludes is added automatically if not specified by the user).
 
 
 == Handling of newly created header files
index 6399253f77eb3112d9fa74c1797ff5753fba5382..18cf74a762f3bf48a4b263ff7a835bcd8c5d71f8 100644 (file)
@@ -120,6 +120,7 @@ public:
   void set_max_size(uint64_t value);
   void set_run_second_cpp(bool value);
   void set_temporary_dir(const std::string& value);
+  void set_msvc_dep_prefix(const std::string& value);
 
   // Where to write configuration changes.
   const std::string& config_path() const;
@@ -593,3 +594,9 @@ Config::set_temporary_dir(const std::string& value)
 {
   m_temporary_dir = value;
 }
+
+inline void
+Config::set_msvc_dep_prefix(const std::string& value)
+{
+  m_msvc_dep_prefix = value;
+}
index 9d60841015943f249d3b86941908e9cfac755814..25b114097af664e04c472868b34f19131b5310b7 100644 (file)
@@ -118,6 +118,8 @@ public:
   std::unique_ptr<MiniTrace> mini_trace;
 #endif
 
+  bool auto_depend_mode = false;
+
   // Register a temporary file to remove at program exit.
   void register_pending_tmp_file(const std::string& path);
 
index e1ec112185b21de1e28ed9992c0c2c79e59a590a..2b0603f954a9432e0d8340a9f1c232ea32a290c6 100644 (file)
@@ -1499,6 +1499,13 @@ process_args(Context& ctx)
     }
   }
 
+  if (ctx.config.depend_mode() && !args_info.generating_includes
+      && ctx.config.compiler_type() == CompilerType::msvc) {
+    ctx.auto_depend_mode = true;
+    args_info.generating_includes = true;
+    args_info.depend_extra_args.push_back("-showIncludes");
+  }
+
   return {
     preprocessor_args,
     extra_args_to_hash,
index 6effb648777b1b84b3da23f2b8fb5b43808841a0..5b8ce65663e8a1462f4ff619f6709f1c886b3e84 100644 (file)
@@ -1075,7 +1075,10 @@ to_cache(Context& ctx,
     Util::send_to_fd(
       ctx, util::to_string_view(result->stderr_data), STDERR_FILENO);
     Util::send_to_fd(
-      ctx, util::to_string_view(result->stdout_data), STDOUT_FILENO);
+      ctx,
+      util::to_string_view(core::ShowIncludesParser::strip_includes(
+        ctx, std::move(result->stdout_data))),
+      STDOUT_FILENO);
 
     auto failure = Failure(Statistic::compile_failed);
     failure.set_exit_code(result->exit_status);
@@ -1134,7 +1137,10 @@ to_cache(Context& ctx,
     ctx, util::to_string_view(result->stderr_data), STDERR_FILENO);
   // Send stdout after stderr, it makes the output clearer with MSVC.
   Util::send_to_fd(
-    ctx, util::to_string_view(result->stdout_data), STDOUT_FILENO);
+    ctx,
+    util::to_string_view(core::ShowIncludesParser::strip_includes(
+      ctx, std::move(result->stdout_data))),
+    STDOUT_FILENO);
 
   return *result_key;
 }
index bdefc19fee2363f77166cd178151b91ed650cf98..484e1632a61a902ab556d4efd0f262de3f206c02 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <Context.hpp>
 #include <Stat.hpp>
+#include <core/ShowIncludesParser.hpp>
 #include <core/exceptions.hpp>
 #include <core/wincompat.hpp>
 #include <fmtmacros.hpp>
@@ -61,7 +62,10 @@ ResultRetriever::on_embedded_file(uint8_t file_number,
       data.size());
 
   if (file_type == FileType::stdout_output) {
-    Util::send_to_fd(m_ctx, util::to_string_view(data), STDOUT_FILENO);
+    Util::send_to_fd(
+      m_ctx,
+      util::to_string_view(ShowIncludesParser::strip_includes(m_ctx, data)),
+      STDOUT_FILENO);
   } else if (file_type == FileType::stderr_output) {
     Util::send_to_fd(m_ctx, util::to_string_view(data), STDERR_FILENO);
   } else {
index a25cf76a1a59ffa2b45b6d2d6d41e0d82e782a43..ca1b764c2b3fed61fc432748538715e44dd24c29 100644 (file)
@@ -49,4 +49,28 @@ tokenize(std::string_view file_content, std::string_view prefix)
   return result;
 }
 
+util::Bytes
+strip_includes(const Context& ctx, util::Bytes&& stdout_data)
+{
+  using util::Tokenizer;
+  using Mode = Tokenizer::Mode;
+  using IncludeDelimiter = Tokenizer::IncludeDelimiter;
+
+  if (stdout_data.empty() || !ctx.auto_depend_mode
+      || ctx.config.compiler_type() != CompilerType::msvc) {
+    return std::move(stdout_data);
+  }
+
+  std::string new_stdout_text;
+  for (const auto line : Tokenizer(util::to_string_view(stdout_data),
+                                   "\n",
+                                   Mode::include_empty,
+                                   IncludeDelimiter::yes)) {
+    if (!util::starts_with(line, ctx.config.msvc_dep_prefix())) {
+      new_stdout_text.append(line.data(), line.length());
+    }
+  }
+  return util::Bytes(new_stdout_text.data(), new_stdout_text.size());
+}
+
 } // namespace core::ShowIncludesParser
index a977cec09dd21b5242b20cb05e9ba000108e53bc..a368d62b814b4537e8c1bbd3ac1bccc5c833f00a 100644 (file)
@@ -18,6 +18,8 @@
 
 #pragma once
 
+#include <util/Bytes.hpp>
+
 #include <string_view>
 #include <vector>
 
@@ -28,4 +30,6 @@ namespace core::ShowIncludesParser {
 std::vector<std::string_view> tokenize(std::string_view file_content,
                                        std::string_view prefix);
 
+util::Bytes strip_includes(const Context& ctx, util::Bytes&& stdout_data);
+
 } // namespace core::ShowIncludesParser
index c3ba58c5a902c2194aed08c31101a457178cc8b5..2d3fc572eef8b6bb95558302f6725ab8b0d524fc 100644 (file)
@@ -16,7 +16,9 @@
 // this program; if not, write to the Free Software Foundation, Inc., 51
 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
+#include "../src/Context.hpp"
 #include "../src/core/ShowIncludesParser.hpp"
+#include "../src/util/string.hpp"
 #include "TestUtil.hpp"
 
 #include "third_party/doctest.h"
@@ -93,4 +95,80 @@ Just a line with custom in the middle)";
   }
 }
 
+TEST_CASE("ShowIncludesParser::strip_includes")
+{
+  Context ctx;
+  const util::Bytes input = util::to_span(
+    "First\n"
+    "Note: including file: foo\n"
+    "Second\n");
+
+  SUBCASE("empty output")
+  {
+    const util::Bytes result =
+      core::ShowIncludesParser::strip_includes(ctx, {});
+    CHECK(result.size() == 0);
+  }
+
+  SUBCASE("feature disabled")
+  {
+    const util::Bytes result =
+      core::ShowIncludesParser::strip_includes(ctx, util::Bytes(input));
+    CHECK(result == input);
+  }
+
+  ctx.auto_depend_mode = true;
+
+  SUBCASE("wrong compiler")
+  {
+    const util::Bytes result =
+      core::ShowIncludesParser::strip_includes(ctx, util::Bytes(input));
+    CHECK(result == input);
+  }
+
+  ctx.config.set_compiler_type(CompilerType::msvc);
+
+  SUBCASE("Simple output")
+  {
+    const util::Bytes result =
+      core::ShowIncludesParser::strip_includes(ctx, util::Bytes(input));
+    CHECK(result == util::to_span("First\nSecond\n"));
+  }
+
+  SUBCASE("Empty lines")
+  {
+    const util::Bytes result = core::ShowIncludesParser::strip_includes(
+      ctx,
+      util::to_span("First\n"
+                    "\n"
+                    "Note: including file: foo\n"
+                    "\n"
+                    "Second\n"
+                    "\n"));
+    CHECK(result == util::to_span("First\n\n\nSecond\n\n"));
+  }
+
+  SUBCASE("CRLF")
+  {
+    const util::Bytes result = core::ShowIncludesParser::strip_includes(
+      ctx,
+      util::to_span("First\r\n"
+                    "Note: including file: foo\r\n"
+                    "Second\r\n"));
+    CHECK(result == util::to_span("First\r\nSecond\r\n"));
+  }
+
+  SUBCASE("Custom prefix")
+  {
+    ctx.config.set_msvc_dep_prefix("custom");
+    const util::Bytes result = core::ShowIncludesParser::strip_includes(
+      ctx,
+      util::to_span("First\n"
+                    "custom: including file: foo\n"
+                    "Second\n"
+                    "Third custom line\n"));
+    CHECK(result == util::to_span("First\nSecond\nThird custom line\n"));
+  }
+}
+
 TEST_SUITE_END();