| 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 |