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
28using namespace std;
29
30bool 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
81bool 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
State * state_
Definition dyndep.h:64
DiskInterface * disk_interface_
Definition dyndep.h:65
OptionalExplanations explanations_
Definition dyndep.h:66
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.
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
const std::string & path() const
Definition graph.h:82
void set_in_edge(Edge *edge)
Definition graph.h:101
Edge * in_edge() const
Definition graph.h:100
void set_dyndep_pending(bool pending)
Definition graph.h:98
void AddOutEdge(Edge *edge)
Definition graph.h:116
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