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/toolchain_manager.h" | 5 #include "tools/gn/toolchain_manager.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "build/build_config.h" | 10 #include "build/build_config.h" |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 return SourceFile(dir.value() + "BUILD.gn"); | 71 return SourceFile(dir.value() + "BUILD.gn"); |
72 } | 72 } |
73 | 73 |
74 } // namespace | 74 } // namespace |
75 | 75 |
76 struct ToolchainManager::Info { | 76 struct ToolchainManager::Info { |
77 Info(const BuildSettings* build_settings, | 77 Info(const BuildSettings* build_settings, |
78 const Label& toolchain_name, | 78 const Label& toolchain_name, |
79 const std::string& output_subdir_name) | 79 const std::string& output_subdir_name) |
80 : state(TOOLCHAIN_NOT_LOADED), | 80 : state(TOOLCHAIN_NOT_LOADED), |
81 toolchain(toolchain_name), | 81 settings(build_settings, output_subdir_name), |
| 82 toolchain(new Toolchain(&settings, toolchain_name)), |
82 toolchain_set(false), | 83 toolchain_set(false), |
83 settings(build_settings, &toolchain, output_subdir_name), | |
84 toolchain_file_loaded(false), | 84 toolchain_file_loaded(false), |
85 item_node(NULL) { | 85 item_node(NULL) { |
| 86 settings.set_toolchain_label(toolchain_name); |
| 87 } |
| 88 |
| 89 ~Info() { |
| 90 if (!item_node) // See toolchain definition for more. |
| 91 delete toolchain; |
86 } | 92 } |
87 | 93 |
88 // Makes sure that an ItemNode is created for the toolchain, which lets | 94 // Makes sure that an ItemNode is created for the toolchain, which lets |
89 // targets depend on the (potentially future) loading of the toolchain. | 95 // targets depend on the (potentially future) loading of the toolchain. |
90 // | 96 // |
91 // We can't always do this at the beginning since when doing the default | 97 // We can't always do this at the beginning since when doing the default |
92 // build config, we don't know the toolchain name yet. We also need to go | 98 // build config, we don't know the toolchain name yet. We also need to go |
93 // through some effort to avoid doing this inside the toolchain manager's | 99 // through some effort to avoid doing this inside the toolchain manager's |
94 // lock (to avoid holding two locks at once). | 100 // lock (to avoid holding two locks at once). |
95 void EnsureItemNode() { | 101 void EnsureItemNode() { |
96 if (!item_node) { | 102 if (!item_node) { |
97 ItemTree& tree = settings.build_settings()->item_tree(); | 103 ItemTree& tree = settings.build_settings()->item_tree(); |
98 item_node = new ItemNode(&toolchain); | 104 item_node = new ItemNode(toolchain); |
99 tree.AddNodeLocked(item_node); | 105 tree.AddNodeLocked(item_node); |
100 } | 106 } |
101 } | 107 } |
102 | 108 |
103 ToolchainState state; | 109 ToolchainState state; |
104 | 110 |
105 Toolchain toolchain; | |
106 bool toolchain_set; | |
107 LocationRange toolchain_definition_location; | |
108 | |
109 // The first place in the build that we saw a reference for this toolchain. | 111 // The first place in the build that we saw a reference for this toolchain. |
110 // This allows us to report errors if it can't be loaded and blame some | 112 // This allows us to report errors if it can't be loaded and blame some |
111 // reasonable place of the code. This will be empty for the default toolchain. | 113 // reasonable place of the code. This will be empty for the default toolchain. |
112 LocationRange specified_from; | 114 LocationRange specified_from; |
113 | 115 |
114 // When the state is TOOLCHAIN_SETTINGS_LOADED, the settings should be | 116 // When the state is TOOLCHAIN_SETTINGS_LOADED, the settings should be |
115 // considered read-only and can be read without locking. Otherwise, they | 117 // considered read-only and can be read without locking. Otherwise, they |
116 // should not be accessed at all except to load them (which can therefore | 118 // should not be accessed at all except to load them (which can therefore |
117 // also be done outside of the lock). This works as long as the state flag | 119 // also be done outside of the lock). This works as long as the state flag |
118 // is only ever read or written inside the lock. | 120 // is only ever read or written inside the lock. |
119 Settings settings; | 121 Settings settings; |
120 | 122 |
| 123 // When we create an item node, this pointer will be owned by that node |
| 124 // so it's lifetime is managed by the dependency graph. Before we've created |
| 125 // the ItemNode, this class has to takre responsibility for this pointer. |
| 126 Toolchain* toolchain; |
| 127 bool toolchain_set; |
| 128 LocationRange toolchain_definition_location; |
| 129 |
121 // Set when the file corresponding to the toolchain definition is loaded. | 130 // Set when the file corresponding to the toolchain definition is loaded. |
122 // This will normally be set right after "toolchain_set". However, if the | 131 // This will normally be set right after "toolchain_set". However, if the |
123 // toolchain definition is missing, the file might be marked loaded but the | 132 // toolchain definition is missing, the file might be marked loaded but the |
124 // toolchain definition could still be unset. | 133 // toolchain definition could still be unset. |
125 bool toolchain_file_loaded; | 134 bool toolchain_file_loaded; |
126 | 135 |
127 // While state == TOOLCHAIN_SETTINGS_LOADING || TOOLCHAIN_DEFINITION_LOADING, | 136 // While state == TOOLCHAIN_SETTINGS_LOADING || TOOLCHAIN_DEFINITION_LOADING, |
128 // this will collect all scheduled invocations using this toolchain. They'll | 137 // this will collect all scheduled invocations using this toolchain. They'll |
129 // be issued once the settings file has been interpreted. | 138 // be issued once the settings file has been interpreted. |
130 // | 139 // |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
195 const Toolchain* ToolchainManager::GetToolchainDefinitionUnlocked( | 204 const Toolchain* ToolchainManager::GetToolchainDefinitionUnlocked( |
196 const Label& toolchain_name) { | 205 const Label& toolchain_name) { |
197 base::AutoLock lock(GetLock()); | 206 base::AutoLock lock(GetLock()); |
198 ToolchainMap::iterator found = toolchains_.find(toolchain_name); | 207 ToolchainMap::iterator found = toolchains_.find(toolchain_name); |
199 if (found == toolchains_.end() || !found->second->toolchain_set) | 208 if (found == toolchains_.end() || !found->second->toolchain_set) |
200 return NULL; | 209 return NULL; |
201 | 210 |
202 // Since we don't allow defining a toolchain more than once, we know that | 211 // Since we don't allow defining a toolchain more than once, we know that |
203 // once it's set it won't be mutated, so we can safely return this pointer | 212 // once it's set it won't be mutated, so we can safely return this pointer |
204 // for reading outside the lock. | 213 // for reading outside the lock. |
205 return &found->second->toolchain; | 214 return found->second->toolchain; |
206 } | 215 } |
207 | 216 |
208 bool ToolchainManager::SetDefaultToolchainUnlocked( | 217 bool ToolchainManager::SetDefaultToolchainUnlocked( |
209 const Label& default_toolchain, | 218 const Label& default_toolchain, |
210 const LocationRange& defined_here, | 219 const LocationRange& defined_here, |
211 Err* err) { | 220 Err* err) { |
212 base::AutoLock lock(GetLock()); | 221 base::AutoLock lock(GetLock()); |
213 if (!default_toolchain_.is_null()) { | 222 if (!default_toolchain_.is_null()) { |
214 *err = Err(defined_here, "Default toolchain already set."); | 223 *err = Err(defined_here, "Default toolchain already set."); |
215 err->AppendSubErr(Err(default_toolchain_defined_here_, | 224 err->AppendSubErr(Err(default_toolchain_defined_here_, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 info = LoadNewToolchainLocked(defined_from, tc.label(), err); | 263 info = LoadNewToolchainLocked(defined_from, tc.label(), err); |
255 if (!info) | 264 if (!info) |
256 return false; | 265 return false; |
257 } else { | 266 } else { |
258 // It's important to preserve the exact Toolchain object in our tree since | 267 // It's important to preserve the exact Toolchain object in our tree since |
259 // it will be in the ItemTree and targets may have dependencies on it. | 268 // it will be in the ItemTree and targets may have dependencies on it. |
260 info = found->second; | 269 info = found->second; |
261 } | 270 } |
262 | 271 |
263 // The labels should match or else we're setting the wrong one! | 272 // The labels should match or else we're setting the wrong one! |
264 CHECK(info->toolchain.label() == tc.label()); | 273 CHECK(info->toolchain->label() == tc.label()); |
265 | 274 |
266 // Save the toolchain. We can just overwrite our definition, but we need to | 275 // Save the toolchain. We can just overwrite our definition. |
267 // be careful to preserve the is_default flag. | 276 *info->toolchain = tc; |
268 bool is_default = info->toolchain.is_default(); | |
269 info->toolchain = tc; | |
270 info->toolchain.set_is_default(is_default); | |
271 | 277 |
272 if (info->toolchain_set) { | 278 if (info->toolchain_set) { |
273 *err = Err(defined_from, "Duplicate toolchain definition."); | 279 *err = Err(defined_from, "Duplicate toolchain definition."); |
274 err->AppendSubErr(Err( | 280 err->AppendSubErr(Err( |
275 info->toolchain_definition_location, | 281 info->toolchain_definition_location, |
276 "Previously defined here.", | 282 "Previously defined here.", |
277 "A toolchain can only be defined once. One tricky way that this could\n" | 283 "A toolchain can only be defined once. One tricky way that this could\n" |
278 "happen is if your definition is itself in a file that's interpreted\n" | 284 "happen is if your definition is itself in a file that's interpreted\n" |
279 "under different toolchains, which would result in multiple\n" | 285 "under different toolchains, which would result in multiple\n" |
280 "definitions as the file is loaded multiple times. So be sure your\n" | 286 "definitions as the file is loaded multiple times. So be sure your\n" |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 toolchains_[default_toolchain_] = info; | 422 toolchains_[default_toolchain_] = info; |
417 toolchains_.erase(old_default); | 423 toolchains_.erase(old_default); |
418 | 424 |
419 // Toolchain should not have been loaded in the build config file. | 425 // Toolchain should not have been loaded in the build config file. |
420 CHECK(!info->toolchain_set); | 426 CHECK(!info->toolchain_set); |
421 | 427 |
422 // We need to set the toolchain label now that we know it. There's no way | 428 // We need to set the toolchain label now that we know it. There's no way |
423 // to set the label, but we can assign the toolchain to a new one. Loading | 429 // to set the label, but we can assign the toolchain to a new one. Loading |
424 // the build config can not change the toolchain, so we won't be overwriting | 430 // the build config can not change the toolchain, so we won't be overwriting |
425 // anything useful. | 431 // anything useful. |
426 info->toolchain = Toolchain(default_toolchain_); | 432 *info->toolchain = Toolchain(&info->settings, default_toolchain_); |
427 info->toolchain.set_is_default(true); | 433 info->settings.set_is_default(true); |
| 434 info->settings.set_toolchain_label(default_toolchain_); |
428 info->EnsureItemNode(); | 435 info->EnsureItemNode(); |
429 | 436 |
430 // The default toolchain is loaded in greedy mode so all targets we | 437 // The default toolchain is loaded in greedy mode so all targets we |
431 // encounter are generated. Non-default toolchain settings stay in non-greedy | 438 // encounter are generated. Non-default toolchain settings stay in non-greedy |
432 // so we only generate the minimally required set. | 439 // so we only generate the minimally required set. |
433 info->settings.set_greedy_target_generation(true); | 440 info->settings.set_greedy_target_generation(true); |
434 | 441 |
435 // Schedule a load of the toolchain build file. | 442 // Schedule a load of the toolchain build file. |
436 Err err; | 443 Err err; |
437 ScheduleInvocationLocked(LocationRange(), default_toolchain_, | 444 ScheduleInvocationLocked(LocationRange(), default_toolchain_, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 void ToolchainManager::BackgroundLoadBuildConfig(Info* info, | 486 void ToolchainManager::BackgroundLoadBuildConfig(Info* info, |
480 bool is_default, | 487 bool is_default, |
481 const ParseNode* root) { | 488 const ParseNode* root) { |
482 // Danger: No early returns without decrementing the work count. | 489 // Danger: No early returns without decrementing the work count. |
483 if (root && !g_scheduler->is_failed()) { | 490 if (root && !g_scheduler->is_failed()) { |
484 // Nobody should be accessing settings at this point other than us since we | 491 // Nobody should be accessing settings at this point other than us since we |
485 // haven't marked it loaded, so we can do it outside the lock. | 492 // haven't marked it loaded, so we can do it outside the lock. |
486 Scope* base_config = info->settings.base_config(); | 493 Scope* base_config = info->settings.base_config(); |
487 base_config->set_source_dir(SourceDir("//")); | 494 base_config->set_source_dir(SourceDir("//")); |
488 | 495 |
489 info->settings.build_settings()->build_args().SetupRootScope(base_config, | 496 info->settings.build_settings()->build_args().SetupRootScope( |
490 info->settings.toolchain()->args()); | 497 base_config, info->toolchain->args()); |
491 | 498 |
492 base_config->SetProcessingBuildConfig(); | 499 base_config->SetProcessingBuildConfig(); |
493 if (is_default) | 500 if (is_default) |
494 base_config->SetProcessingDefaultBuildConfig(); | 501 base_config->SetProcessingDefaultBuildConfig(); |
495 | 502 |
496 ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE, | 503 ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE, |
497 info->settings.build_settings()->build_config_file().value()); | 504 info->settings.build_settings()->build_config_file().value()); |
498 trace.SetToolchain(info->settings.toolchain()->label()); | 505 trace.SetToolchain(info->settings.toolchain_label()); |
499 | 506 |
500 const BlockNode* root_block = root->AsBlock(); | 507 const BlockNode* root_block = root->AsBlock(); |
501 Err err; | 508 Err err; |
502 root_block->ExecuteBlockInScope(base_config, &err); | 509 root_block->ExecuteBlockInScope(base_config, &err); |
503 | 510 |
504 trace.Done(); | 511 trace.Done(); |
505 | 512 |
506 base_config->ClearProcessingBuildConfig(); | 513 base_config->ClearProcessingBuildConfig(); |
507 if (is_default) | 514 if (is_default) |
508 base_config->ClearProcessingDefaultBuildConfig(); | 515 base_config->ClearProcessingDefaultBuildConfig(); |
(...skipping 24 matching lines...) Expand all Loading... |
533 } | 540 } |
534 g_scheduler->DecrementWorkCount(); | 541 g_scheduler->DecrementWorkCount(); |
535 } | 542 } |
536 | 543 |
537 void ToolchainManager::BackgroundInvoke(const Info* info, | 544 void ToolchainManager::BackgroundInvoke(const Info* info, |
538 const SourceFile& file_name, | 545 const SourceFile& file_name, |
539 const ParseNode* root) { | 546 const ParseNode* root) { |
540 if (root && !g_scheduler->is_failed()) { | 547 if (root && !g_scheduler->is_failed()) { |
541 if (g_scheduler->verbose_logging()) { | 548 if (g_scheduler->verbose_logging()) { |
542 g_scheduler->Log("Running", file_name.value() + " with toolchain " + | 549 g_scheduler->Log("Running", file_name.value() + " with toolchain " + |
543 info->toolchain.label().GetUserVisibleName(false)); | 550 info->toolchain->label().GetUserVisibleName(false)); |
544 } | 551 } |
545 | 552 |
546 Scope our_scope(info->settings.base_config()); | 553 Scope our_scope(info->settings.base_config()); |
547 ScopePerFileProvider per_file_provider(&our_scope); | 554 ScopePerFileProvider per_file_provider(&our_scope); |
548 our_scope.set_source_dir(file_name.GetDir()); | 555 our_scope.set_source_dir(file_name.GetDir()); |
549 | 556 |
550 ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE, file_name.value()); | 557 ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE, file_name.value()); |
551 trace.SetToolchain(info->settings.toolchain()->label()); | 558 trace.SetToolchain(info->settings.toolchain_label()); |
552 | 559 |
553 Err err; | 560 Err err; |
554 root->Execute(&our_scope, &err); | 561 root->Execute(&our_scope, &err); |
555 if (err.has_error()) | 562 if (err.has_error()) |
556 g_scheduler->FailWithError(err); | 563 g_scheduler->FailWithError(err); |
557 | 564 |
558 trace.Done(); | 565 trace.Done(); |
559 | 566 |
560 { | 567 { |
561 // Check to see if any build config invocations depend on this file and | 568 // Check to see if any build config invocations depend on this file and |
(...skipping 15 matching lines...) Expand all Loading... |
577 } | 584 } |
578 } | 585 } |
579 } | 586 } |
580 | 587 |
581 g_scheduler->DecrementWorkCount(); | 588 g_scheduler->DecrementWorkCount(); |
582 } | 589 } |
583 | 590 |
584 base::Lock& ToolchainManager::GetLock() const { | 591 base::Lock& ToolchainManager::GetLock() const { |
585 return build_settings_->item_tree().lock(); | 592 return build_settings_->item_tree().lock(); |
586 } | 593 } |
OLD | NEW |