| // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef TOOLS_GN_LOADER_H_ | 
 | #define TOOLS_GN_LOADER_H_ | 
 |  | 
 | #include <map> | 
 | #include <memory> | 
 | #include <set> | 
 |  | 
 | #include "base/callback.h" | 
 | #include "base/memory/ref_counted.h" | 
 | #include "base/single_thread_task_runner.h" | 
 | #include "tools/gn/label.h" | 
 | #include "tools/gn/scope.h" | 
 |  | 
 | class BuildSettings; | 
 | class LocationRange; | 
 | class Settings; | 
 | class SourceFile; | 
 | class Toolchain; | 
 |  | 
 | // The loader manages execution of the different build files. It receives | 
 | // requests (normally from the Builder) when new references are found, and also | 
 | // manages loading the build config files. | 
 | // | 
 | // This loader class is abstract so it can be mocked out for testing the | 
 | // Builder. | 
 | class Loader : public base::RefCountedThreadSafe<Loader> { | 
 |  public: | 
 |   Loader(); | 
 |  | 
 |   // Loads the given file in the conext of the given toolchain. The initial | 
 |   // call to this (the one that actually starts the generation) should have an | 
 |   // empty toolchain name, which will trigger the load of the default build | 
 |   // config. | 
 |   virtual void Load(const SourceFile& file, | 
 |                     const LocationRange& origin, | 
 |                     const Label& toolchain_name) = 0; | 
 |  | 
 |   // Notification that the given toolchain has loaded. This will unblock files | 
 |   // waiting on this definition. | 
 |   virtual void ToolchainLoaded(const Toolchain* toolchain) = 0; | 
 |  | 
 |   // Returns the label of the default toolchain. | 
 |   virtual Label GetDefaultToolchain() const = 0; | 
 |  | 
 |   // Returns information about the toolchain with the given label. Will return | 
 |   // false if we haven't processed this toolchain yet. | 
 |   virtual const Settings* GetToolchainSettings(const Label& label) const = 0; | 
 |  | 
 |   // Helper function that extracts the file and toolchain name from the given | 
 |   // label, and calls Load(). | 
 |   void Load(const Label& label, const LocationRange& origin); | 
 |  | 
 |   // Returns the build file that the given label references. | 
 |   static SourceFile BuildFileForLabel(const Label& label); | 
 |  | 
 |   // When processing the default build config, we want to capture the argument | 
 |   // of set_default_build_config. The implementation of that function uses this | 
 |   // constant as a property key to get the Label* out of the scope where the | 
 |   // label should be stored. | 
 |   static const void* const kDefaultToolchainKey; | 
 |  | 
 |  protected: | 
 |   friend class base::RefCountedThreadSafe<Loader>; | 
 |   virtual ~Loader(); | 
 | }; | 
 |  | 
 | class LoaderImpl : public Loader { | 
 |  public: | 
 |   // Callback to emulate InputFileManager::AsyncLoadFile. | 
 |   typedef base::Callback<bool(const LocationRange&, | 
 |                               const BuildSettings*, | 
 |                               const SourceFile&, | 
 |                               const base::Callback<void(const ParseNode*)>&, | 
 |                               Err*)> AsyncLoadFileCallback; | 
 |  | 
 |   explicit LoaderImpl(const BuildSettings* build_settings); | 
 |  | 
 |   // Loader implementation. | 
 |   void Load(const SourceFile& file, | 
 |             const LocationRange& origin, | 
 |             const Label& toolchain_name) override; | 
 |   void ToolchainLoaded(const Toolchain* toolchain) override; | 
 |   Label GetDefaultToolchain() const override; | 
 |   const Settings* GetToolchainSettings(const Label& label) const override; | 
 |  | 
 |   // Sets the task runner corresponding to the main thread. By default this | 
 |   // class will use the thread active during construction, but there is not | 
 |   // a task runner active during construction all the time. | 
 |   void set_task_runner( | 
 |       scoped_refptr<base::SingleThreadTaskRunner> task_runner) { | 
 |     task_runner_ = task_runner; | 
 |   } | 
 |  | 
 |   // The complete callback is called whenever there are no more pending loads. | 
 |   // Called on the main thread only. This may be called more than once if the | 
 |   // queue is drained, but then more stuff gets added. | 
 |   void set_complete_callback(const base::Closure& cb) { | 
 |     complete_callback_ = cb; | 
 |   } | 
 |  | 
 |   // This callback is used when the loader finds it wants to load a file. | 
 |   void set_async_load_file(const AsyncLoadFileCallback& cb) { | 
 |     async_load_file_ = cb; | 
 |   } | 
 |  | 
 |   const Label& default_toolchain_label() const { | 
 |     return default_toolchain_label_; | 
 |   } | 
 |  | 
 |  private: | 
 |   struct LoadID; | 
 |   struct ToolchainRecord; | 
 |  | 
 |   ~LoaderImpl() override; | 
 |  | 
 |   // Schedules the input file manager to load the given file. | 
 |   void ScheduleLoadFile(const Settings* settings, | 
 |                         const LocationRange& origin, | 
 |                         const SourceFile& file); | 
 |   void ScheduleLoadBuildConfig( | 
 |       Settings* settings, | 
 |       const Scope::KeyValueMap& toolchain_overrides); | 
 |  | 
 |   // Runs the given file on the background thread. These are called by the | 
 |   // input file manager. | 
 |   void BackgroundLoadFile(const Settings* settings, | 
 |                           const SourceFile& file_name, | 
 |                           const LocationRange& origin, | 
 |                           const ParseNode* root); | 
 |   void BackgroundLoadBuildConfig( | 
 |       Settings* settings, | 
 |       const Scope::KeyValueMap& toolchain_overrides, | 
 |       const ParseNode* root); | 
 |  | 
 |   // Posted to the main thread when any file other than a build config file | 
 |   // file has completed running. | 
 |   void DidLoadFile(); | 
 |  | 
 |   // Posted to the main thread when any build config file has completed | 
 |   // running. The label should be the name of the toolchain. | 
 |   // | 
 |   // If there is no defauled toolchain loaded yet, we'll assume that the first | 
 |   // call to this indicates to the default toolchain, and this function will | 
 |   // set the default toolchain name to the given label. | 
 |   void DidLoadBuildConfig(const Label& label); | 
 |  | 
 |   // Decrements the pending_loads_ variable and issues the complete callback if | 
 |   // necessary. | 
 |   void DecrementPendingLoads(); | 
 |  | 
 |   // Forwards to the appropriate location to load the file. | 
 |   bool AsyncLoadFile(const LocationRange& origin, | 
 |                      const BuildSettings* build_settings, | 
 |                      const SourceFile& file_name, | 
 |                      const base::Callback<void(const ParseNode*)>& callback, | 
 |                      Err* err); | 
 |  | 
 |   scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 
 |  | 
 |   int pending_loads_; | 
 |   base::Closure complete_callback_; | 
 |  | 
 |   // When non-null, use this callback instead of the InputFileManager for | 
 |   // mocking purposes. | 
 |   AsyncLoadFileCallback async_load_file_; | 
 |  | 
 |   typedef std::set<LoadID> LoadIDSet; | 
 |   LoadIDSet invocations_; | 
 |  | 
 |   const BuildSettings* build_settings_; | 
 |   Label default_toolchain_label_; | 
 |  | 
 |   // Records for the build config file loads. | 
 |   typedef std::map<Label, std::unique_ptr<ToolchainRecord>> ToolchainRecordMap; | 
 |   ToolchainRecordMap toolchain_records_; | 
 | }; | 
 |  | 
 | #endif  // TOOLS_GN_LOADER_H_ |