summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2011-01-08 17:44:15 (GMT)
committerEvan Martin <martine@danga.com>2011-01-08 17:44:15 (GMT)
commit0a186ab0cbcd2015d2cf9afd8460c7b60e4bcbdd (patch)
tree65e698b8e86a5c1336bad9234cda326ac23ab330 /src
parent83056869b618a27c0b3d8ec86e15e9f15777c172 (diff)
downloadNinja-0a186ab0cbcd2015d2cf9afd8460c7b60e4bcbdd.zip
Ninja-0a186ab0cbcd2015d2cf9afd8460c7b60e4bcbdd.tar.gz
Ninja-0a186ab0cbcd2015d2cf9afd8460c7b60e4bcbdd.tar.bz2
split out graph into its own header
Diffstat (limited to 'src')
-rw-r--r--src/build.cc1
-rw-r--r--src/build_log.cc1
-rw-r--r--src/graph.cc201
-rw-r--r--src/graph.h109
-rw-r--r--src/graphviz.h2
-rw-r--r--src/ninja.cc3
-rw-r--r--src/ninja.h109
-rw-r--r--src/ninja_jumble.cc222
-rw-r--r--src/ninja_test.cc6
-rw-r--r--src/parsers.cc5
-rw-r--r--src/parsers_test.cc1
-rw-r--r--src/test.h5
12 files changed, 349 insertions, 316 deletions
diff --git a/src/build.cc b/src/build.cc
index 8ffbc7c..0aa1d10 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -3,6 +3,7 @@
#include <stdio.h>
#include "build_log.h"
+#include "graph.h"
#include "ninja.h"
#include "subprocess.h"
diff --git a/src/build_log.cc b/src/build_log.cc
index 666b80b..53fca4e 100644
--- a/src/build_log.cc
+++ b/src/build_log.cc
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <string.h>
+#include "graph.h"
#include "ninja.h"
// Implementation details:
diff --git a/src/graph.cc b/src/graph.cc
new file mode 100644
index 0000000..22283a5
--- /dev/null
+++ b/src/graph.cc
@@ -0,0 +1,201 @@
+#include "graph.h"
+
+#include <stdio.h>
+
+#include "build_log.h"
+#include "ninja.h"
+#include "parsers.h"
+
+void FileStat::Touch(int mtime) {
+ mtime_ = mtime;
+ if (node_)
+ node_->MarkDirty();
+}
+
+bool FileStat::Stat(DiskInterface* disk_interface) {
+ mtime_ = disk_interface->Stat(path_);
+ return mtime_ > 0;
+}
+
+void Node::MarkDirty() {
+ if (dirty_)
+ return; // We already know.
+
+ dirty_ = true;
+ MarkDependentsDirty();
+}
+
+void Node::MarkDependentsDirty() {
+ for (vector<Edge*>::iterator i = out_edges_.begin(); i != out_edges_.end(); ++i)
+ (*i)->MarkDirty(this);
+}
+
+bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface,
+ string* err) {
+ bool dirty = false;
+
+ if (!rule_->depfile_.empty()) {
+ if (!LoadDepFile(state, disk_interface, err))
+ return false;
+ }
+
+ time_t most_recent_input = 1;
+ for (vector<Node*>::iterator i = inputs_.begin(); i != inputs_.end(); ++i) {
+ if ((*i)->file_->StatIfNecessary(disk_interface)) {
+ if (Edge* edge = (*i)->in_edge_) {
+ if (!edge->RecomputeDirty(state, disk_interface, err))
+ return false;
+ } else {
+ // This input has no in-edge; it is dirty if it is missing.
+ // But it's ok for implicit deps to be missing.
+ if (!is_implicit(i - inputs_.begin()))
+ (*i)->dirty_ = !(*i)->file_->exists();
+ }
+ }
+
+ if (is_order_only(i - inputs_.begin())) {
+ // Order-only deps only make us dirty if they're missing.
+ if (!(*i)->file_->exists())
+ dirty = true;
+ continue;
+ }
+
+ // If a regular input is dirty (or missing), we're dirty.
+ // Otherwise consider mtime.
+ if ((*i)->dirty_) {
+ dirty = true;
+ } else {
+ if ((*i)->file_->mtime_ > most_recent_input)
+ most_recent_input = (*i)->file_->mtime_;
+ }
+ }
+
+ string command = EvaluateCommand();
+
+ assert(!outputs_.empty());
+ for (vector<Node*>::iterator i = outputs_.begin(); i != outputs_.end(); ++i) {
+ // We may have other outputs, that our input-recursive traversal hasn't hit
+ // yet (or never will). Stat them if we haven't already.
+ (*i)->file_->StatIfNecessary(disk_interface);
+
+ // Output is dirty if we're dirty, we're missing the output,
+ // or if it's older than the most recent input mtime.
+ if (dirty || !(*i)->file_->exists() ||
+ (*i)->file_->mtime_ < most_recent_input) {
+ (*i)->dirty_ = true;
+ } else {
+ // May also be dirty due to the command changing since the last build.
+ BuildLog::LogEntry* entry;
+ if (state->build_log_ &&
+ (entry = state->build_log_->LookupByOutput((*i)->file_->path_))) {
+ if (command != entry->command)
+ (*i)->dirty_ = true;
+ }
+ }
+ }
+ return true;
+}
+
+void Edge::MarkDirty(Node* node) {
+ if (rule_ == &State::kPhonyRule)
+ return;
+
+ vector<Node*>::iterator i = find(inputs_.begin(), inputs_.end(), node);
+ if (i == inputs_.end())
+ return;
+ if (i - inputs_.begin() >= ((int)inputs_.size()) - order_only_deps_)
+ return; // Order-only deps don't cause us to become dirty.
+ for (i = outputs_.begin(); i != outputs_.end(); ++i)
+ (*i)->MarkDirty();
+}
+
+struct EdgeEnv : public Env {
+ EdgeEnv(Edge* edge) : edge_(edge) {}
+ virtual string LookupVariable(const string& var) {
+ string result;
+ if (var == "in") {
+ int explicit_deps = edge_->inputs_.size() - edge_->implicit_deps_ -
+ edge_->order_only_deps_;
+ for (vector<Node*>::iterator i = edge_->inputs_.begin();
+ i != edge_->inputs_.end() && explicit_deps; ++i, --explicit_deps) {
+ if (!result.empty())
+ result.push_back(' ');
+ result.append((*i)->file_->path_);
+ }
+ } else if (var == "out") {
+ result = edge_->outputs_[0]->file_->path_;
+ } else if (edge_->env_) {
+ return edge_->env_->LookupVariable(var);
+ }
+ return result;
+ }
+ Edge* edge_;
+};
+
+string Edge::EvaluateCommand() {
+ EdgeEnv env(this);
+ return rule_->command_.Evaluate(&env);
+}
+
+string Edge::GetDescription() {
+ EdgeEnv env(this);
+ return rule_->description_.Evaluate(&env);
+}
+
+bool Edge::LoadDepFile(State* state, DiskInterface* disk_interface, string* err) {
+ EdgeEnv env(this);
+ string path = rule_->depfile_.Evaluate(&env);
+
+ string content = disk_interface->ReadFile(path, err);
+ if (!err->empty())
+ return false;
+ if (content.empty())
+ return true;
+
+ MakefileParser makefile;
+ if (!makefile.Parse(content, err))
+ return false;
+
+ // Check that this depfile matches our output.
+ if (outputs_.size() != 1) {
+ *err = "expected only one output";
+ return false;
+ }
+ if (outputs_[0]->file_->path_ != makefile.out_) {
+ *err = "expected makefile to mention '" + outputs_[0]->file_->path_ + "', "
+ "got '" + makefile.out_ + "'";
+ return false;
+ }
+
+ // Add all its in-edges.
+ for (vector<string>::iterator i = makefile.ins_.begin();
+ i != makefile.ins_.end(); ++i) {
+ Node* node = state->GetNode(*i);
+ for (vector<Node*>::iterator j = inputs_.begin(); j != inputs_.end(); ++j) {
+ if (*j == node) {
+ node = NULL;
+ break;
+ }
+ }
+ if (node) {
+ inputs_.insert(inputs_.end() - order_only_deps_, node);
+ node->out_edges_.push_back(this);
+ ++implicit_deps_;
+ }
+ }
+
+ return true;
+}
+
+void Edge::Dump() {
+ printf("[ ");
+ for (vector<Node*>::iterator i = inputs_.begin(); i != inputs_.end(); ++i) {
+ printf("%s ", (*i)->file_->path_.c_str());
+ }
+ printf("--%s-> ", rule_->name_.c_str());
+ for (vector<Node*>::iterator i = outputs_.begin(); i != outputs_.end(); ++i) {
+ printf("%s ", (*i)->file_->path_.c_str());
+ }
+ printf("]\n");
+}
+
diff --git a/src/graph.h b/src/graph.h
new file mode 100644
index 0000000..3f46db4
--- /dev/null
+++ b/src/graph.h
@@ -0,0 +1,109 @@
+#ifndef NINJA_GRAPH_H_
+#define NINJA_GRAPH_H_
+
+#include <string>
+#include <vector>
+using namespace std;
+
+#include "eval_env.h"
+
+struct DiskInterface;
+
+struct Node;
+struct FileStat {
+ FileStat(const string& path) : path_(path), mtime_(-1), node_(NULL) {}
+ void Touch(int mtime);
+ // Return true if the file exists (mtime_ got a value).
+ bool Stat(DiskInterface* disk_interface);
+
+ // Return true if we needed to stat.
+ bool StatIfNecessary(DiskInterface* disk_interface) {
+ if (status_known())
+ return false;
+ Stat(disk_interface);
+ return true;
+ }
+
+ bool exists() const {
+ return mtime_ != 0;
+ }
+
+ bool status_known() const {
+ return mtime_ != -1;
+ }
+
+ string path_;
+ // Possible values of mtime_:
+ // -1: file hasn't been examined
+ // 0: we looked, and file doesn't exist
+ // >0: actual file's mtime
+ time_t mtime_;
+ Node* node_;
+};
+
+struct Edge;
+struct Node {
+ Node(FileStat* file) : file_(file), dirty_(false), in_edge_(NULL) {}
+
+ bool dirty() const { return dirty_; }
+ void MarkDirty();
+ void MarkDependentsDirty();
+
+ FileStat* file_;
+ bool dirty_;
+ Edge* in_edge_;
+ vector<Edge*> out_edges_;
+};
+
+struct Rule {
+ Rule(const string& name) : name_(name) { }
+
+ bool ParseCommand(const string& command, string* err) {
+ return command_.Parse(command, err);
+ }
+ string name_;
+ EvalString command_;
+ EvalString description_;
+ EvalString depfile_;
+};
+
+struct State;
+struct Edge {
+ Edge() : rule_(NULL), env_(NULL), implicit_deps_(0), order_only_deps_(0) {}
+
+ void MarkDirty(Node* node);
+ bool RecomputeDirty(State* state, DiskInterface* disk_interface, string* err);
+ string EvaluateCommand(); // XXX move to env, take env ptr
+ string GetDescription();
+ bool LoadDepFile(State* state, DiskInterface* disk_interface, string* err);
+
+ void Dump();
+
+ const Rule* rule_;
+ vector<Node*> inputs_;
+ vector<Node*> outputs_;
+ Env* env_;
+
+ // XXX There are three types of inputs.
+ // 1) explicit deps, which show up as $in on the command line;
+ // 2) implicit deps, which the target depends on implicitly (e.g. C headers),
+ // and changes in them cause the target to rebuild;
+ // 3) order-only deps, which are needed before the target builds but which
+ // don't cause the target to rebuild.
+ // Currently we stuff all of these into inputs_ and keep counts of #2 and #3
+ // when we need to compute subsets. This is suboptimal; should think of a
+ // better representation. (Could make each pointer into a pair of a pointer
+ // and a type of input, or if memory matters could use the low bits of the
+ // pointer...)
+ int implicit_deps_;
+ int order_only_deps_;
+ bool is_implicit(int index) {
+ return index >= ((int)inputs_.size()) - order_only_deps_ - implicit_deps_ &&
+ !is_order_only(index);
+ }
+ bool is_order_only(int index) {
+ return index >= ((int)inputs_.size()) - order_only_deps_;
+ }
+};
+
+#endif // NINJA_GRAPH_H_
diff --git a/src/graphviz.h b/src/graphviz.h
index d688a15..eb9ee25 100644
--- a/src/graphviz.h
+++ b/src/graphviz.h
@@ -1,5 +1,7 @@
#include <set>
+// XXX deinline all this code so we don't need this include
+#include "graph.h"
struct Node;
struct GraphViz {
diff --git a/src/ninja.cc b/src/ninja.cc
index d568267..5602806 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -6,9 +6,10 @@
#include "build.h"
#include "build_log.h"
-#include "graphviz.h"
#include "parsers.h"
+#include "graphviz.h"
+
option options[] = {
{ "help", no_argument, NULL, 'h' },
{ }
diff --git a/src/ninja.h b/src/ninja.h
index 3ece1ab..26432c3 100644
--- a/src/ninja.h
+++ b/src/ninja.h
@@ -14,6 +14,11 @@ using namespace std;
#include "eval_env.h"
#include "hash_map.h"
+struct Edge;
+struct FileStat;
+struct Node;
+struct Rule;
+
int ReadFile(const string& path, string* contents, string* err);
struct DiskInterface {
@@ -34,106 +39,6 @@ struct RealDiskInterface : public DiskInterface {
virtual string ReadFile(const string& path, string* err);
};
-struct Node;
-struct FileStat {
- FileStat(const string& path) : path_(path), mtime_(-1), node_(NULL) {}
- void Touch(int mtime);
- // Return true if the file exists (mtime_ got a value).
- bool Stat(DiskInterface* disk_interface);
-
- // Return true if we needed to stat.
- bool StatIfNecessary(DiskInterface* disk_interface) {
- if (status_known())
- return false;
- Stat(disk_interface);
- return true;
- }
-
- bool exists() const {
- assert(status_known());
- return mtime_ != 0;
- }
-
- bool status_known() const {
- return mtime_ != -1;
- }
-
- string path_;
- // Possible values of mtime_:
- // -1: file hasn't been examined
- // 0: we looked, and file doesn't exist
- // >0: actual file's mtime
- time_t mtime_;
- Node* node_;
-};
-
-struct Edge;
-struct Node {
- Node(FileStat* file) : file_(file), dirty_(false), in_edge_(NULL) {}
-
- bool dirty() const { return dirty_; }
- void MarkDirty();
- void MarkDependentsDirty();
-
- FileStat* file_;
- bool dirty_;
- Edge* in_edge_;
- vector<Edge*> out_edges_;
-};
-
-struct Rule {
- Rule(const string& name) : name_(name) { }
-
- bool ParseCommand(const string& command, string* err) {
- return command_.Parse(command, err);
- }
- string name_;
- EvalString command_;
- EvalString description_;
- EvalString depfile_;
-};
-
-struct State;
-struct Edge {
- Edge() : rule_(NULL), env_(NULL), implicit_deps_(0), order_only_deps_(0) {}
-
- void MarkDirty(Node* node);
- bool RecomputeDirty(State* state, DiskInterface* disk_interface, string* err);
- string EvaluateCommand(); // XXX move to env, take env ptr
- string GetDescription();
- bool LoadDepFile(State* state, DiskInterface* disk_interface, string* err);
-
- void Dump();
-
- enum InOut { IN, OUT };
-
- const Rule* rule_;
- vector<Node*> inputs_;
- vector<Node*> outputs_;
- Env* env_;
-
- // XXX There are three types of inputs.
- // 1) explicit deps, which show up as $in on the command line;
- // 2) implicit deps, which the target depends on implicitly (e.g. C headers),
- // and changes in them cause the target to rebuild;
- // 3) order-only deps, which are needed before the target builds but which
- // don't cause the target to rebuild.
- // Currently we stuff all of these into inputs_ and keep counts of #2 and #3
- // when we need to compute subsets. This is suboptimal; should think of a
- // better representation. (Could make each pointer into a pair of a pointer
- // and a type of input, or if memory matters could use the low bits of the
- // pointer...)
- int implicit_deps_;
- int order_only_deps_;
- bool is_implicit(int index) {
- return index >= ((int)inputs_.size()) - order_only_deps_ - implicit_deps_ &&
- !is_order_only(index);
- }
- bool is_order_only(int index) {
- return index >= ((int)inputs_.size()) - order_only_deps_;
- }
-};
-
struct StatCache {
typedef hash_map<string, FileStat*> Paths;
Paths paths_;
@@ -141,6 +46,7 @@ struct StatCache {
void Dump();
void Reload();
};
+
struct State {
State();
@@ -151,7 +57,8 @@ struct State {
Edge* AddEdge(const Rule* rule);
Node* GetNode(const string& path);
Node* LookupNode(const string& path);
- void AddInOut(Edge* edge, Edge::InOut inout, const string& path);
+ void AddIn(Edge* edge, const string& path);
+ void AddOut(Edge* edge, const string& path);
StatCache stat_cache_;
map<string, const Rule*> rules_;
diff --git a/src/ninja_jumble.cc b/src/ninja_jumble.cc
index 18faac8..d351a6c 100644
--- a/src/ninja_jumble.cc
+++ b/src/ninja_jumble.cc
@@ -3,13 +3,14 @@
#include "ninja.h"
-#include "build_log.h"
-
#include <errno.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
+#include "build_log.h"
+#include "graph.h"
+
int ReadFile(const string& path, string* contents, string* err) {
FILE* f = fopen(path.c_str(), "r");
if (!f) {
@@ -90,141 +91,6 @@ bool RealDiskInterface::MakeDir(const string& path) {
}
return true;
}
-void FileStat::Touch(int mtime) {
- mtime_ = mtime;
- if (node_)
- node_->MarkDirty();
-}
-
-bool FileStat::Stat(DiskInterface* disk_interface) {
- mtime_ = disk_interface->Stat(path_);
- return mtime_ > 0;
-}
-
-void Node::MarkDirty() {
- if (dirty_)
- return; // We already know.
-
- dirty_ = true;
- MarkDependentsDirty();
-}
-
-void Node::MarkDependentsDirty() {
- for (vector<Edge*>::iterator i = out_edges_.begin(); i != out_edges_.end(); ++i)
- (*i)->MarkDirty(this);
-}
-
-bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface,
- string* err) {
- bool dirty = false;
-
- if (!rule_->depfile_.empty()) {
- if (!LoadDepFile(state, disk_interface, err))
- return false;
- }
-
- time_t most_recent_input = 1;
- for (vector<Node*>::iterator i = inputs_.begin(); i != inputs_.end(); ++i) {
- if ((*i)->file_->StatIfNecessary(disk_interface)) {
- if (Edge* edge = (*i)->in_edge_) {
- if (!edge->RecomputeDirty(state, disk_interface, err))
- return false;
- } else {
- // This input has no in-edge; it is dirty if it is missing.
- // But it's ok for implicit deps to be missing.
- if (!is_implicit(i - inputs_.begin()))
- (*i)->dirty_ = !(*i)->file_->exists();
- }
- }
-
- if (is_order_only(i - inputs_.begin())) {
- // Order-only deps only make us dirty if they're missing.
- if (!(*i)->file_->exists())
- dirty = true;
- continue;
- }
-
- // If a regular input is dirty (or missing), we're dirty.
- // Otherwise consider mtime.
- if ((*i)->dirty_) {
- dirty = true;
- } else {
- if ((*i)->file_->mtime_ > most_recent_input)
- most_recent_input = (*i)->file_->mtime_;
- }
- }
-
- string command = EvaluateCommand();
-
- assert(!outputs_.empty());
- for (vector<Node*>::iterator i = outputs_.begin(); i != outputs_.end(); ++i) {
- // We may have other outputs, that our input-recursive traversal hasn't hit
- // yet (or never will). Stat them if we haven't already.
- (*i)->file_->StatIfNecessary(disk_interface);
-
- // Output is dirty if we're dirty, we're missing the output,
- // or if it's older than the most recent input mtime.
- if (dirty || !(*i)->file_->exists() ||
- (*i)->file_->mtime_ < most_recent_input) {
- (*i)->dirty_ = true;
- } else {
- // May also be dirty due to the command changing since the last build.
- BuildLog::LogEntry* entry;
- if (state->build_log_ &&
- (entry = state->build_log_->LookupByOutput((*i)->file_->path_))) {
- if (command != entry->command)
- (*i)->dirty_ = true;
- }
- }
- }
- return true;
-}
-
-void Edge::MarkDirty(Node* node) {
- if (rule_ == &State::kPhonyRule)
- return;
-
- vector<Node*>::iterator i = find(inputs_.begin(), inputs_.end(), node);
- if (i == inputs_.end())
- return;
- if (i - inputs_.begin() >= ((int)inputs_.size()) - order_only_deps_)
- return; // Order-only deps don't cause us to become dirty.
- for (i = outputs_.begin(); i != outputs_.end(); ++i)
- (*i)->MarkDirty();
-}
-
-struct EdgeEnv : public Env {
- EdgeEnv(Edge* edge) : edge_(edge) {}
- virtual string LookupVariable(const string& var) {
- string result;
- if (var == "in") {
- int explicit_deps = edge_->inputs_.size() - edge_->implicit_deps_ -
- edge_->order_only_deps_;
- for (vector<Node*>::iterator i = edge_->inputs_.begin();
- i != edge_->inputs_.end() && explicit_deps; ++i, --explicit_deps) {
- if (!result.empty())
- result.push_back(' ');
- result.append((*i)->file_->path_);
- }
- } else if (var == "out") {
- result = edge_->outputs_[0]->file_->path_;
- } else if (edge_->env_) {
- return edge_->env_->LookupVariable(var);
- }
- return result;
- }
- Edge* edge_;
-};
-
-string Edge::EvaluateCommand() {
- EdgeEnv env(this);
- return rule_->command_.Evaluate(&env);
-}
-
-string Edge::GetDescription() {
- EdgeEnv env(this);
- return rule_->description_.Evaluate(&env);
-}
FileStat* StatCache::GetFile(const string& path) {
Paths::iterator i = paths_.find(path);
@@ -248,65 +114,6 @@ void StatCache::Dump() {
}
}
-#include "parsers.h"
-
-bool Edge::LoadDepFile(State* state, DiskInterface* disk_interface, string* err) {
- EdgeEnv env(this);
- string path = rule_->depfile_.Evaluate(&env);
-
- string content = disk_interface->ReadFile(path, err);
- if (!err->empty())
- return false;
- if (content.empty())
- return true;
-
- MakefileParser makefile;
- if (!makefile.Parse(content, err))
- return false;
-
- // Check that this depfile matches our output.
- if (outputs_.size() != 1) {
- *err = "expected only one output";
- return false;
- }
- if (outputs_[0]->file_->path_ != makefile.out_) {
- *err = "expected makefile to mention '" + outputs_[0]->file_->path_ + "', "
- "got '" + makefile.out_ + "'";
- return false;
- }
-
- // Add all its in-edges.
- for (vector<string>::iterator i = makefile.ins_.begin();
- i != makefile.ins_.end(); ++i) {
- Node* node = state->GetNode(*i);
- for (vector<Node*>::iterator j = inputs_.begin(); j != inputs_.end(); ++j) {
- if (*j == node) {
- node = NULL;
- break;
- }
- }
- if (node) {
- inputs_.insert(inputs_.end() - order_only_deps_, node);
- node->out_edges_.push_back(this);
- ++implicit_deps_;
- }
- }
-
- return true;
-}
-
-void Edge::Dump() {
- printf("[ ");
- for (vector<Node*>::iterator i = inputs_.begin(); i != inputs_.end(); ++i) {
- printf("%s ", (*i)->file_->path_.c_str());
- }
- printf("--%s-> ", rule_->name_.c_str());
- for (vector<Node*>::iterator i = outputs_.begin(); i != outputs_.end(); ++i) {
- printf("%s ", (*i)->file_->path_.c_str());
- }
- printf("]\n");
-}
-
const Rule State::kPhonyRule("phony");
State::State() : build_log_(NULL) {
@@ -348,19 +155,20 @@ Node* State::GetNode(const string& path) {
return file->node_;
}
-void State::AddInOut(Edge* edge, Edge::InOut inout, const string& path) {
+void State::AddIn(Edge* edge, const string& path) {
Node* node = GetNode(path);
- if (inout == Edge::IN) {
- edge->inputs_.push_back(node);
- node->out_edges_.push_back(edge);
- } else {
- edge->outputs_.push_back(node);
- if (node->in_edge_) {
- fprintf(stderr, "WARNING: multiple rules generate %s. "
- "build will not be correct; continuing anyway\n", path.c_str());
- }
- node->in_edge_ = edge;
+ edge->inputs_.push_back(node);
+ node->out_edges_.push_back(edge);
+}
+
+void State::AddOut(Edge* edge, const string& path) {
+ Node* node = GetNode(path);
+ edge->outputs_.push_back(node);
+ if (node->in_edge_) {
+ fprintf(stderr, "WARNING: multiple rules generate %s. "
+ "build will not be correct; continuing anyway\n", path.c_str());
}
+ node->in_edge_ = edge;
}
bool EvalString::Parse(const string& input, string* err) {
diff --git a/src/ninja_test.cc b/src/ninja_test.cc
index 12ba93c..0c992e9 100644
--- a/src/ninja_test.cc
+++ b/src/ninja_test.cc
@@ -31,9 +31,9 @@ TEST(State, Basic) {
ASSERT_EQ("", err);
state.AddRule(rule);
Edge* edge = state.AddEdge(rule);
- state.AddInOut(edge, Edge::IN, "in1");
- state.AddInOut(edge, Edge::IN, "in2");
- state.AddInOut(edge, Edge::OUT, "out");
+ state.AddIn(edge, "in1");
+ state.AddIn(edge, "in2");
+ state.AddOut(edge, "out");
EXPECT_EQ("cat in1 in2 > out", edge->EvaluateCommand());
diff --git a/src/parsers.cc b/src/parsers.cc
index 7eee93c..f57c3b9 100644
--- a/src/parsers.cc
+++ b/src/parsers.cc
@@ -5,6 +5,7 @@
#include <stdio.h>
#include <string.h>
+#include "graph.h"
#include "ninja.h"
string Token::AsString() const {
@@ -460,9 +461,9 @@ bool ManifestParser::ParseEdge(string* err) {
Edge* edge = state_->AddEdge(rule);
edge->env_ = env;
for (vector<string>::iterator i = ins.begin(); i != ins.end(); ++i)
- state_->AddInOut(edge, Edge::IN, *i);
+ state_->AddIn(edge, *i);
for (vector<string>::iterator i = outs.begin(); i != outs.end(); ++i)
- state_->AddInOut(edge, Edge::OUT, *i);
+ state_->AddOut(edge, *i);
edge->order_only_deps_ = order_only;
return true;
diff --git a/src/parsers_test.cc b/src/parsers_test.cc
index 6fb418d..28ba619 100644
--- a/src/parsers_test.cc
+++ b/src/parsers_test.cc
@@ -2,6 +2,7 @@
#include <gtest/gtest.h>
+#include "graph.h"
#include "ninja.h"
struct ParserTest : public testing::Test,
diff --git a/src/test.h b/src/test.h
index 4d45a2e..405f039 100644
--- a/src/test.h
+++ b/src/test.h
@@ -1,7 +1,8 @@
-#include "ninja.h"
-
#include <gtest/gtest.h>
+#include "graph.h"
+#include "ninja.h"
+
struct StateTestWithBuiltinRules : public testing::Test {
StateTestWithBuiltinRules();
Node* GetNode(const string& path);