From: Joel Rosdahl Date: Thu, 28 Jul 2022 08:58:05 +0000 (+0200) Subject: feat: Improve handling of dependency files X-Git-Tag: v4.7~137 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fec405539bca90ebd0992ae6606bd10eec3a64da;p=thirdparty%2Fccache.git feat: Improve handling of dependency files - 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. --- diff --git a/src/ArgsInfo.hpp b/src/ArgsInfo.hpp index 343fedc6e..94a7fe428 100644 --- a/src/ArgsInfo.hpp +++ b/src/ArgsInfo.hpp @@ -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 #include #include @@ -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 dependency_target; // Is the compiler being asked to output coverage? bool generating_coverage = false; diff --git a/src/Depfile.cpp b/src/Depfile.cpp index 7ceccc7e7..14ce86308 100644 --- a/src/Depfile.cpp +++ b/src/Depfile.cpp @@ -60,7 +60,7 @@ escape_filename(std::string_view filename) } std::optional -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 { diff --git a/src/Depfile.hpp b/src/Depfile.hpp index fc453c310..125746264 100644 --- a/src/Depfile.hpp +++ b/src/Depfile.hpp @@ -31,9 +31,12 @@ class Hash; namespace Depfile { std::string escape_filename(std::string_view filename); -std::optional rewrite_paths(const Context& ctx, - const std::string& file_content); + +std::optional +rewrite_source_paths(const Context& ctx, const std::string& file_content); + void make_paths_relative_in_output_dep(const Context& ctx); + std::vector tokenize(std::string_view file_content); } // namespace Depfile diff --git a/src/ResultRetriever.cpp b/src/ResultRetriever.cpp index 6e84c82bc..c3f0f51cf 100644 --- a/src/ResultRetriever.cpp +++ b/src/ResultRetriever.cpp @@ -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; } } diff --git a/src/ResultRetriever.hpp b/src/ResultRetriever.hpp index bdd4f893b..a114698eb 100644 --- a/src/ResultRetriever.hpp +++ b/src/ResultRetriever.hpp @@ -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(); }; diff --git a/src/argprocessing.cpp b/src/argprocessing.cpp index 08c41e91f..daf3b5ff0 100644 --- a/src/argprocessing.cpp +++ b/src/argprocessing.cpp @@ -25,6 +25,7 @@ #include "fmtmacros.hpp" #include "language.hpp" +#include #include #include @@ -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 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 . - // 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) { diff --git a/src/ccache.cpp b/src/ccache.cpp index f436da6c4..17c0ed0ca 100644 --- a/src/ccache.cpp +++ b/src/ccache.cpp @@ -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 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> +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 option; + std::optional 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) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8f80e20cd..1cacb26d4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -30,7 +30,6 @@ addtest(cpp1) addtest(debug_prefix_map) addtest(depend) addtest(direct) -addtest(direct_gcc) addtest(fileclone) addtest(hardlink) addtest(inode_cache) diff --git a/test/run b/test/run index d5b338957..bc13b0ef3 100755 --- 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 diff --git a/test/suites/base.bash b/test/suites/base.bash index c7b6da88a..c7cf998bb 100644 --- a/test/suites/base.bash +++ b/test/suites/base.bash @@ -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" diff --git a/test/suites/basedir.bash b/test/suites/basedir.bash index b02fcb6a8..5486b1e50 100644 --- a/test/suites/basedir.bash +++ b/test/suites/basedir.bash @@ -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 /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.c -// test.c -#include "test1.h" -#include "test2.h" -EOF - cat <test1.h -#include "test3.h" -int test1; -EOF - cat <test2.h -int test2; -EOF - cat <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 -} diff --git a/unittest/test_Depfile.cpp b/unittest/test_Depfile.cpp index c4f7e3530..3bbb1415b 100644 --- a/unittest/test_Depfile.cpp +++ b/unittest/test_Depfile.cpp @@ -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); } diff --git a/unittest/test_argprocessing.cpp b/unittest/test_argprocessing.cpp index f5e861930..5de5eb2b0 100644 --- a/unittest/test_argprocessing.cpp +++ b/unittest/test_argprocessing.cpp @@ -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");