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 12 namespace { 13 14 // Returns a newly-allocated scope on success, null on failure. 15 Scope* UncachedImport(const Settings* settings, 16 const SourceFile& file, 17 const ParseNode* node_for_err, 18 Err* err) { 19 const ParseNode* node = g_scheduler->input_file_manager()->SyncLoadFile( 20 node_for_err->GetRange(), settings->build_settings(), file, err); 21 if (!node) 22 return NULL; 23 const BlockNode* block = node->AsBlock(); 24 CHECK(block); 25 26 scoped_ptr<Scope> scope(new Scope(settings->base_config())); 27 scope->set_source_dir(file.GetDir()); 28 scope->SetProcessingImport(); 29 block->ExecuteBlockInScope(scope.get(), err); 30 if (err->has_error()) 31 return NULL; 32 scope->ClearProcessingImport(); 33 34 return scope.release(); 35 } 36 37 } // namesapce 38 39 ImportManager::ImportManager() { 40 } 41 42 ImportManager::~ImportManager() { 43 STLDeleteContainerPairSecondPointers(imports_.begin(), imports_.end()); 44 } 45 46 bool ImportManager::DoImport(const SourceFile& file, 47 const ParseNode* node_for_err, 48 Scope* scope, 49 Err* err) { 50 // See if we have a cached import, but be careful to actually do the scope 51 // copying outside of the lock. 52 const Scope* imported_scope = NULL; 53 { 54 base::AutoLock lock(lock_); 55 ImportMap::const_iterator found = imports_.find(file); 56 if (found != imports_.end()) 57 imported_scope = found->second; 58 } 59 60 if (!imported_scope) { 61 // Do a new import of the file. 62 imported_scope = UncachedImport(scope->settings(), file, 63 node_for_err, err); 64 if (!imported_scope) 65 return false; 66 67 // We loaded the file outside the lock. This means that there could be a 68 // race and the file was already loaded on a background thread. Recover 69 // from this and use the existing one if that happens. 70 { 71 base::AutoLock lock(lock_); 72 ImportMap::const_iterator found = imports_.find(file); 73 if (found != imports_.end()) { 74 delete imported_scope; 75 imported_scope = found->second; 76 } else { 77 imports_[file] = imported_scope; 78 } 79 } 80 } 81 82 return imported_scope->NonRecursiveMergeTo(scope, node_for_err, 83 "import", err); 84 } 85