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/import_manager.h" 6 7 #include "base/memory/scoped_ptr.h" 8 #include "base/stl_util.h" 9 #include "tools/gn/parse_tree.h" 10 #include "tools/gn/scheduler.h" 11 #include "tools/gn/scope_per_file_provider.h" 12 13 namespace { 14 15 // Returns a newly-allocated scope on success, null on failure. 16 Scope* UncachedImport(const Settings* settings, 17 const SourceFile& file, 18 const ParseNode* node_for_err, 19 Err* err) { 20 const ParseNode* node = g_scheduler->input_file_manager()->SyncLoadFile( 21 node_for_err->GetRange(), settings->build_settings(), file, err); 22 if (!node) 23 return NULL; 24 const BlockNode* block = node->AsBlock(); 25 CHECK(block); 26 27 scoped_ptr<Scope> scope(new Scope(settings->base_config())); 28 scope->set_source_dir(file.GetDir()); 29 30 // Don't allow ScopePerFileProvider to provide target-related variables. 31 // These will be relative to the imported file, which is probably not what 32 // people mean when they use these. 33 ScopePerFileProvider per_file_provider(scope.get(), false); 34 35 scope->SetProcessingImport(); 36 block->ExecuteBlockInScope(scope.get(), err); 37 if (err->has_error()) 38 return NULL; 39 scope->ClearProcessingImport(); 40 41 return scope.release(); 42 } 43 44 } // namesapce 45 46 ImportManager::ImportManager() { 47 } 48 49 ImportManager::~ImportManager() { 50 STLDeleteContainerPairSecondPointers(imports_.begin(), imports_.end()); 51 } 52 53 bool ImportManager::DoImport(const SourceFile& file, 54 const ParseNode* node_for_err, 55 Scope* scope, 56 Err* err) { 57 // See if we have a cached import, but be careful to actually do the scope 58 // copying outside of the lock. 59 const Scope* imported_scope = NULL; 60 { 61 base::AutoLock lock(lock_); 62 ImportMap::const_iterator found = imports_.find(file); 63 if (found != imports_.end()) 64 imported_scope = found->second; 65 } 66 67 if (!imported_scope) { 68 // Do a new import of the file. 69 imported_scope = UncachedImport(scope->settings(), file, 70 node_for_err, err); 71 if (!imported_scope) 72 return false; 73 74 // We loaded the file outside the lock. This means that there could be a 75 // race and the file was already loaded on a background thread. Recover 76 // from this and use the existing one if that happens. 77 { 78 base::AutoLock lock(lock_); 79 ImportMap::const_iterator found = imports_.find(file); 80 if (found != imports_.end()) { 81 delete imported_scope; 82 imported_scope = found->second; 83 } else { 84 imports_[file] = imported_scope; 85 } 86 } 87 } 88 89 Scope::MergeOptions options; 90 options.skip_private_vars = true; 91 options.mark_used = true; // Don't require all imported values be used. 92 return imported_scope->NonRecursiveMergeTo(scope, options, node_for_err, 93 "import", err); 94 } 95