-// 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.
//
#include "Args.hpp"
+#include <optional>
#include <string>
#include <vector>
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.
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).
// 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<std::string> dependency_target;
// Is the compiler being asked to output coverage?
bool generating_coverage = false;
}
std::optional<std::string>
-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);
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",
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);
} else {
adjusted_file_content.append(token.begin(), token.end());
}
+
+ if (tokens[i].back() == ':') {
+ seen_target_token = true;
+ }
}
}
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 {
namespace Depfile {
std::string escape_filename(std::string_view filename);
-std::optional<std::string> rewrite_paths(const Context& ctx,
- const std::string& file_content);
+
+std::optional<std::string>
+rewrite_source_paths(const Context& ctx, const std::string& file_content);
+
void make_paths_relative_in_output_dep(const Context& ctx);
+
std::vector<std::string> tokenize(std::string_view file_content);
} // namespace Depfile
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)
{
}
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;
}
}
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,
// 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();
};
#include "fmtmacros.hpp"
#include "language.hpp"
+#include <Depfile.hpp>
#include <core/wincompat.hpp>
#include <util/string.hpp>
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;
bool found_directives_only = false;
bool found_rewrite_includes = false;
std::optional<std::string> 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;
// 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;
}
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;
}
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;
}
// 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);
// -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");
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) {
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;
}
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")
&& (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()) {
}
// 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);
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 <http://gcc.gnu.org/onlinedocs/cpp/Environment-Variables.html>.
- // 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
}
}
+ // 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 -");
}
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.
}
#endif
- handle_dependency_environment_variables(ctx, state);
-
if (args_info.input_file.empty()) {
LOG_RAW("No input file found");
return Statistic::no_input_file;
|| 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
}
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) {
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 {
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<void, Failure>
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
});
}
+static std::tuple<std::optional<std::string_view>,
+ std::optional<std::string_view>>
+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.
}
}
- // 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<std::string_view> option;
+ std::optional<std::string_view> 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);
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;
}
}
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) {
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)) {
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) {
addtest(debug_prefix_map)
addtest(depend)
addtest(direct)
-addtest(direct_gcc)
addtest(fileclone)
addtest(hardlink)
addtest(inode_cache)
fi
done < <(compgen -e)
+ unset DEPENDENCIES_OUTPUT
unset GCC_COLORS
+ unset SUNPRO_DEPENDENCIES
unset TERM
unset XDG_CACHE_HOME
unset XDG_CONFIG_HOME
$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"
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"
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
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 <test.d
cd ..
expect_stat direct_cache_hit 1
expect_stat preprocessed_cache_hit 0
expect_stat cache_miss 1
+
+ # -------------------------------------------------------------------------
+ TEST "Object token path in dependency file"
+
+ cd dir1
+
+ CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -MMD -I$(pwd)/include -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 "test.o:*"
+
+ CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -MMD -I$(pwd)/include -c src/test.c -o test.o
+ expect_stat direct_cache_hit 1
+ expect_stat preprocessed_cache_hit 0
+ expect_stat cache_miss 1
+ expect_contains test.d test.o:
+ expect_content_pattern test.d "test.o:*"
+
+ CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -MMD -I$(pwd)/include -c src/test.c -o $(pwd)/test.o
+ expect_stat direct_cache_hit 2
+ expect_stat preprocessed_cache_hit 0
+ expect_stat cache_miss 1
+ expect_contains test.d test.o:
+ expect_content_pattern test.d "$(pwd)/test.o:*"
+
+ CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -MMD -I$(pwd)/include -c $(pwd)/src/test.c
+ expect_stat direct_cache_hit 3
+ expect_stat preprocessed_cache_hit 0
+ expect_stat cache_miss 1
+ expect_contains test.d test.o:
+ expect_content_pattern test.d "test.o:*"
}
expect_stat cache_miss 2
# -------------------------------------------------------------------------
- TEST "Calculation of dependency file names"
-
- i=0
for ext in .o .obj "" . .foo.bar; do
- rm -rf testdir
- mkdir testdir
+ TEST "Calculation of dependency file names, ext=\"${ext}\""
+ mkdir testdir
dep_file=testdir/`echo test$ext | sed 's/\.[^.]*\$//'`.d
- $CCACHE_COMPILE -MD -c test.c -o testdir/test$ext
- expect_stat direct_cache_hit $((3 * i))
- expect_stat cache_miss $((i + 1))
+ # No -MQ/-MT:
+ $CCACHE_COMPILE -MMD -c test.c -o testdir/test$ext
+ expect_stat direct_cache_hit 0
+ expect_stat cache_miss 1
+ expect_content_pattern "${dep_file}" "testdir/test${ext}:*"
rm -f $dep_file
- $CCACHE_COMPILE -MD -c test.c -o testdir/test$ext
- expect_stat direct_cache_hit $((3 * i + 1))
- expect_stat cache_miss $((i + 1))
- expect_exists $dep_file
- if ! grep "test$ext:" $dep_file >/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"
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
# -----------------------------------------------------------------
$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"
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.d)
+ expected_1='$$mq1 $mt1: test.c test3.h'
+ expected_2='$mt1 $$mq1: test.c test3.h'
+ if [[ $content != "${expected_1}" && $content != "${expected_2}" ]]; then
+ test_failed "Bad content of test.d\nExpected: ${expected_1} or ${expected_2}\nActual: ${content}"
+ fi
+
+ $CCACHE_COMPILE -MMD -MQ '$mq2' -MT '$mt2' -c test.c
+ expect_stat direct_cache_hit 4 # New dependency targets but still a cache hit
+ expect_stat cache_miss 4
+ content=$(<test.d)
+ expected_1='$$mq2 $mt2: test.c test3.h'
+ expected_2='$mt2 $$mq2: test.c test3.h'
+ if [[ $content != "${expected_1}" && $content != "${expected_2}" ]]; then
+ test_failed "Bad content of test.d\nExpected: ${expected_1} or ${expected_2}\nActual: ${content}"
+ fi
+
+ # -MQ -MT -Wp,-MMD,
+
+ $CCACHE_COMPILE -MMD -MQ '$mq1' -MT '$mt1' -Wp,-MMD,foo.d -c test.c
+ expect_stat direct_cache_hit 4
+ expect_stat cache_miss 5
+ content=$(<foo.d)
+ expected_1='$$mq1 $mt1: test.c test3.h'
+ expected_2='$mt1 $$mq1: test.c test3.h'
+ if [[ $content != "${expected_1}" && $content != "${expected_2}" ]]; then
+ test_failed "Bad content of foo.d\nExpected: ${expected_1} or ${expected_2}\nActual: ${content}"
+ fi
+
+ $CCACHE_COMPILE -MMD -MQ '$mq2' -MT '$mt2' -Wp,-MMD,foo.d -c test.c
+ expect_stat direct_cache_hit 5 # New dependency targets but still a cache hit
+ expect_stat cache_miss 5
+ content=$(<foo.d)
+ expected_1='$$mq2 $mt2: test.c test3.h'
+ expected_2='$mt2 $$mq2: test.c test3.h'
+ if [[ $content != "${expected_1}" && $content != "${expected_2}" ]]; then
+ test_failed "Bad content of test.d\nExpected: ${expected_1} or ${expected_2}\nActual: ${content}"
+ fi
+
# -------------------------------------------------------------------------
TEST "stderr from both preprocessor and compiler"
+++ /dev/null
-SUITE_direct_gcc_PROBE() {
- if [[ "${COMPILER_TYPE_GCC}" != "true" ]]; then
- echo "Skipping GCC only test cases"
- fi
-}
-
-SUITE_direct_gcc_SETUP() {
- unset CCACHE_NODIRECT
-
- cat <<EOF >test.c
-// test.c
-#include "test1.h"
-#include "test2.h"
-EOF
- cat <<EOF >test1.h
-#include "test3.h"
-int test1;
-EOF
- cat <<EOF >test2.h
-int test2;
-EOF
- cat <<EOF >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
-}
-// 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.
//
CHECK(Depfile::escape_filename("foo$bar") == "foo$$bar");
}
-TEST_CASE("Depfile::rewrite_paths")
+TEST_CASE("Depfile::rewrite_source_paths")
{
Context ctx;
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);
}
{
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", "");
{
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", "");
" -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");
" -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");