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 #ifndef TOOLS_GN_TOOLCHAIN_MANAGER_H_ 6 #define TOOLS_GN_TOOLCHAIN_MANAGER_H_ 7 8 #include <map> 9 10 #include "base/basictypes.h" 11 #include "base/synchronization/lock.h" 12 #include "tools/gn/label.h" 13 #include "tools/gn/location.h" 14 #include "tools/gn/source_file.h" 15 #include "tools/gn/toolchain.h" 16 17 class Err; 18 class BuildSettings; 19 class ParseNode; 20 class Settings; 21 22 // The toolchain manager manages the mapping of toolchain names to the 23 // settings and toolchain object. It also loads build files in the context of a 24 // toolchain context of a toolchain, and manages running the build config 25 // script when necessary. 26 // 27 // This class uses the lock from the item tree to manage threadsafety. The 28 // functions requiring this lock to be held are named "Locked" to make this 29 // more clear. The "Unlocked" versions will acquire the lock themselves so will 30 // break if you call it while locked. (The rationale behind which is which is 31 // just based on the needs of the callers, so it can be changed.) There are two 32 // reasons for this: 33 // 34 // The first is that when resolving a target, we do a bunch of script 35 // stuff (slow) and then lookup the target, config, and toolchain dependencies 36 // based on that. The options are to do a lock around each dependency lookup 37 // or do a lock around the entire operation. Given that there's not a huge 38 // amount of work, the "big lock" approach is likely a bit better since it 39 // avoids lots of locking overhead. 40 // 41 // The second reason is that if we had a separate lock here, we would need to 42 // lock around creating a new toolchain. But creating a new toolchain involves 43 // adding it to the item tree, and this needs to be done atomically to prevent 44 // other threads from seeing a partially initialized toolchain. This sets up 45 // having deadlock do to acquiring multiple locks, or recursive locking 46 // problems. 47 class ToolchainManager { 48 public: 49 ToolchainManager(const BuildSettings* build_settings); 50 ~ToolchainManager(); 51 52 // At the very beginning of processing, this begins loading build files. 53 // This will scheduler loadin the default build config and the given build 54 // file in that context, going out from there. 55 // 56 // This returns immediately, you need to run the Scheduler to actually 57 // process anything. It's assumed this function is called on the main thread 58 // before doing anything, so it does not need locking. 59 void StartLoadingUnlocked(const SourceFile& build_file_name); 60 61 // Returns the settings object for a given toolchain. This does not 62 // schedule loading the given toolchain if it's not loaded yet: you actually 63 // need to invoke a target with that toolchain to get that. 64 // 65 // On error, returns NULL and sets the error. 66 const Settings* GetSettingsForToolchainLocked(const LocationRange& from_here, 67 const Label& toolchain_name, 68 Err* err); 69 70 // Returns the toolchain definition or NULL if the toolchain hasn't been 71 // defined yet. 72 const Toolchain* GetToolchainDefinitionUnlocked(const Label& toolchain_name); 73 74 // Sets the default toolchain. If the default toolchain is already set, 75 // this function will return false and fill in the given err. 76 bool SetDefaultToolchainUnlocked(const Label& dt, 77 const LocationRange& defined_from, 78 Err* err); 79 80 // Returns the default toolchain name. This will be empty if it hasn't been 81 // set. 82 Label GetDefaultToolchainUnlocked() const; 83 84 // Saves the given named toolchain (the name will be taken from the toolchain 85 // parameter). This will fail and return false if the given toolchain was 86 // already defined. In this case, the given error will be set. 87 bool SetToolchainDefinitionLocked(const Toolchain& tc, 88 const LocationRange& defined_from, 89 Err* err); 90 91 // Schedules an invocation of the given file under the given toolchain. The 92 // toolchain file will be loaded if necessary. If the toolchain is an is_null 93 // label, the default toolchain will be used. 94 // 95 // The origin should be the node that will be blamed for this invocation if 96 // an error occurs. If a synchronous error occurs, the given error will be 97 // set and it will return false. If an async error occurs, the error will be 98 // sent to the scheduler. 99 bool ScheduleInvocationLocked(const LocationRange& origin, 100 const Label& toolchain_name, 101 const SourceDir& dir, 102 Err* err); 103 104 private: 105 enum SettingsState { 106 // Toolchain settings have not requested to be loaded. This means we 107 // haven't seen any targets that require this toolchain yet. Not loading 108 // the settings automatically allows you to define a bunch of toolchains 109 // and potentially not use them without much overhead. 110 TOOLCHAIN_SETTINGS_NOT_LOADED, 111 112 // The settings have been scheduled to be loaded but have not completed. 113 TOOLCHAIN_SETTINGS_LOADING, 114 115 // The settings are done being loaded. 116 TOOLCHAIN_SETTINGS_LOADED 117 }; 118 119 struct Info; 120 121 static std::string ToolchainToOutputSubdir(const Label& toolchain_name); 122 123 // Creates a new info struct and saves it in the map. A pointer to the 124 // struct is returned. No loads are scheduled. 125 // 126 // If the label is non-empty, the toolchain will be added to the ItemTree 127 // so that other nodes can depend on it. THe empty label case is for the 128 // default build config file (when the toolchain name isn't known yet). It 129 // will be added later. 130 // 131 // On error, will return NULL and the error will be set. 132 Info* LoadNewToolchainLocked(const LocationRange& specified_from, 133 const Label& toolchain_name, 134 Err* err); 135 136 // Fixes up the default toolchain names once they're known when processing 137 // the default build config, or throw an error if the default toolchain 138 // hasn't been set. See the StartLoading() implementation for more. 139 void FixupDefaultToolchainLocked(); 140 141 // Loads the base config for the given toolchain. Run on a background thread 142 // asynchronously. 143 void BackgroundLoadBuildConfig(Info* info, 144 bool is_default, 145 const ParseNode* root); 146 147 // Invokes the given file for a toolchain with loaded settings. Run on a 148 // background thread asynchronously. 149 void BackgroundInvoke(const Info* info, 150 const SourceFile& file_name, 151 const ParseNode* root); 152 153 // Returns the lock to use. 154 base::Lock& GetLock() const; 155 156 const BuildSettings* build_settings_; 157 158 // We own the info pointers. 159 typedef std::map<Label, Info*> ToolchainMap; 160 ToolchainMap toolchains_; 161 162 Label default_toolchain_; 163 LocationRange default_toolchain_defined_here_; 164 165 DISALLOW_COPY_AND_ASSIGN(ToolchainManager); 166 }; 167 168 #endif // TOOLS_GN_TOOLCHAIN_MANAGER_H_ 169