| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "tools/gn/builder.h" | 5 #include "tools/gn/builder.h" |
| 6 | 6 |
| 7 #include "tools/gn/config.h" | 7 #include "tools/gn/config.h" |
| 8 #include "tools/gn/deps_iterator.h" | 8 #include "tools/gn/deps_iterator.h" |
| 9 #include "tools/gn/err.h" | 9 #include "tools/gn/err.h" |
| 10 #include "tools/gn/loader.h" | 10 #include "tools/gn/loader.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 // participates in a cycle. | 22 // participates in a cycle. |
| 23 // | 23 // |
| 24 // If this returns true, the cycle will be in *path. This should point to an | 24 // If this returns true, the cycle will be in *path. This should point to an |
| 25 // empty vector for the first call. During computation, the path will contain | 25 // empty vector for the first call. During computation, the path will contain |
| 26 // the full dependency path to the current node. | 26 // the full dependency path to the current node. |
| 27 // | 27 // |
| 28 // Return false means no cycle was found. | 28 // Return false means no cycle was found. |
| 29 bool RecursiveFindCycle(const BuilderRecord* search_in, | 29 bool RecursiveFindCycle(const BuilderRecord* search_in, |
| 30 std::vector<const BuilderRecord*>* path) { | 30 std::vector<const BuilderRecord*>* path) { |
| 31 path->push_back(search_in); | 31 path->push_back(search_in); |
| 32 | 32 for (const auto& cur : search_in->unresolved_deps()) { |
| 33 const BuilderRecord::BuilderRecordSet& unresolved = | |
| 34 search_in->unresolved_deps(); | |
| 35 for (BuilderRecord::BuilderRecordSet::const_iterator i = unresolved.begin(); | |
| 36 i != unresolved.end(); ++i) { | |
| 37 const BuilderRecord* cur = *i; | |
| 38 | |
| 39 std::vector<const BuilderRecord*>::iterator found = | 33 std::vector<const BuilderRecord*>::iterator found = |
| 40 std::find(path->begin(), path->end(), cur); | 34 std::find(path->begin(), path->end(), cur); |
| 41 if (found != path->end()) { | 35 if (found != path->end()) { |
| 42 // This item is already in the set, we found the cycle. Everything before | 36 // This item is already in the set, we found the cycle. Everything before |
| 43 // the first definition of cur is irrelevant to the cycle. | 37 // the first definition of cur is irrelevant to the cycle. |
| 44 path->erase(path->begin(), found); | 38 path->erase(path->begin(), found); |
| 45 path->push_back(cur); | 39 path->push_back(cur); |
| 46 return true; | 40 return true; |
| 47 } | 41 } |
| 48 | 42 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 if (!record) | 119 if (!record) |
| 126 return NULL; | 120 return NULL; |
| 127 if (!record->item()) | 121 if (!record->item()) |
| 128 return NULL; | 122 return NULL; |
| 129 return record->item()->AsToolchain(); | 123 return record->item()->AsToolchain(); |
| 130 } | 124 } |
| 131 | 125 |
| 132 std::vector<const BuilderRecord*> Builder::GetAllRecords() const { | 126 std::vector<const BuilderRecord*> Builder::GetAllRecords() const { |
| 133 std::vector<const BuilderRecord*> result; | 127 std::vector<const BuilderRecord*> result; |
| 134 result.reserve(records_.size()); | 128 result.reserve(records_.size()); |
| 135 for (RecordMap::const_iterator i = records_.begin(); | 129 for (const auto& record : records_) |
| 136 i != records_.end(); ++i) | 130 result.push_back(record.second); |
| 137 result.push_back(i->second); | |
| 138 return result; | 131 return result; |
| 139 } | 132 } |
| 140 | 133 |
| 141 std::vector<const Target*> Builder::GetAllResolvedTargets() const { | 134 std::vector<const Target*> Builder::GetAllResolvedTargets() const { |
| 142 std::vector<const Target*> result; | 135 std::vector<const Target*> result; |
| 143 result.reserve(records_.size()); | 136 result.reserve(records_.size()); |
| 144 for (RecordMap::const_iterator i = records_.begin(); | 137 for (const auto& record : records_) { |
| 145 i != records_.end(); ++i) { | 138 if (record.second->type() == BuilderRecord::ITEM_TARGET && |
| 146 if (i->second->type() == BuilderRecord::ITEM_TARGET && | 139 record.second->should_generate() && record.second->item()) |
| 147 i->second->should_generate() && i->second->item()) | 140 result.push_back(record.second->item()->AsTarget()); |
| 148 result.push_back(i->second->item()->AsTarget()); | |
| 149 } | 141 } |
| 150 return result; | 142 return result; |
| 151 } | 143 } |
| 152 | 144 |
| 153 const BuilderRecord* Builder::GetRecord(const Label& label) const { | 145 const BuilderRecord* Builder::GetRecord(const Label& label) const { |
| 154 // Forward to the non-const version. | 146 // Forward to the non-const version. |
| 155 return const_cast<Builder*>(this)->GetRecord(label); | 147 return const_cast<Builder*>(this)->GetRecord(label); |
| 156 } | 148 } |
| 157 | 149 |
| 158 BuilderRecord* Builder::GetRecord(const Label& label) { | 150 BuilderRecord* Builder::GetRecord(const Label& label) { |
| 159 RecordMap::iterator found = records_.find(label); | 151 RecordMap::iterator found = records_.find(label); |
| 160 if (found == records_.end()) | 152 if (found == records_.end()) |
| 161 return NULL; | 153 return NULL; |
| 162 return found->second; | 154 return found->second; |
| 163 } | 155 } |
| 164 | 156 |
| 165 bool Builder::CheckForBadItems(Err* err) const { | 157 bool Builder::CheckForBadItems(Err* err) const { |
| 166 // Look for errors where we find a defined node with an item that refers to | 158 // Look for errors where we find a defined node with an item that refers to |
| 167 // an undefined one with no item. There may be other nodes in turn depending | 159 // an undefined one with no item. There may be other nodes in turn depending |
| 168 // on our defined one, but listing those isn't helpful: we want to find the | 160 // on our defined one, but listing those isn't helpful: we want to find the |
| 169 // broken link. | 161 // broken link. |
| 170 // | 162 // |
| 171 // This finds normal "missing dependency" errors but does not find circular | 163 // This finds normal "missing dependency" errors but does not find circular |
| 172 // dependencies because in this case all items in the cycle will be GENERATED | 164 // dependencies because in this case all items in the cycle will be GENERATED |
| 173 // but none will be resolved. If this happens, we'll check explicitly for | 165 // but none will be resolved. If this happens, we'll check explicitly for |
| 174 // that below. | 166 // that below. |
| 175 std::vector<const BuilderRecord*> bad_records; | 167 std::vector<const BuilderRecord*> bad_records; |
| 176 std::string depstring; | 168 std::string depstring; |
| 177 for (RecordMap::const_iterator i = records_.begin(); | 169 for (const auto& record_pair : records_) { |
| 178 i != records_.end(); ++i) { | 170 const BuilderRecord* src = record_pair.second; |
| 179 const BuilderRecord* src = i->second; | |
| 180 if (!src->should_generate()) | 171 if (!src->should_generate()) |
| 181 continue; // Skip ungenerated nodes. | 172 continue; // Skip ungenerated nodes. |
| 182 | 173 |
| 183 if (!src->resolved()) { | 174 if (!src->resolved()) { |
| 184 bad_records.push_back(src); | 175 bad_records.push_back(src); |
| 185 | 176 |
| 186 // Check dependencies. | 177 // Check dependencies. |
| 187 for (BuilderRecord::BuilderRecordSet::const_iterator dest_iter = | 178 for (const auto& dest : src->unresolved_deps()) { |
| 188 src->unresolved_deps().begin(); | |
| 189 dest_iter != src->unresolved_deps().end(); | |
| 190 ++dest_iter) { | |
| 191 const BuilderRecord* dest = *dest_iter; | |
| 192 if (!dest->item()) { | 179 if (!dest->item()) { |
| 193 depstring += src->label().GetUserVisibleName(true) + | 180 depstring += src->label().GetUserVisibleName(true) + |
| 194 "\n needs " + dest->label().GetUserVisibleName(true) + "\n"; | 181 "\n needs " + dest->label().GetUserVisibleName(true) + "\n"; |
| 195 } | 182 } |
| 196 } | 183 } |
| 197 } | 184 } |
| 198 } | 185 } |
| 199 | 186 |
| 200 if (!depstring.empty()) { | 187 if (!depstring.empty()) { |
| 201 *err = Err(Location(), "Unresolved dependencies.", depstring); | 188 *err = Err(Location(), "Unresolved dependencies.", depstring); |
| 202 return false; | 189 return false; |
| 203 } | 190 } |
| 204 | 191 |
| 205 if (!bad_records.empty()) { | 192 if (!bad_records.empty()) { |
| 206 // Our logic above found a bad node but didn't identify the problem. This | 193 // Our logic above found a bad node but didn't identify the problem. This |
| 207 // normally means a circular dependency. | 194 // normally means a circular dependency. |
| 208 depstring = CheckForCircularDependencies(bad_records); | 195 depstring = CheckForCircularDependencies(bad_records); |
| 209 if (depstring.empty()) { | 196 if (depstring.empty()) { |
| 210 // Something's very wrong, just dump out the bad nodes. | 197 // Something's very wrong, just dump out the bad nodes. |
| 211 depstring = "I have no idea what went wrong, but these are unresolved, " | 198 depstring = "I have no idea what went wrong, but these are unresolved, " |
| 212 "possibly due to an\ninternal error:"; | 199 "possibly due to an\ninternal error:"; |
| 213 for (size_t i = 0; i < bad_records.size(); i++) { | 200 for (const auto& bad_record : bad_records) { |
| 214 depstring += "\n\"" + | 201 depstring += "\n\"" + |
| 215 bad_records[i]->label().GetUserVisibleName(false) + "\""; | 202 bad_record->label().GetUserVisibleName(false) + "\""; |
| 216 } | 203 } |
| 217 *err = Err(Location(), "", depstring); | 204 *err = Err(Location(), "", depstring); |
| 218 } else { | 205 } else { |
| 219 *err = Err(Location(), "Dependency cycle:", depstring); | 206 *err = Err(Location(), "Dependency cycle:", depstring); |
| 220 } | 207 } |
| 221 return false; | 208 return false; |
| 222 } | 209 } |
| 223 | 210 |
| 224 return true; | 211 return true; |
| 225 } | 212 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 item->GetItemTypeName() + " instead of a " + | 308 item->GetItemTypeName() + " instead of a " + |
| 322 BuilderRecord::GetNameForType(type) + "."); | 309 BuilderRecord::GetNameForType(type) + "."); |
| 323 return NULL; | 310 return NULL; |
| 324 } | 311 } |
| 325 return record; | 312 return record; |
| 326 } | 313 } |
| 327 | 314 |
| 328 bool Builder::AddDeps(BuilderRecord* record, | 315 bool Builder::AddDeps(BuilderRecord* record, |
| 329 const LabelConfigVector& configs, | 316 const LabelConfigVector& configs, |
| 330 Err* err) { | 317 Err* err) { |
| 331 for (size_t i = 0; i < configs.size(); i++) { | 318 for (const auto& config : configs) { |
| 332 BuilderRecord* dep_record = GetOrCreateRecordOfType( | 319 BuilderRecord* dep_record = GetOrCreateRecordOfType( |
| 333 configs[i].label, configs[i].origin, BuilderRecord::ITEM_CONFIG, err); | 320 config.label, config.origin, BuilderRecord::ITEM_CONFIG, err); |
| 334 if (!dep_record) | 321 if (!dep_record) |
| 335 return false; | 322 return false; |
| 336 record->AddDep(dep_record); | 323 record->AddDep(dep_record); |
| 337 } | 324 } |
| 338 return true; | 325 return true; |
| 339 } | 326 } |
| 340 | 327 |
| 341 bool Builder::AddDeps(BuilderRecord* record, | 328 bool Builder::AddDeps(BuilderRecord* record, |
| 342 const UniqueVector<LabelConfigPair>& configs, | 329 const UniqueVector<LabelConfigPair>& configs, |
| 343 Err* err) { | 330 Err* err) { |
| 344 for (size_t i = 0; i < configs.size(); i++) { | 331 for (const auto& config : configs) { |
| 345 BuilderRecord* dep_record = GetOrCreateRecordOfType( | 332 BuilderRecord* dep_record = GetOrCreateRecordOfType( |
| 346 configs[i].label, configs[i].origin, BuilderRecord::ITEM_CONFIG, err); | 333 config.label, config.origin, BuilderRecord::ITEM_CONFIG, err); |
| 347 if (!dep_record) | 334 if (!dep_record) |
| 348 return false; | 335 return false; |
| 349 record->AddDep(dep_record); | 336 record->AddDep(dep_record); |
| 350 } | 337 } |
| 351 return true; | 338 return true; |
| 352 } | 339 } |
| 353 | 340 |
| 354 bool Builder::AddDeps(BuilderRecord* record, | 341 bool Builder::AddDeps(BuilderRecord* record, |
| 355 const LabelTargetVector& targets, | 342 const LabelTargetVector& targets, |
| 356 Err* err) { | 343 Err* err) { |
| 357 for (size_t i = 0; i < targets.size(); i++) { | 344 for (const auto& target : targets) { |
| 358 BuilderRecord* dep_record = GetOrCreateRecordOfType( | 345 BuilderRecord* dep_record = GetOrCreateRecordOfType( |
| 359 targets[i].label, targets[i].origin, BuilderRecord::ITEM_TARGET, err); | 346 target.label, target.origin, BuilderRecord::ITEM_TARGET, err); |
| 360 if (!dep_record) | 347 if (!dep_record) |
| 361 return false; | 348 return false; |
| 362 record->AddDep(dep_record); | 349 record->AddDep(dep_record); |
| 363 } | 350 } |
| 364 return true; | 351 return true; |
| 365 } | 352 } |
| 366 | 353 |
| 367 bool Builder::AddToolchainDep(BuilderRecord* record, | 354 bool Builder::AddToolchainDep(BuilderRecord* record, |
| 368 const Target* target, | 355 const Target* target, |
| 369 Err* err) { | 356 Err* err) { |
| 370 BuilderRecord* toolchain_record = GetOrCreateRecordOfType( | 357 BuilderRecord* toolchain_record = GetOrCreateRecordOfType( |
| 371 target->settings()->toolchain_label(), target->defined_from(), | 358 target->settings()->toolchain_label(), target->defined_from(), |
| 372 BuilderRecord::ITEM_TOOLCHAIN, err); | 359 BuilderRecord::ITEM_TOOLCHAIN, err); |
| 373 if (!toolchain_record) | 360 if (!toolchain_record) |
| 374 return false; | 361 return false; |
| 375 record->AddDep(toolchain_record); | 362 record->AddDep(toolchain_record); |
| 376 | 363 |
| 377 return true; | 364 return true; |
| 378 } | 365 } |
| 379 | 366 |
| 380 void Builder::RecursiveSetShouldGenerate(BuilderRecord* record, | 367 void Builder::RecursiveSetShouldGenerate(BuilderRecord* record, |
| 381 bool force) { | 368 bool force) { |
| 382 if (!force && record->should_generate()) | 369 if (!force && record->should_generate()) |
| 383 return; // Already set. | 370 return; // Already set. |
| 384 record->set_should_generate(true); | 371 record->set_should_generate(true); |
| 385 | 372 |
| 386 const BuilderRecordSet& deps = record->all_deps(); | 373 for (const auto& cur : record->all_deps()) { |
| 387 for (BuilderRecordSet::const_iterator i = deps.begin(); | |
| 388 i != deps.end(); i++) { | |
| 389 BuilderRecord* cur = *i; | |
| 390 if (!cur->should_generate()) { | 374 if (!cur->should_generate()) { |
| 391 ScheduleItemLoadIfNecessary(cur); | 375 ScheduleItemLoadIfNecessary(cur); |
| 392 RecursiveSetShouldGenerate(cur, false); | 376 RecursiveSetShouldGenerate(cur, false); |
| 393 } | 377 } |
| 394 } | 378 } |
| 395 } | 379 } |
| 396 | 380 |
| 397 void Builder::ScheduleItemLoadIfNecessary(BuilderRecord* record) { | 381 void Builder::ScheduleItemLoadIfNecessary(BuilderRecord* record) { |
| 398 const ParseNode* origin = record->originally_referenced_from(); | 382 const ParseNode* origin = record->originally_referenced_from(); |
| 399 loader_->Load(record->label(), | 383 loader_->Load(record->label(), |
| (...skipping 21 matching lines...) Expand all Loading... |
| 421 } | 405 } |
| 422 | 406 |
| 423 record->set_resolved(true); | 407 record->set_resolved(true); |
| 424 | 408 |
| 425 if (!record->item()->OnResolved(err)) | 409 if (!record->item()->OnResolved(err)) |
| 426 return false; | 410 return false; |
| 427 if (!resolved_callback_.is_null()) | 411 if (!resolved_callback_.is_null()) |
| 428 resolved_callback_.Run(record); | 412 resolved_callback_.Run(record); |
| 429 | 413 |
| 430 // Recursively update everybody waiting on this item to be resolved. | 414 // Recursively update everybody waiting on this item to be resolved. |
| 431 BuilderRecordSet& waiting_set = record->waiting_on_resolution(); | 415 for (BuilderRecord* waiting : record->waiting_on_resolution()) { |
| 432 for (BuilderRecordSet::iterator i = waiting_set.begin(); | |
| 433 i != waiting_set.end(); ++i) { | |
| 434 BuilderRecord* waiting = *i; | |
| 435 DCHECK(waiting->unresolved_deps().find(record) != | 416 DCHECK(waiting->unresolved_deps().find(record) != |
| 436 waiting->unresolved_deps().end()); | 417 waiting->unresolved_deps().end()); |
| 437 waiting->unresolved_deps().erase(record); | 418 waiting->unresolved_deps().erase(record); |
| 438 | 419 |
| 439 if (waiting->can_resolve()) { | 420 if (waiting->can_resolve()) { |
| 440 if (!ResolveItem(waiting, err)) | 421 if (!ResolveItem(waiting, err)) |
| 441 return false; | 422 return false; |
| 442 } | 423 } |
| 443 } | 424 } |
| 444 waiting_set.clear(); | 425 record->waiting_on_resolution().clear(); |
| 445 return true; | 426 return true; |
| 446 } | 427 } |
| 447 | 428 |
| 448 bool Builder::ResolveDeps(LabelTargetVector* deps, Err* err) { | 429 bool Builder::ResolveDeps(LabelTargetVector* deps, Err* err) { |
| 449 for (size_t i = 0; i < deps->size(); i++) { | 430 for (LabelTargetPair& cur : *deps) { |
| 450 LabelTargetPair& cur = (*deps)[i]; | |
| 451 DCHECK(!cur.ptr); | 431 DCHECK(!cur.ptr); |
| 452 | 432 |
| 453 BuilderRecord* record = GetResolvedRecordOfType( | 433 BuilderRecord* record = GetResolvedRecordOfType( |
| 454 cur.label, cur.origin, BuilderRecord::ITEM_TARGET, err); | 434 cur.label, cur.origin, BuilderRecord::ITEM_TARGET, err); |
| 455 if (!record) | 435 if (!record) |
| 456 return false; | 436 return false; |
| 457 cur.ptr = record->item()->AsTarget(); | 437 cur.ptr = record->item()->AsTarget(); |
| 458 } | 438 } |
| 459 return true; | 439 return true; |
| 460 } | 440 } |
| 461 | 441 |
| 462 bool Builder::ResolveConfigs(UniqueVector<LabelConfigPair>* configs, Err* err) { | 442 bool Builder::ResolveConfigs(UniqueVector<LabelConfigPair>* configs, Err* err) { |
| 463 for (size_t i = 0; i < configs->size(); i++) { | 443 for (const auto& cur : *configs) { |
| 464 const LabelConfigPair& cur = (*configs)[i]; | |
| 465 DCHECK(!cur.ptr); | 444 DCHECK(!cur.ptr); |
| 466 | 445 |
| 467 BuilderRecord* record = GetResolvedRecordOfType( | 446 BuilderRecord* record = GetResolvedRecordOfType( |
| 468 cur.label, cur.origin, BuilderRecord::ITEM_CONFIG, err); | 447 cur.label, cur.origin, BuilderRecord::ITEM_CONFIG, err); |
| 469 if (!record) | 448 if (!record) |
| 470 return false; | 449 return false; |
| 471 const_cast<LabelConfigPair&>(cur).ptr = record->item()->AsConfig(); | 450 const_cast<LabelConfigPair&>(cur).ptr = record->item()->AsConfig(); |
| 472 } | 451 } |
| 473 return true; | 452 return true; |
| 474 } | 453 } |
| 475 | 454 |
| 476 // "Forward dependent configs" should refer to targets in the deps that should | 455 // "Forward dependent configs" should refer to targets in the deps that should |
| 477 // have their configs forwarded. | 456 // have their configs forwarded. |
| 478 bool Builder::ResolveForwardDependentConfigs(Target* target, Err* err) { | 457 bool Builder::ResolveForwardDependentConfigs(Target* target, Err* err) { |
| 479 const UniqueVector<LabelTargetPair>& configs = | 458 const UniqueVector<LabelTargetPair>& configs = |
| 480 target->forward_dependent_configs(); | 459 target->forward_dependent_configs(); |
| 481 | 460 |
| 482 // Assume that the lists are small so that brute-force n^2 is appropriate. | 461 // Assume that the lists are small so that brute-force n^2 is appropriate. |
| 483 for (size_t config_i = 0; config_i < configs.size(); config_i++) { | 462 for (const auto& config : configs) { |
| 484 for (const auto& dep_pair : target->GetDeps(Target::DEPS_LINKED)) { | 463 for (const auto& dep_pair : target->GetDeps(Target::DEPS_LINKED)) { |
| 485 if (configs[config_i].label == dep_pair.label) { | 464 if (config.label == dep_pair.label) { |
| 486 DCHECK(dep_pair.ptr); // Should already be resolved. | 465 DCHECK(dep_pair.ptr); // Should already be resolved. |
| 487 // UniqueVector's contents are constant so uniqueness is preserved, but | 466 // UniqueVector's contents are constant so uniqueness is preserved, but |
| 488 // we want to update this pointer which doesn't change uniqueness | 467 // we want to update this pointer which doesn't change uniqueness |
| 489 // (uniqueness in this vector is determined by the label only). | 468 // (uniqueness in this vector is determined by the label only). |
| 490 const_cast<LabelTargetPair&>(configs[config_i]).ptr = dep_pair.ptr; | 469 const_cast<LabelTargetPair&>(config).ptr = dep_pair.ptr; |
| 491 break; | 470 break; |
| 492 } | 471 } |
| 493 } | 472 } |
| 494 if (!configs[config_i].ptr) { | 473 if (!config.ptr) { |
| 495 *err = Err(target->defined_from(), | 474 *err = Err(target->defined_from(), |
| 496 "Target in forward_dependent_configs_from was not listed in the deps", | 475 "Target in forward_dependent_configs_from was not listed in the deps", |
| 497 "This target has a forward_dependent_configs_from entry that was " | 476 "This target has a forward_dependent_configs_from entry that was " |
| 498 "not present in\nthe deps. A target can only forward things it " | 477 "not present in\nthe deps. A target can only forward things it " |
| 499 "depends on. It was forwarding:\n " + | 478 "depends on. It was forwarding:\n " + |
| 500 configs[config_i].label.GetUserVisibleName(false)); | 479 config.label.GetUserVisibleName(false)); |
| 501 return false; | 480 return false; |
| 502 } | 481 } |
| 503 } | 482 } |
| 504 return true; | 483 return true; |
| 505 } | 484 } |
| 506 | 485 |
| 507 bool Builder::ResolveToolchain(Target* target, Err* err) { | 486 bool Builder::ResolveToolchain(Target* target, Err* err) { |
| 508 BuilderRecord* record = GetResolvedRecordOfType( | 487 BuilderRecord* record = GetResolvedRecordOfType( |
| 509 target->settings()->toolchain_label(), target->defined_from(), | 488 target->settings()->toolchain_label(), target->defined_from(), |
| 510 BuilderRecord::ITEM_TOOLCHAIN, err); | 489 BuilderRecord::ITEM_TOOLCHAIN, err); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 531 std::string ret; | 510 std::string ret; |
| 532 for (size_t i = 0; i < cycle.size(); i++) { | 511 for (size_t i = 0; i < cycle.size(); i++) { |
| 533 ret += " " + cycle[i]->label().GetUserVisibleName(false); | 512 ret += " " + cycle[i]->label().GetUserVisibleName(false); |
| 534 if (i != cycle.size() - 1) | 513 if (i != cycle.size() - 1) |
| 535 ret += " ->"; | 514 ret += " ->"; |
| 536 ret += "\n"; | 515 ret += "\n"; |
| 537 } | 516 } |
| 538 | 517 |
| 539 return ret; | 518 return ret; |
| 540 } | 519 } |
| OLD | NEW |