From: Orgad Shaneh Date: Sat, 15 Oct 2022 18:09:36 +0000 (+0300) Subject: feat: Support auto depend mode for MSVC without /showIncludes (#1176) X-Git-Tag: v4.7~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bda468cf42988546cd84ab5a6f8e556cff29480a;p=thirdparty%2Fccache.git feat: Support auto depend mode for MSVC without /showIncludes (#1176) If MSVC is executed *without* /showIncludes, and ccache is configured with depend mode, add /showIncludes and strip the extra output from stdout. --- diff --git a/doc/MANUAL.adoc b/doc/MANUAL.adoc index 37e0226a1..e2ebf4084 100644 --- a/doc/MANUAL.adoc +++ b/doc/MANUAL.adoc @@ -1583,7 +1583,7 @@ The depend mode will be disabled if any of the following holds: * <> is false. * <> 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 diff --git a/src/Config.hpp b/src/Config.hpp index 6399253f7..18cf74a76 100644 --- a/src/Config.hpp +++ b/src/Config.hpp @@ -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; +} diff --git a/src/Context.hpp b/src/Context.hpp index 9d6084101..25b114097 100644 --- a/src/Context.hpp +++ b/src/Context.hpp @@ -118,6 +118,8 @@ public: std::unique_ptr 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); diff --git a/src/argprocessing.cpp b/src/argprocessing.cpp index e1ec11218..2b0603f95 100644 --- a/src/argprocessing.cpp +++ b/src/argprocessing.cpp @@ -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, diff --git a/src/ccache.cpp b/src/ccache.cpp index 6effb6487..5b8ce6566 100644 --- a/src/ccache.cpp +++ b/src/ccache.cpp @@ -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; } diff --git a/src/core/ResultRetriever.cpp b/src/core/ResultRetriever.cpp index bdefc19fe..484e1632a 100644 --- a/src/core/ResultRetriever.cpp +++ b/src/core/ResultRetriever.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -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 { diff --git a/src/core/ShowIncludesParser.cpp b/src/core/ShowIncludesParser.cpp index a25cf76a1..ca1b764c2 100644 --- a/src/core/ShowIncludesParser.cpp +++ b/src/core/ShowIncludesParser.cpp @@ -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 diff --git a/src/core/ShowIncludesParser.hpp b/src/core/ShowIncludesParser.hpp index a977cec09..a368d62b8 100644 --- a/src/core/ShowIncludesParser.hpp +++ b/src/core/ShowIncludesParser.hpp @@ -18,6 +18,8 @@ #pragma once +#include + #include #include @@ -28,4 +30,6 @@ namespace core::ShowIncludesParser { std::vector tokenize(std::string_view file_content, std::string_view prefix); +util::Bytes strip_includes(const Context& ctx, util::Bytes&& stdout_data); + } // namespace core::ShowIncludesParser diff --git a/unittest/test_core_ShowIncludesParser.cpp b/unittest/test_core_ShowIncludesParser.cpp index c3ba58c5a..2d3fc572e 100644 --- a/unittest/test_core_ShowIncludesParser.cpp +++ b/unittest/test_core_ShowIncludesParser.cpp @@ -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();