From 2ab31632ec4edbaa4804337484674e6293b1e7a5 Mon Sep 17 00:00:00 2001 From: Deepak Yadav Date: Sat, 25 Jul 2020 20:19:33 +0530 Subject: [PATCH] Share cache for different object file names with -MD/-MMD (#592) --- src/ArgsInfo.hpp | 9 +++++ src/ResultRetriever.cpp | 20 +++++++++++ src/ResultRetriever.hpp | 1 + src/argprocessing.cpp | 14 ++++---- src/ccache.cpp | 3 +- test/suites/base.bash | 3 -- test/suites/direct.bash | 79 ++++++++++++++++++++++++++++++++++++----- 7 files changed, 110 insertions(+), 19 deletions(-) diff --git a/src/ArgsInfo.hpp b/src/ArgsInfo.hpp index 497ba2afd..54f7a31c5 100644 --- a/src/ArgsInfo.hpp +++ b/src/ArgsInfo.hpp @@ -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; diff --git a/src/ResultRetriever.cpp b/src/ResultRetriever.cpp index 81386c60e..c13074aca 100644 --- a/src/ResultRetriever.cpp +++ b/src/ResultRetriever.cpp @@ -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(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 diff --git a/src/ResultRetriever.hpp b/src/ResultRetriever.hpp index d15d93506..45b3d4d8c 100644 --- a/src/ResultRetriever.hpp +++ b/src/ResultRetriever.hpp @@ -45,4 +45,5 @@ private: Fd m_dest_fd; std::string m_dest_path; std::string m_stderr_text; + bool m_first; }; diff --git a/src/argprocessing.cpp b/src/argprocessing.cpp index e072017ea..5ac3391fa 100644 --- a/src/argprocessing.cpp +++ b/src/argprocessing.cpp @@ -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 diff --git a/src/ccache.cpp b/src/ccache.cpp index 70d0eaa51..baf0da66c 100644 --- a/src/ccache.cpp +++ b/src/ccache.cpp @@ -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. // diff --git a/test/suites/base.bash b/test/suites/base.bash index 0c680eb2b..53afdca2c 100644 --- a/test/suites/base.bash +++ b/test/suites/base.bash @@ -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 diff --git a/test/suites/direct.bash b/test/suites/direct.bash index ad601791c..688048259 100644 --- a/test/suites/direct.bash +++ b/test/suites/direct.bash @@ -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" -- 2.47.3