// 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;
std::string dest_path;
m_dest_file_type = file_type;
+ m_first = true;
switch (file_type) {
case FileType::object:
if (m_dest_file_type == FileType::stderr_output) {
m_stderr_text.append(reinterpret_cast<const char*>(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
Fd m_dest_fd;
std::string m_dest_path;
std::string m_stderr_text;
+ bool m_first;
};
// 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;
// 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;
}
}
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
// 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.
}
}
+ 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);
}
}
- 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
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.
//
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
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
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:\""
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"
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"
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"