Home | History | Annotate | Download | only in gn
      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