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 "explanations.h"
24 #include "graph.h"
25 #include "state.h"
26 #include "util.h"
27 
28 using namespace std;
29 
30 bool DyndepLoader::LoadDyndeps(Node* node, std::string* err) const {
31  DyndepFile ddf;
32  return LoadDyndeps(node, &ddf, err);
33 }
34 
36  std::string* err) const {
37  // We are loading the dyndep file now so it is no longer pending.
38  node->set_dyndep_pending(false);
39 
40  // Load the dyndep information from the file.
41  explanations_.Record(node, "loading dyndep file '%s'", node->path().c_str());
42 
43  if (!LoadDyndepFile(node, ddf, err))
44  return false;
45 
46  // Update each edge that specified this node as its dyndep binding.
47  std::vector<Edge*> const& out_edges = node->out_edges();
48  for (Edge* edge : out_edges) {
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 (const auto& dyndep_output : *ddf) {
69  if (!dyndep_output.second.used_) {
70  Edge* const edge = dyndep_output.first;
71  *err = ("dyndep file '" + node->path() + "' mentions output "
72  "'" + edge->outputs_[0]->path() + "' whose build statement "
73  "does not have a dyndep binding for the file");
74  return false;
75  }
76  }
77 
78  return true;
79 }
80 
81 bool DyndepLoader::UpdateEdge(Edge* edge, Dyndeps const* dyndeps,
82  std::string* err) const {
83  // Add dyndep-discovered bindings to the edge.
84  // We know the edge already has its own binding
85  // scope because it has a "dyndep" binding.
86  if (dyndeps->restat_)
87  edge->env_->AddBinding("restat", "1");
88 
89  // Add the dyndep-discovered outputs to the edge.
90  edge->outputs_.insert(edge->outputs_.end(),
91  dyndeps->implicit_outputs_.begin(),
92  dyndeps->implicit_outputs_.end());
93  edge->implicit_outs_ += dyndeps->implicit_outputs_.size();
94 
95  // Add this edge as incoming to each new output.
96  for (Node* node : dyndeps->implicit_outputs_) {
97  if (node->in_edge()) {
98  // This node already has an edge producing it.
99  *err = "multiple rules generate " + node->path();
100  return false;
101  }
102  node->set_in_edge(edge);
103  }
104 
105  // Add the dyndep-discovered inputs to the edge.
106  edge->inputs_.insert(edge->inputs_.end() - edge->order_only_deps_,
107  dyndeps->implicit_inputs_.begin(),
108  dyndeps->implicit_inputs_.end());
109  edge->implicit_deps_ += dyndeps->implicit_inputs_.size();
110 
111  // Add this edge as outgoing from each new input.
112  for (Node* node : dyndeps->implicit_inputs_)
113  node->AddOutEdge(edge);
114 
115  return true;
116 }
117 
119  std::string* err) const {
120  DyndepParser parser(state_, disk_interface_, ddf);
121  return parser.Load(file->path(), err);
122 }
Definition: hash_map.h:26
void AddBinding(const std::string &key, const std::string &val)
Definition: eval_env.cc:30
Store data loaded from one dyndep file.
Definition: dyndep.h:42
bool LoadDyndepFile(Node *file, DyndepFile *ddf, std::string *err) const
Definition: dyndep.cc:118
bool UpdateEdge(Edge *edge, Dyndeps const *dyndeps, std::string *err) const
Definition: dyndep.cc:81
bool LoadDyndeps(Node *node, std::string *err) const
Load a dyndep file from the given node's path and update the build graph with the new information.
Definition: dyndep.cc:30
Parses dyndep files.
Definition: dyndep_parser.h:25
Store dynamically-discovered dependency information for one edge.
Definition: dyndep.h:30
std::vector< Node * > implicit_inputs_
Definition: dyndep.h:34
std::vector< Node * > implicit_outputs_
Definition: dyndep.h:35
bool restat_
Definition: dyndep.h:33
An edge in the dependency graph; links between Nodes using Rules.
Definition: graph.h:175
std::vector< Node * > outputs_
Definition: graph.h:217
int implicit_deps_
Definition: graph.h:243
int order_only_deps_
Definition: graph.h:244
int implicit_outs_
Definition: graph.h:258
BindingEnv * env_
Definition: graph.h:220
std::vector< Node * > inputs_
Definition: graph.h:216
Information about a node in the dependency graph: the file, whether it's dirty, mtime,...
Definition: graph.h:42
void set_in_edge(Edge *edge)
Definition: graph.h:101
void set_dyndep_pending(bool pending)
Definition: graph.h:98
void AddOutEdge(Edge *edge)
Definition: graph.h:116
const std::string & path() const
Definition: graph.h:82
Edge * in_edge() const
Definition: graph.h:100
const std::vector< Edge * > & out_edges() const
Definition: graph.h:114
bool Load(const std::string &filename, std::string *err, Lexer *parent=NULL)
Load and parse a file.
Definition: parser.cc:22