Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright (c) 2014 Google Inc. 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 """ | |
| 6 This script is intended for use as a GYP_GENERATOR. It takes as input (by way of | |
| 7 the generator flag file_path) the list of relative file paths to consider. If | |
| 8 any target has at least one of the paths as a source (or input to an action or | |
| 9 rule) then 'Found dependency' is output, otherwise 'No dependencies' is output. | |
| 10 """ | |
| 11 | |
| 12 import gyp.common | |
| 13 import gyp.ninja_syntax as ninja_syntax | |
| 14 import os | |
| 15 import posixpath | |
| 16 | |
| 17 generator_supports_multiple_toolsets = True | |
| 18 | |
| 19 generator_wants_static_library_dependencies_adjusted = False | |
| 20 | |
| 21 generator_default_variables = { | |
| 22 } | |
| 23 for dirname in ['INTERMEDIATE_DIR', 'SHARED_INTERMEDIATE_DIR', 'PRODUCT_DIR', | |
| 24 'LIB_DIR', 'SHARED_LIB_DIR']: | |
| 25 generator_default_variables[dirname] = '!!!' | |
| 26 | |
| 27 for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME', | |
| 28 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT', | |
| 29 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX', | |
| 30 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX', | |
| 31 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX', | |
| 32 'CONFIGURATION_NAME']: | |
| 33 generator_default_variables[unused] = '' | |
| 34 | |
| 35 def __MakeRelativeTargetName(path): | |
| 36 """Converts a gyp target name into a relative name. For example, the path to a | |
| 37 gyp file may be something like c:\foo\bar.gyp:target, this converts it to | |
| 38 bar.gyp. | |
| 39 """ | |
| 40 prune_path = os.getcwd() | |
| 41 if path.startswith(prune_path): | |
| 42 path = path[len(prune_path):] | |
| 43 # Gyp paths are always posix style. | |
| 44 path = path.replace('\\', '/') | |
| 45 if path.endswith('#target'): | |
| 46 path = path[0:len(path) - len('#target')] | |
| 47 return path | |
| 48 | |
| 49 def __ExtractBasePath(target): | |
| 50 """Extracts the path components of the specified gyp target path.""" | |
| 51 last_index = target.rfind('/') | |
| 52 if last_index == -1: | |
| 53 return '' | |
| 54 return target[0:(last_index + 1)] | |
| 55 | |
| 56 def __AddSources(sources, base_path, base_path_components, result): | |
| 57 """Extracts valid sources from |sources| and adds them to |result|. Each | |
| 58 source file is relative to |base_path|, but may contain '..'. To make | |
| 59 resolving '..' easier |base_path_components| contains each of the | |
| 60 directories in |base_path|. Additionally each source may contain variables. | |
| 61 Such sources are ignored as it is assumed dependencies on them are expressed | |
| 62 and tracked in some other means.""" | |
| 63 # NOTE: gyp paths are always posix style. | |
| 64 for source in sources: | |
| 65 if source.startswith('!!!'): | |
| 66 continue; | |
| 67 if source.startswith('$'): | |
| 68 continue | |
| 69 # variable expansion may lead to //. | |
| 70 source = source.replace('//', '/') | |
|
Mark Mentovai
2014/06/12 18:36:32
Technically this is only correct for double-slashe
| |
| 71 if source.startswith('../'): | |
| 72 path_components = base_path_components[:] | |
| 73 # Resolve relative paths. | |
| 74 while source.startswith('../'): | |
| 75 path_components.pop(len(path_components) - 1) | |
| 76 source = source[3:] | |
| 77 result.append('/'.join(path_components) + source) | |
| 78 continue | |
| 79 result.append(base_path + source) | |
| 80 | |
| 81 def __ExtractSourcesFromAction(action, base_path, base_path_components, | |
| 82 results): | |
| 83 if 'inputs' in action: | |
| 84 __AddSources(action['inputs'], base_path, base_path_components, results) | |
| 85 | |
| 86 def __ExtractSources(target, target_dict): | |
| 87 base_path = posixpath.dirname(target) | |
| 88 base_path_components = base_path.split('/') | |
| 89 # Add a trailing '/' so that __AddSources() can easily build paths. | |
| 90 if len(base_path): | |
| 91 base_path += '/' | |
| 92 results = [] | |
| 93 if 'sources' in target_dict: | |
| 94 __AddSources(target_dict['sources'], base_path, base_path_components, | |
| 95 results) | |
| 96 # Include the inputs from any actions. Any changes to these effect the | |
| 97 # resulting output. | |
| 98 if 'actions' in target_dict: | |
| 99 for action in target_dict['actions']: | |
| 100 __ExtractSourcesFromAction(action, base_path, base_path_components, | |
| 101 results) | |
| 102 if 'rules' in target_dict: | |
| 103 for rule in target_dict['rules']: | |
| 104 __ExtractSourcesFromAction(rule, base_path, base_path_components, results) | |
| 105 | |
| 106 return results | |
| 107 | |
| 108 class Target(object): | |
| 109 """Holds information about a particular target: | |
| 110 sources: set of source files defined by this target. This includes inputs to | |
| 111 actions and rules. | |
| 112 deps: list of direct dependencies.""" | |
| 113 def __init__(self): | |
| 114 self.sources = [] | |
| 115 self.deps = [] | |
| 116 | |
| 117 def __GenerateTargets(target_list, target_dicts): | |
| 118 """Generates a dictionary with the key the name of a target and the value a | |
| 119 Target.""" | |
| 120 targets = {} | |
| 121 | |
| 122 # Queue of targets to visit. | |
| 123 targets_to_visit = target_list[:] | |
| 124 | |
| 125 while len(targets_to_visit) > 0: | |
| 126 absolute_target_name = targets_to_visit.pop() | |
| 127 # |absolute_target| may be an absolute path and may include #target. | |
| 128 # References to targets are relative, so we need to clean the name. | |
| 129 relative_target_name = __MakeRelativeTargetName(absolute_target_name) | |
| 130 if relative_target_name in targets: | |
| 131 continue | |
| 132 | |
| 133 target = Target() | |
| 134 targets[relative_target_name] = target | |
| 135 target.sources.extend(__ExtractSources(relative_target_name, | |
| 136 target_dicts[absolute_target_name])) | |
| 137 | |
| 138 for dep in target_dicts[absolute_target_name].get('dependencies', []): | |
| 139 targets[relative_target_name].deps.append(__MakeRelativeTargetName(dep)) | |
| 140 targets_to_visit.append(dep) | |
| 141 | |
| 142 return targets | |
| 143 | |
| 144 def __GetFiles(params): | |
| 145 """Returns the list of files to analyze, or None if none specified.""" | |
| 146 generator_flags = params.get('generator_flags', {}) | |
| 147 file_path = generator_flags.get('file_path', None) | |
| 148 if not file_path: | |
| 149 return None | |
| 150 try: | |
| 151 f = open(file_path, 'r') | |
| 152 result = [] | |
| 153 for file_name in f: | |
| 154 if file_name.endswith('\n'): | |
| 155 file_name = file_name[0:len(file_name) - 1] | |
| 156 if len(file_name): | |
| 157 result.append(file_name) | |
| 158 f.close() | |
| 159 return result | |
| 160 except IOError: | |
| 161 print 'Unable to open file', file_path | |
| 162 return None | |
| 163 | |
| 164 def CalculateVariables(default_variables, params): | |
| 165 """Calculate additional variables for use in the build (called by gyp).""" | |
| 166 flavor = gyp.common.GetFlavor(params) | |
| 167 if flavor == 'mac': | |
| 168 default_variables.setdefault('OS', 'mac') | |
| 169 elif flavor == 'win': | |
| 170 default_variables.setdefault('OS', 'win') | |
| 171 else: | |
| 172 operating_system = flavor | |
| 173 if flavor == 'android': | |
| 174 operating_system = 'linux' # Keep this legacy behavior for now. | |
| 175 default_variables.setdefault('OS', operating_system) | |
| 176 | |
| 177 def GenerateOutput(target_list, target_dicts, data, params): | |
| 178 """Called by gyp as the final stage. Outputs results.""" | |
| 179 files = __GetFiles(params) | |
| 180 if not files: | |
| 181 print 'Must specify files to analyze via file_path generator flag' | |
| 182 return | |
| 183 | |
| 184 targets = __GenerateTargets(target_list, target_dicts) | |
| 185 | |
| 186 files_set = frozenset(files) | |
| 187 found_in_all_sources = 0 | |
| 188 for target_name, target in targets.iteritems(): | |
| 189 sources = files_set.intersection(target.sources) | |
| 190 if len(sources): | |
| 191 print 'Found dependency' | |
| 192 return | |
| 193 | |
| 194 print 'No dependencies' | |
| OLD | NEW |