Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(223)

Side by Side Diff: tools/gn/item_tree.cc

Issue 21114002: Add initial prototype for the GN meta-buildsystem. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add owners and readme Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/gn/item_tree.h ('k') | tools/gn/label.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "tools/gn/item_tree.h"
6
7 #include <algorithm>
8
9 #include "base/stl_util.h"
10 #include "tools/gn/err.h"
11 #include "tools/gn/item.h"
12 #include "tools/gn/item_node.h"
13
14 namespace {
15
16 // Recursively looks in the tree for a given node, returning true if it
17 // was found in the dependecy graph. This is used to see if a given node
18 // participates in a cycle.
19 //
20 // Note that "look_for" and "search_in" will be the same node when starting the
21 // search, so we don't want to return true in that case.
22 //
23 // If a cycle is found, the return value will be true and the cycle vector will
24 // be filled with the path (in reverse order).
25 bool RecursiveFindCycle(const ItemNode* look_for,
26 const ItemNode* search_in,
27 std::vector<const ItemNode*>* cycle) {
28 const ItemNode::ItemNodeSet& unresolved =
29 search_in->unresolved_dependencies();
30 for (ItemNode::ItemNodeSet::const_iterator i = unresolved.begin();
31 i != unresolved.end(); ++i) {
32 if (*i == look_for) {
33 cycle->push_back(*i);
34 return true;
35 }
36
37 if (RecursiveFindCycle(look_for, *i, cycle)) {
38 // Found a cycle inside this one, record our path and return.
39 cycle->push_back(*i);
40 return true;
41 }
42 }
43 return false;
44 }
45
46 } // namespace
47
48 ItemTree::ItemTree() {
49 }
50
51 ItemTree::~ItemTree() {
52 STLDeleteContainerPairSecondPointers(items_.begin(), items_.end());
53 }
54
55 ItemNode* ItemTree::GetExistingNodeLocked(const Label& label) {
56 lock_.AssertAcquired();
57 StringToNodeHash::iterator found = items_.find(label);
58 if (found == items_.end())
59 return NULL;
60 return found->second;
61 }
62
63 void ItemTree::AddNodeLocked(ItemNode* node) {
64 lock_.AssertAcquired();
65 DCHECK(items_.find(node->item()->label()) == items_.end());
66 items_[node->item()->label()] = node;
67 }
68
69 Err ItemTree::MarkItemGeneratedLocked(const Label& label) {
70 lock_.AssertAcquired();
71 DCHECK(items_.find(label) != items_.end());
72
73 ItemNode* node = items_[label];
74
75 if (!node->unresolved_dependencies().empty()) {
76 // Still some pending dependencies, wait for those to be resolved.
77 node->SetGenerated();
78 return Err();
79 }
80 return MarkItemResolvedLocked(node);
81 }
82
83 void ItemTree::GetAllItemsLocked(std::vector<const Item*>* dest) const {
84 lock_.AssertAcquired();
85 dest->reserve(items_.size());
86 for (StringToNodeHash::const_iterator i = items_.begin();
87 i != items_.end(); ++i) {
88 dest->push_back(i->second->item());
89 }
90 }
91
92 Err ItemTree::CheckForBadItems() const {
93 base::AutoLock lock(lock_);
94
95 // Look for errors where we find a GENERATED node that refers to a REFERENCED
96 // one. There may be other nodes depending on the GENERATED one, but listing
97 // all of those isn't helpful, we want to find the broken link.
98 //
99 // This finds normal "missing dependency" errors but does not find circular
100 // dependencies because in this case all items in the cycle will be GENERATED
101 // but none will be resolved. If this happens, we'll check explicitly for
102 // that below.
103 std::vector<const ItemNode*> bad_nodes;
104 std::string depstring;
105 for (StringToNodeHash::const_iterator i = items_.begin();
106 i != items_.end(); ++i) {
107 const ItemNode* src = i->second;
108
109 if (src->state() == ItemNode::GENERATED) {
110 bad_nodes.push_back(src);
111
112 // Check dependencies.
113 for (ItemNode::ItemNodeSet::const_iterator dest =
114 src->unresolved_dependencies().begin();
115 dest != src->unresolved_dependencies().end();
116 ++dest) {
117 if ((*dest)->state() == ItemNode::REFERENCED) {
118 depstring += "\"" + src->item()->label().GetUserVisibleName(false) +
119 "\" needs " + (*dest)->item()->GetItemTypeName() +
120 " \"" + (*dest)->item()->label().GetUserVisibleName(false) +
121 "\"\n";
122 }
123 }
124 }
125 }
126
127 if (!bad_nodes.empty() && depstring.empty()) {
128 // Our logic above found a bad node but didn't identify the problem. This
129 // normally means a circular dependency.
130 depstring = CheckForCircularDependenciesLocked(bad_nodes);
131 if (depstring.empty()) {
132 // Something's very wrong, just dump out the bad nodes.
133 depstring = "I have no idea what went wrong, but these are unresolved, "
134 "possible due to an\ninternal error:";
135 for (size_t i = 0; i < bad_nodes.size(); i++) {
136 depstring += "\n\"" +
137 bad_nodes[i]->item()->label().GetUserVisibleName(false) + "\"";
138 }
139 }
140 }
141
142 if (depstring.empty())
143 return Err();
144 return Err(Location(), "Unresolved dependencies.", depstring);
145 }
146
147 Err ItemTree::MarkItemResolvedLocked(ItemNode* node) {
148 node->SetResolved();
149 node->item()->OnResolved();
150
151 // Now update our waiters, pushing the "resolved" bit.
152 ItemNode::ItemNodeSet waiting;
153 node->SwapOutWaitingDependencySet(&waiting);
154 for (ItemNode::ItemNodeSet::iterator i = waiting.begin();
155 i != waiting.end(); ++i) {
156 ItemNode* waiter = *i;
157
158 // Our node should be unresolved in the waiter.
159 DCHECK(waiter->unresolved_dependencies().find(node) !=
160 waiter->unresolved_dependencies().end());
161 waiter->MarkDirectDependencyResolved(node);
162
163 // Recursively mark nodes as resolved.
164 if (waiter->state() == ItemNode::GENERATED &&
165 waiter->unresolved_dependencies().empty()) {
166 Err err = MarkItemResolvedLocked(waiter);
167 if (err.has_error())
168 return err;
169 }
170 }
171
172 return Err();
173 }
174
175 std::string ItemTree::CheckForCircularDependenciesLocked(
176 const std::vector<const ItemNode*>& bad_nodes) const {
177 std::vector<const ItemNode*> cycle;
178 if (!RecursiveFindCycle(bad_nodes[0], bad_nodes[0], &cycle))
179 return std::string(); // Didn't find a cycle, something else is wrong.
180
181 cycle.push_back(bad_nodes[0]);
182 std::string ret = "There is a dependency cycle:";
183
184 // Walk backwards since the dependency arrows point in the reverse direction.
185 for (int i = static_cast<int>(cycle.size()) - 1; i >= 0; i--) {
186 ret += "\n \"" + cycle[i]->item()->label().GetUserVisibleName(false) +
187 "\"";
188 if (i != 0)
189 ret += " ->";
190 }
191
192 return ret;
193 }
OLDNEW
« no previous file with comments | « tools/gn/item_tree.h ('k') | tools/gn/label.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698