aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Parsons <cparsons@google.com>2022-05-17 15:08:55 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2022-05-17 15:08:55 +0000
commit30041e4cd15ce5f55a7b2809e771c61a92b985d1 (patch)
tree29a992ca91f0568604657087120ce846f29df337
parentf5a64fd445303624881dc16eddbd104e1d08a592 (diff)
parentb3dd6ea54b471469d46ad13d9ef0ee1de4bb7b7d (diff)
downloadninja-30041e4cd15ce5f55a7b2809e771c61a92b985d1.tar.gz
Merge "Set output mtime of phony edges to latest inputs"
-rw-r--r--src/graph.cc12
-rw-r--r--src/graph.h3
-rw-r--r--src/graph_test.cc37
3 files changed, 52 insertions, 0 deletions
diff --git a/src/graph.cc b/src/graph.cc
index b7a3c7c..682182e 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -49,6 +49,12 @@ bool Node::Stat(DiskInterface* disk_interface, string* err) {
}
}
+void Node::UpdatePhonyMtime(TimeStamp mtime) {
+ if (!exists()) {
+ mtime_ = std::max(mtime_, mtime);
+ }
+}
+
bool Node::LStat(
DiskInterface* disk_interface, bool* is_dir, bool* is_symlink, string* err) {
assert(in_edge() != nullptr);
@@ -427,6 +433,12 @@ bool DependencyScan::RecomputeOutputsDirty(Edge* edge, Node* most_recent_input,
return true;
}
}
+
+ // Update the mtime with the newest input. Dependents can thus call mtime()
+ // on the fake node and get the latest mtime of the dependencies
+ if (most_recent_input) {
+ (*o)->UpdatePhonyMtime(most_recent_input->mtime());
+ }
continue;
}
if (RecomputeOutputDirty(edge, most_recent_input, command_hash, *o)) {
diff --git a/src/graph.h b/src/graph.h
index 3472c07..33a42fc 100644
--- a/src/graph.h
+++ b/src/graph.h
@@ -119,6 +119,9 @@ struct Node {
/// Only use when lstat() is desired (output files)
bool LStat(DiskInterface* disk_interface, bool* is_dir, bool* is_symlink, string* err);
+ /// If the file doesn't exist, set the mtime_ from its dependencies
+ void UpdatePhonyMtime(TimeStamp mtime);
+
/// Return false on error.
bool StatIfNecessary(DiskInterface* disk_interface, string* err) {
if (status_known())
diff --git a/src/graph_test.cc b/src/graph_test.cc
index de39980..427334f 100644
--- a/src/graph_test.cc
+++ b/src/graph_test.cc
@@ -1189,3 +1189,40 @@ TEST_F(GraphTest, GetAllPathsInCycles) {
std::vector<std::string> expected_path = {"f", "d", "c", "b", "a"};
ASSERT_TRUE(paths_f_to_a[0] == expected_path);
}
+
+// Check that phony's dependencies' mtimes are propagated.
+TEST_F(GraphTest, PhonyDepsMtimes) {
+ string err;
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule touch\n"
+" command = touch $out\n"
+"build in_ph: phony in1\n"
+"build out1: touch in_ph\n"
+));
+ fs_.Create("in1", "");
+ fs_.Create("out1", "");
+ Node* out1 = GetNode("out1");
+ Node* in1 = GetNode("in1");
+
+ EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out1"), NULL, &err));
+ EXPECT_TRUE(!out1->dirty());
+
+ // Get the mtime of out1
+ ASSERT_TRUE(in1->Stat(&fs_, &err));
+ ASSERT_TRUE(out1->Stat(&fs_, &err));
+ TimeStamp out1Mtime1 = out1->mtime();
+ TimeStamp in1Mtime1 = in1->mtime();
+
+ // Touch in1. This should cause out1 to be dirty
+ state_.Reset();
+ fs_.Tick();
+ fs_.Create("in1", "");
+
+ ASSERT_TRUE(in1->Stat(&fs_, &err));
+ EXPECT_GT(in1->mtime(), in1Mtime1);
+
+ EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out1"), NULL, &err));
+ EXPECT_GT(in1->mtime(), in1Mtime1);
+ EXPECT_EQ(out1->mtime(), out1Mtime1);
+ EXPECT_TRUE(out1->dirty());
+}