Ninja
dyndep.cc
Go to the documentation of this file.
1 // Copyright 2015 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dyndep.h"
16 
17 #include <assert.h>
18 #include <stdio.h>
19 
20 #include "debug_flags.h"
21 #include "disk_interface.h"
22 #include "dyndep_parser.h"
23 #include "graph.h"
24 #include "state.h"
25 #include "util.h"
26 
27 using namespace std;
28 
29 bool DyndepLoader::LoadDyndeps(Node* node, std::string* err) const {
30  DyndepFile ddf;
31  return LoadDyndeps(node, &ddf, err);
32 }
33 
35  std::string* err) const {
36  // We are loading the dyndep file now so it is no longer pending.
37  node->set_dyndep_pending(false);
38 
39  // Load the dyndep information from the file.
40  EXPLAIN("loading dyndep file '%s'", node->path().c_str());
41  if (!LoadDyndepFile(node, ddf, err))
42  return false;
43 
44  // Update each edge that specified this node as its dyndep binding.
45  std::vector<Edge*> const& out_edges = node->out_edges();
46  for (std::vector<Edge*>::const_iterator oe = out_edges.begin();
47  oe != out_edges.end(); ++oe) {
48  Edge* const edge = *oe;
49  if (edge->dyndep_ != node)
50  continue;
51 
52  DyndepFile::iterator ddi = ddf->find(edge);
53  if (ddi == ddf->end()) {
54  *err = ("'" + edge->outputs_[0]->path() + "' "
55  "not mentioned in its dyndep file "
56  "'" + node->path() + "'");
57  return false;
58  }
59 
60  ddi->second.used_ = true;
61  Dyndeps const& dyndeps = ddi->second;
62  if (!UpdateEdge(edge, &dyndeps, err)) {
63  return false;
64  }
65  }
66 
67  // Reject extra outputs in dyndep file.
68  for (DyndepFile::const_iterator oe = ddf->begin(); oe != ddf->end();
69  ++oe) {
70  if (!oe->second.used_) {
71  Edge* const edge = oe->first;
72  *err = ("dyndep file '" + node->path() + "' mentions output "
73  "'" + edge->outputs_[0]->path() + "' whose build statement "
74  "does not have a dyndep binding for the file");
75  return false;
76  }
77  }
78 
79  return true;
80 }
81 
82 bool DyndepLoader::UpdateEdge(Edge* edge, Dyndeps const* dyndeps,
83  std::string* err) const {
84  // Add dyndep-discovered bindings to the edge.
85  // We know the edge already has its own binding
86  // scope because it has a "dyndep" binding.
87  if (dyndeps->restat_)
88  edge->env_->AddBinding("restat", "1");
89 
90  // Add the dyndep-discovered outputs to the edge.
91  edge->outputs_.insert(edge->outputs_.end(),
92  dyndeps->implicit_outputs_.begin(),
93  dyndeps->implicit_outputs_.end());
94  edge->implicit_outs_ += dyndeps->implicit_outputs_.size();
95 
96  // Add this edge as incoming to each new output.
97  for (std::vector<Node*>::const_iterator i =
98  dyndeps->implicit_outputs_.begin();
99  i != dyndeps->implicit_outputs_.end(); ++i) {
100  if ((*i)->in_edge() != NULL) {
101  *err = "multiple rules generate " + (*i)->path();
102  return false;
103  }
104  (*i)->set_in_edge(edge);
105  }
106 
107  // Add the dyndep-discovered inputs to the edge.
108  edge->inputs_.insert(edge->inputs_.end() - edge->order_only_deps_,
109  dyndeps->implicit_inputs_.begin(),
110  dyndeps->implicit_inputs_.end());
111  edge->implicit_deps_ += dyndeps->implicit_inputs_.size();
112 
113  // Add this edge as outgoing from each new input.
114  for (std::vector<Node*>::const_iterator i =
115  dyndeps->implicit_inputs_.begin();
116  i != dyndeps->implicit_inputs_.end(); ++i)
117  (*i)->AddOutEdge(edge);
118 
119  return true;
120 }
121 
123  std::string* err) const {
124  DyndepParser parser(state_, disk_interface_, ddf);
125  return parser.Load(file->path(), err);
126 }
std::vector< Node * > implicit_inputs_
Definition: dyndep.h:32
int order_only_deps_
Definition: graph.h:197
int implicit_deps_
Definition: graph.h:196
Store data loaded from one dyndep file.
Definition: dyndep.h:40
bool restat_
Definition: dyndep.h:31
Information about a node in the dependency graph: the file, whether it&#39;s dirty, mtime, etc.
Definition: graph.h:37
std::vector< Node * > outputs_
Definition: graph.h:175
bool Load(const std::string &filename, std::string *err, Lexer *parent=NULL)
Load and parse a file.
Definition: parser.cc:22
An edge in the dependency graph; links between Nodes using Rules.
Definition: graph.h:139
const std::string & path() const
Definition: graph.h:76
Store dynamically-discovered dependency information for one edge.
Definition: dyndep.h:28
void set_dyndep_pending(bool pending)
Definition: graph.h:92
bool LoadDyndepFile(Node *file, DyndepFile *ddf, std::string *err) const
Definition: dyndep.cc:122
BindingEnv * env_
Definition: graph.h:177
int implicit_outs_
Definition: graph.h:211
std::vector< Node * > inputs_
Definition: graph.h:174
Parses dyndep files.
Definition: dyndep_parser.h:25
void AddBinding(const std::string &key, const std::string &val)
Definition: eval_env.cc:30
const std::vector< Edge * > & out_edges() const
Definition: graph.h:100
bool UpdateEdge(Edge *edge, Dyndeps const *dyndeps, std::string *err) const
Definition: dyndep.cc:82
bool LoadDyndeps(Node *node, std::string *err) const
Load a dyndep file from the given node&#39;s path and update the build graph with the new information...
Definition: dyndep.cc:29
Node * dyndep_
Definition: graph.h:176
std::vector< Node * > implicit_outputs_
Definition: dyndep.h:33
#define EXPLAIN(fmt,...)
Definition: debug_flags.h:20