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